diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1a030ea --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +docsrc/xml +docsrc/build +.DS_Store \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 4573d10..ab807db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,53 @@ # Changelog +## 2.0.0 + +**New features:** + +* Added support for the `icon` property in the `HABinarySensor` (you can set the icon using `HABinarySensor::setIcon("iconName")`) +* Added support for changing the current state of the `HABinarySensor` using `HABinarySensor::setCurrentState` method +* Added support for forcing `setState` in `HABinarySensor` using a second argument as follows `HABinarySensor::setState(true, true)` +* Added support for the `device_class` property in the `HACover` (you can set the class using `HACover::setDeviceClass("className")` +* Added support for the `icon` property in the `HACover` (you can set the icon using `HACover::setIcon("iconName")`) +* Added pointer of the sender to the `HACover` callback function +* Added support for `optimistic` property in the `HACover` (you can change the mode using `HACover::setOptimistic(true)`) +* Added support for forcing `setPosition` in `HACover` using a second argument as follows `HACover::setPosition(100, true)` +* Added support for the `device_class` property in the `HASwitch` (you can set the class using `HASwitch::setDeviceClass("className")` +* Added support for the `optimistic` property in the `HASwitch` (you can change the mode using `HASwitch::setOptimistic(true)`) +* Added support for the `force_update` property in the `HASensor` (you can set the mode using `HASensor::setForceUpdate(true)`) +* Added support for the `HAButton` device type +* Added support for the `HADeviceTracker` device type +* Added support for the `HACamera` device type +* Added support for the `HALock` device type +* Added support for the `HASelect` device type +* Added support for the `HANumber` device type +* Added support for the `HAScene` device type +* Added support for the `HALight` device type + +**Bugs fixes:** +* Last Will Message is now retained (#70) +* Compilation error on SAMD family (#82) + +**New examples:** +* [Button](examples/button/button.ino) - adding simple buttons to the Home Assistant panel. + +**Breaking changes:** + +* Changed structure of all MQTT topics used in the library. +* Changed constructor of the `HABinarySensor` class (removed `deviceClass` and `initialState` arguments) +* Renamed `HABinarySensor::getState()` method to `HABinarySensor::getCurrentState()` +* Replaced `HATriggers` with `HADeviceTrigger` - the new implementation is not backward compatible. Please check the updated example of the `multi-state-button`. +* Renamed `HADevice::isOnline()` method to `HADevice::isAvailable()` +* Renamed `HASwitch::onStateChanged` method to `HASwitch::onCommand`. +* Renamed `HAFan::onStateChanged` method to `HAFan::onStateCommand`. +* Renamed `HAFan::onSpeedChanged` method to `HAFan::onSpeedCommand`. +* Changed logic of the `HASwitch` callback. Please check the `led-switch` example. +* Refactored `HASensor` logic. It's now divided into two different classes: `HASensor` and `HASensorNumber`. +* Removed all legacy constructors with `HAMqtt` argument +* Removed `onConnectionFailed` callback from the `HAMqtt` class +* The position in the `HACover` is now available as configurable feature. It's disabled by default. +* Refactored `HAHVAC` class to support more features of the MQTT discovery. Please check the update example. + ## 1.3.0 **New features:** @@ -10,7 +58,7 @@ * Added `setName` method to HASwitch * Added `onBeforeStateChanged` callback to HASwitch -**Updates:** +**Improvements:** * Removed legacy properties from HAFan (Home Assistant 2021.4.4). Deprecated methods will be removed after a quarter (2021.7) * Separated `uniqueID` field from `name` in all devices types @@ -31,7 +79,7 @@ * Added `onConnectionFailed()` method in the HAMqtt * Added support for MQTT LWT (see [Advanced Availability example](examples/advanced-availability/advanced-availability.ino)) -**Updates:** +**Improvements:** * Optimized codebase and logic in all devices types * Updated all examples * Fixed compilation warnings in all classes diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..29ebfa5 --- /dev/null +++ b/LICENSE @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. \ No newline at end of file diff --git a/README.md b/README.md index 9957e95..33862ce 100644 --- a/README.md +++ b/README.md @@ -1,85 +1,99 @@ -# Arduino Home Assistant integration +# Arduino Home Assistant integration 🏠 ArduinoHA allows to integrate an Arduino/ESP based device with Home Assistant using MQTT. -The library is designed to use as little resources (RAM/flash) as possible. -Initially it was optimized to work on Arduino Uno with Ethernet Shield, +The library is designed to use as low resources (RAM/flash) as possible. +Initially, it was optimized to work on Arduino Uno with Ethernet Shield, but I successfully use it on ESP8266/ESP8255 boards in my projects. +[📘 Documentation](https://dawidchyrzynski.github.io/arduino-home-assistant/) + ## Features +* Two-way communication (state reporting and command execution) * MQTT discovery (device is added to the Home Assistant panel automatically) * MQTT Last Will and Testament * Support for custom MQTT messages (publishing and subscribing) * Auto reconnect with MQTT broker * Reporting availability (online/offline states) of a device +* Doxygen documentation for all classes +* Covered by unit tests (AUnit + EpoxyDuino + AUniter) ## Supported HA types -* Binary sensors -* Covers -* Fans -* Device triggers -* Switches -* Sensors -* Tag scanner -* HVACs *(side note: HVACs requires more flash size than other HA types. It's not suitable for Arduino Nano/Uno)* +| Home Assistant type | Supported | +| ------------------- | :--------: | +| Binary sensor | ✅ | +| Button | ✅ | +| Camera | ✅ | +| Cover | ✅ | +| Device tracker | ✅ | +| Device trigger | ✅ | +| Fan | ✅ | +| Humidifier | ❌ | +| HVAC | ✅ | +| Light | ✅ | +| Lock | ✅ | +| Number | ✅ | +| Scene | ✅ | +| Select | ✅ | +| Sensor | ✅ | +| Switch | ✅ | +| Tag scanner | ✅ | +| Vacuum | ❌ | ## Examples -* [Binary Sensor](examples/binary-sensor/binary-sensor.ino) -* [Cover](examples/cover/cover.ino) -* [Fan](examples/fan/fan.ino) -* [LED switch](examples/led-switch/led-switch.ino) -* [Multi-state button](examples/multi-state-button/multi-state-button.ino) -* [Sensor (temperature, humidity, etc.)](examples/sensor/sensor.ino) -* [HVAC](examples/hvac/hvac.ino) -* [NodeMCU Wi-Fi](examples/nodemcu/nodemcu.ino) -* [Arduino Nano 33 IoT Wi-Fi (SAMD)](examples/nano33iot/nano33iot.ino) -* [Availability feature](examples/availability) -* [Advanced availability (MQTT LWT)](examples/advanced-availability/advanced-availability.ino) -* [MQTT with credentials](examples/mqtt-with-credentials/mqtt-with-credentials.ino) -* [MQTT advanced](examples/mqtt-advanced/mqtt-advanced.ino) +|Example|Description | +|-------|-----------------------------| +|[Binary sensor](examples/binary-sensor/binary-sensor.ino)|Using the binary sensor as a door contact sensor.| +|[Button](examples/button/button.ino)|Adding simple buttons to the Home Assistant panel.| +|[Camera](examples/esp32-cam/esp32-cam.ino)|Publishing the preview from the ESP32-CAM module.| +|[Cover](examples/cover/cover.ino)|Controlling a window cover (open / close / stop).| +|[Device trigger](examples/multi-state-button/multi-state-button.ino)|Implementation of a simple wall switch that reports press and hold states.| +|[Fan](examples/fan/fan.ino)|Controlling a simple fan (state + speed).| +|[HVAC](examples/hvac/hvac.ino)|HVAC controller with multiple modes, power control and target temperature.| +|[Lock](examples/lock/lock.ino)|A simple door lock that's controlled by the Home Assistant.| +|[Light](examples/light/light.ino)|A simple light that allows changing brightness, color temperature and RGB color.| +|[Number](examples/number/number.ino)|Adding an interactive numeric slider in the Home Assistant panel.| +|[Scene](examples/scene/scene.ino)|Adding a custom scene in the Home Assistant panel. | +|[Select](examples/select/select.ino)|A dropdown selector that's displayed in the Home Assistant panel.| +|[Sensor](examples/sensor/sensor.ino)|A simple sensor that reports a state in a string representation (open / opening / close).| +|[Analog sensor](examples/sensor-analog/sensor-analog.ino)|Reporting the analog pin's voltage to the Home Assistant.| +|[Integer sensor](examples/sensor-integer/sensor-integer.ino)|Reporting the device's uptime to the Home Assistant.| +|[Switch](examples/led-switch/led-switch.ino)|The LED that's controlled by the Home Assistant.| +|[Multi-switch](examples/multi-switch/multi-switch.ino)|Multiple switches controlled by the Home Assistant.| +|[Tag scanner](examples/tag-scanner/tag-scanner.ino)|Scanning RFID tags using the MFRC522 module.| +|[Availability](examples/availability/availability.ino)|Reporting entities' availability (online / offline) to the Home Assistant.| +|[Advanced availability](examples/advanced-availability/advanced-availability.ino)|Advanced availability reporting with MQTT LWT (Last Will and Testament).| +|[MQTT advanced](examples/mqtt-advanced/mqtt-advanced.ino)|Subscribing to custom topics and publishing custom messages.| +|[MQTT with credentials](examples/mqtt-with-credentials/mqtt-with-credentials.ino)|Establishing connection with a MQTT broker using the credentials. | +|[NodeMCU (ESP8266)](examples/nodemcu/nodemcu.ino)|Basic example for ESP8266 devices.| +|[Arduino Nano 33 IoT](examples/nano33iot/nano33iot.ino)|Basic example for Arduino Nano 33 IoT (SAMD family).| +|[mDNS discovery](examples/mdns/mdns.ino)|Make your ESP8266 discoverable via the mDNS.| -## Tested boards +## Compatible hardware + +The library uses the Arduino Ethernet Client API for interacting with the network hardware. +It should work fine as long as the `Client` class is available. + +Here is the list of devices on which the library was tested: * Arduino Uno * Arduino Mega +* Arduino Nano +* Arduino Pro Mini +* Arduino Nano 33 IoT * NodeMCU +* Controllino Mega (Pure) +* Controllino Maxi (Pure) * ESP-01 -* Generic ESP8266/ESP8255 -* Arduino Nano 33 IoT (SAMD) - -## Tested devices - -* Controllino Maxi (standard/pure/automation/power) -* Controllino Mega (standard/pure) +* ESP32-CAM * Sonoff Dual R2 +* Sonoff Dual R3 * Sonoff Basic * Sonoff Mini * Tuya Wi-Fi switch module * Tuya Wi-Fi curtain module -## Tested Arduino Shields - -* Arduino Ethernet Shield (WizNet W5100) - -## Roadmap - -* FAQ + Home Assistant setup instructions -* Documentation of the library -* Unit tests -* Reduce flash memory usage -* Add support for HA lights - -## Unsupported features - -The library doesn't support all features of the MQTT integration. -If you need support for a new feature please open a new issue in the repository. - -# License - -This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License v3.0 as published by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with this program. If not, see https://www.gnu.org/licenses/gpl.html +Please note that it's not the complete list of supported devices. +You may try to use the library on any device that uses Arduino core. diff --git a/docs/.buildinfo b/docs/.buildinfo new file mode 100644 index 0000000..264e0c0 --- /dev/null +++ b/docs/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: 2ec2743465492061aecb7af749506d9c +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/docs/.nojekyll b/docs/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/docs/_images/library-search.png b/docs/_images/library-search.png new file mode 100644 index 0000000..41e752e Binary files /dev/null and b/docs/_images/library-search.png differ diff --git a/docs/_images/manage-libraries.png b/docs/_images/manage-libraries.png new file mode 100644 index 0000000..a8640ad Binary files /dev/null and b/docs/_images/manage-libraries.png differ diff --git a/docs/_static/basic.css b/docs/_static/basic.css new file mode 100644 index 0000000..bf18350 --- /dev/null +++ b/docs/_static/basic.css @@ -0,0 +1,906 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2022 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +div.section::after { + display: block; + content: ''; + clear: left; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li p.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 450px; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +a.brackets:before, +span.brackets > a:before{ + content: "["; +} + +a.brackets:after, +span.brackets > a:after { + content: "]"; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, figure.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, figure.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, figure.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +img.align-default, figure.align-default, .figure.align-default { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-default { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar, +aside.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px; + background-color: #ffe; + width: 40%; + float: right; + clear: right; + overflow-x: auto; +} + +p.sidebar-title { + font-weight: bold; +} + +div.admonition, div.topic, blockquote { + clear: left; +} + +/* -- topics ---------------------------------------------------------------- */ + +div.topic { + border: 1px solid #ccc; + padding: 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- content of sidebars/topics/admonitions -------------------------------- */ + +div.sidebar > :last-child, +aside.sidebar > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +div.sidebar::after, +aside.sidebar::after, +div.topic::after, +div.admonition::after, +blockquote::after { + display: block; + content: ''; + clear: both; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + margin-top: 10px; + margin-bottom: 10px; + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table.align-default { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +table.footnote td, table.footnote th { + border: 0 !important; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +th > :first-child, +td > :first-child { + margin-top: 0px; +} + +th > :last-child, +td > :last-child { + margin-bottom: 0px; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure, figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption, figcaption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number, +figcaption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text, +figcaption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist { + margin: 1em 0; +} + +table.hlist td { + vertical-align: top; +} + +/* -- object description styles --------------------------------------------- */ + +.sig { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; +} + +.sig-name, code.descname { + background-color: transparent; + font-weight: bold; +} + +.sig-name { + font-size: 1.1em; +} + +code.descname { + font-size: 1.2em; +} + +.sig-prename, code.descclassname { + background-color: transparent; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.sig-param.n { + font-style: italic; +} + +/* C++ specific styling */ + +.sig-inline.c-texpr, +.sig-inline.cpp-texpr { + font-family: unset; +} + +.sig.c .k, .sig.c .kt, +.sig.cpp .k, .sig.cpp .kt { + color: #0033B3; +} + +.sig.c .m, +.sig.cpp .m { + color: #1750EB; +} + +.sig.c .s, .sig.c .sc, +.sig.cpp .s, .sig.cpp .sc { + color: #067D17; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +:not(li) > ol > li:first-child > :first-child, +:not(li) > ul > li:first-child > :first-child { + margin-top: 0px; +} + +:not(li) > ol > li:last-child > :last-child, +:not(li) > ul > li:last-child > :last-child { + margin-bottom: 0px; +} + +ol.simple ol p, +ol.simple ul p, +ul.simple ol p, +ul.simple ul p { + margin-top: 0; +} + +ol.simple > li:not(:first-child) > p, +ul.simple > li:not(:first-child) > p { + margin-top: 0; +} + +ol.simple p, +ul.simple p { + margin-bottom: 0; +} + +dl.footnote > dt, +dl.citation > dt { + float: left; + margin-right: 0.5em; +} + +dl.footnote > dd, +dl.citation > dd { + margin-bottom: 0em; +} + +dl.footnote > dd:after, +dl.citation > dd:after { + content: ""; + clear: both; +} + +dl.field-list { + display: grid; + grid-template-columns: fit-content(30%) auto; +} + +dl.field-list > dt { + font-weight: bold; + word-break: break-word; + padding-left: 0.5em; + padding-right: 5px; +} + +dl.field-list > dt:after { + content: ":"; +} + +dl.field-list > dd { + padding-left: 0.5em; + margin-top: 0em; + margin-left: 0em; + margin-bottom: 0em; +} + +dl { + margin-bottom: 15px; +} + +dd > :first-child { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +dl > dd:last-child, +dl > dd:last-child > :last-child { + margin-bottom: 0; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +.classifier:before { + font-style: normal; + margin: 0 0.5em; + content: ":"; + display: inline-block; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +pre, div[class*="highlight-"] { + clear: both; +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; + white-space: nowrap; +} + +div[class*="highlight-"] { + margin: 1em 0; +} + +td.linenos pre { + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + display: block; +} + +table.highlighttable tbody { + display: block; +} + +table.highlighttable tr { + display: flex; +} + +table.highlighttable td { + margin: 0; + padding: 0; +} + +table.highlighttable td.linenos { + padding-right: 0.5em; +} + +table.highlighttable td.code { + flex: 1; + overflow: hidden; +} + +.highlight .hll { + display: block; +} + +div.highlight pre, +table.highlighttable pre { + margin: 0; +} + +div.code-block-caption + div { + margin-top: 0; +} + +div.code-block-caption { + margin-top: 1em; + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +table.highlighttable td.linenos, +span.linenos, +div.highlight span.gp { /* gp: Generic.Prompt */ + user-select: none; + -webkit-user-select: text; /* Safari fallback only */ + -webkit-user-select: none; /* Chrome/Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+ */ +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + margin: 1em 0; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: absolute; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/docs/_static/custom.css b/docs/_static/custom.css new file mode 100644 index 0000000..6d79a89 --- /dev/null +++ b/docs/_static/custom.css @@ -0,0 +1,180 @@ +header.navbar { + background: #3eaf7c +} +header.navbar a { + color: #fff +} +header.navbar .nav-item a:hover { + color: #eee +} +header.navbar .site-name { + color: #fff +} +header.navbar .icon { + color: #fff; + position: relative; + top: 2px +} +.body-header ul.page-nav { + margin-right: 1.2em; + padding-right: 0 +} +.body-header + hr { + margin-top: 0 !important; +} +table.examples-table tbody td + td { + text-align: left; +} +.sidebar-links li.toctree-l1 > a { + font-weight: 600 +} +.sidebar-links > .caption { + display: none +} +.content + div.page-nav { + max-width: 840px; +} +.content + div.page-nav ul.page-nav { + max-width: 100%; + padding: 0 0 0.5em +} +.searchbox .caption-text { + display: none +} +form { + display: flex; + flex-direction: row; + margin-top: 0.5em +} +form.search { + padding-right: 0.5em +} +input[type="text"] { + border: 1px solid #ddd; + border-radius: 2px; + flex: 1; + padding: 8px 15px; + font-size: 15px; + outline: none; +} +input[type="submit"] { + background: #3eaf7c; + border: 1px solid #3eaf7c; + color: #fff; + font-weight: 500; + font-size: 15px; + padding: 8px; + cursor: pointer; + text-transform: capitalize; + transition: background-color .3s +} +input[type="submit"]:hover { + background: #58C996 +} +.content p + ul { + margin-top: -10px +} +.content pre { + font-size: 14px +} +.cpp.var, +.cpp.function { + border: 1px solid #eee; + background: #fcfcfc; + margin-bottom: 0.5em; + padding: 15px +} +.cpp > dt { + border-bottom: 1px solid #eee; + margin: 0 0 10px; + padding-bottom: 5px; +} +.cpp.function > dt { + border-bottom: 2px solid #eee; +} +.cpp > dt * { + font-size: 16px; + font-weight: 600 +} +.cpp.class > dt * { + font-size: 20px +} +.cpp > dt a * { + color: #3eaf7c +} +.cpp > dt .k::after { + content: " " +} +.cpp > dt .kt + .w::before { + content: " " +} +.cpp > dd { + margin-left: 0; + text-align: justify; + font-size: 15px; +} +.cpp .sig-paren { + margin-left: 0; + margin-right: 3px; +} +.cpp .sig-name { + margin-right: 2px +} +.cpp .p::after, +.cpp .n::after { + content: " " +} +.cpp .k, +.cpp .kt { + color: #2664b9 +} +.cpp .n { + color: #2c3e50; + margin: 0 +} +.cpp.function .field-list { + display: block; + margin-bottom: 0 +} +.cpp.function .field-list dt { + padding-left: 0; + text-transform: uppercase; + font-size: 14px; + font-weight: 600; + border-bottom: 1px solid #eee; + color: #999 !important; +} +.cpp.function .field-list dd { + padding-left: 0 +} +.cpp.function .field-list dd > p, +.cpp.function .field-list dd > ul { + margin: 8px 0 0; + list-style-type: none; + padding-left: 0 +} +.cpp.function .field-list dd p strong { + margin-left: 0 +} +.cpp.function .field-list dd + dt { + margin-top: 15px +} +.cpp .admonition { + padding: 8px 15px +} +.cpp .admonition .admonition-title { + margin-bottom: 5px +} +.breathe-sectiondef-title { + color: #222 !important; + font-size: 20px !important; + text-align: center; + text-decoration: underline; + text-transform: uppercase; +} +.cpp p + ul { + margin-top: 5px +} +p.highlight-link { + margin-bottom: 0 +} \ No newline at end of file diff --git a/docs/_static/custom.js b/docs/_static/custom.js new file mode 100644 index 0000000..b1ead75 --- /dev/null +++ b/docs/_static/custom.js @@ -0,0 +1,13 @@ +window.addEventListener('load', function() { + document.querySelectorAll('a.reference.external').forEach(function(link) { + link.target = '_blank'; + }); + + document.querySelectorAll('.footer a').forEach(function(link) { + link.target = '_blank'; + }); + + document.querySelectorAll('form input[type="text"]').forEach(function(input) { + input.setAttribute("placeholder", "Search docs"); + }); +}); \ No newline at end of file diff --git a/docs/_static/doctools.js b/docs/_static/doctools.js new file mode 100644 index 0000000..e1bfd70 --- /dev/null +++ b/docs/_static/doctools.js @@ -0,0 +1,358 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for all documentation. + * + * :copyright: Copyright 2007-2022 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/** + * select a different prefix for underscore + */ +$u = _.noConflict(); + +/** + * make the code below compatible with browsers without + * an installed firebug like debugger +if (!window.console || !console.firebug) { + var names = ["log", "debug", "info", "warn", "error", "assert", "dir", + "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", + "profile", "profileEnd"]; + window.console = {}; + for (var i = 0; i < names.length; ++i) + window.console[names[i]] = function() {}; +} + */ + +/** + * small helper function to urldecode strings + * + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent#Decoding_query_parameters_from_a_URL + */ +jQuery.urldecode = function(x) { + if (!x) { + return x + } + return decodeURIComponent(x.replace(/\+/g, ' ')); +}; + +/** + * small helper function to urlencode strings + */ +jQuery.urlencode = encodeURIComponent; + +/** + * This function returns the parsed url parameters of the + * current request. Multiple values per key are supported, + * it will always return arrays of strings for the value parts. + */ +jQuery.getQueryParameters = function(s) { + if (typeof s === 'undefined') + s = document.location.search; + var parts = s.substr(s.indexOf('?') + 1).split('&'); + var result = {}; + for (var i = 0; i < parts.length; i++) { + var tmp = parts[i].split('=', 2); + var key = jQuery.urldecode(tmp[0]); + var value = jQuery.urldecode(tmp[1]); + if (key in result) + result[key].push(value); + else + result[key] = [value]; + } + return result; +}; + +/** + * highlight a given string on a jquery object by wrapping it in + * span elements with the given class name. + */ +jQuery.fn.highlightText = function(text, className) { + function highlight(node, addItems) { + if (node.nodeType === 3) { + var val = node.nodeValue; + var pos = val.toLowerCase().indexOf(text); + if (pos >= 0 && + !jQuery(node.parentNode).hasClass(className) && + !jQuery(node.parentNode).hasClass("nohighlight")) { + var span; + var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.className = className; + } + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + if (isInSVG) { + var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); + var bbox = node.parentElement.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute('class', className); + addItems.push({ + "parent": node.parentNode, + "target": rect}); + } + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this, addItems); + }); + } + } + var addItems = []; + var result = this.each(function() { + highlight(this, addItems); + }); + for (var i = 0; i < addItems.length; ++i) { + jQuery(addItems[i].parent).before(addItems[i].target); + } + return result; +}; + +/* + * backward compatibility for jQuery.browser + * This will be supported until firefox bug is fixed. + */ +if (!jQuery.browser) { + jQuery.uaMatch = function(ua) { + ua = ua.toLowerCase(); + + var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || + /(webkit)[ \/]([\w.]+)/.exec(ua) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || + /(msie) ([\w.]+)/.exec(ua) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || + []; + + return { + browser: match[ 1 ] || "", + version: match[ 2 ] || "0" + }; + }; + jQuery.browser = {}; + jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; +} + +/** + * Small JavaScript module for the documentation. + */ +var Documentation = { + + init : function() { + this.fixFirefoxAnchorBug(); + this.highlightSearchWords(); + this.initIndexTable(); + this.initOnKeyListeners(); + }, + + /** + * i18n support + */ + TRANSLATIONS : {}, + PLURAL_EXPR : function(n) { return n === 1 ? 0 : 1; }, + LOCALE : 'unknown', + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext : function(string) { + var translated = Documentation.TRANSLATIONS[string]; + if (typeof translated === 'undefined') + return string; + return (typeof translated === 'string') ? translated : translated[0]; + }, + + ngettext : function(singular, plural, n) { + var translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated === 'undefined') + return (n == 1) ? singular : plural; + return translated[Documentation.PLURALEXPR(n)]; + }, + + addTranslations : function(catalog) { + for (var key in catalog.messages) + this.TRANSLATIONS[key] = catalog.messages[key]; + this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); + this.LOCALE = catalog.locale; + }, + + /** + * add context elements like header anchor links + */ + addContextElements : function() { + $('div[id] > :header:first').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this headline')). + appendTo(this); + }); + $('dt[id]').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this definition')). + appendTo(this); + }); + }, + + /** + * workaround a firefox stupidity + * see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075 + */ + fixFirefoxAnchorBug : function() { + if (document.location.hash && $.browser.mozilla) + window.setTimeout(function() { + document.location.href += ''; + }, 10); + }, + + /** + * highlight the search words provided in the url in the text + */ + highlightSearchWords : function() { + var params = $.getQueryParameters(); + var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; + if (terms.length) { + var body = $('div.body'); + if (!body.length) { + body = $('body'); + } + window.setTimeout(function() { + $.each(terms, function() { + body.highlightText(this.toLowerCase(), 'highlighted'); + }); + }, 10); + $('') + .appendTo($('#searchbox')); + } + }, + + /** + * init the domain index toggle buttons + */ + initIndexTable : function() { + var togglers = $('img.toggler').click(function() { + var src = $(this).attr('src'); + var idnum = $(this).attr('id').substr(7); + $('tr.cg-' + idnum).toggle(); + if (src.substr(-9) === 'minus.png') + $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); + else + $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); + }).css('display', ''); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { + togglers.click(); + } + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords : function() { + $('#searchbox .highlight-link').fadeOut(300); + $('span.highlighted').removeClass('highlighted'); + var url = new URL(window.location); + url.searchParams.delete('highlight'); + window.history.replaceState({}, '', url); + }, + + /** + * helper function to focus on search bar + */ + focusSearchBar : function() { + $('input[name=q]').first().focus(); + }, + + /** + * make the url absolute + */ + makeURL : function(relativeURL) { + return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; + }, + + /** + * get the current relative url + */ + getCurrentURL : function() { + var path = document.location.pathname; + var parts = path.split(/\//); + $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { + if (this === '..') + parts.pop(); + }); + var url = parts.join('/'); + return path.substring(url.lastIndexOf('/') + 1, path.length - 1); + }, + + initOnKeyListeners: function() { + // only install a listener if it is really needed + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS && + !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) + return; + + $(document).keydown(function(event) { + var activeElementType = document.activeElement.tagName; + // don't navigate when in search box, textarea, dropdown or button + if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT' + && activeElementType !== 'BUTTON') { + if (event.altKey || event.ctrlKey || event.metaKey) + return; + + if (!event.shiftKey) { + switch (event.key) { + case 'ArrowLeft': + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) + break; + var prevHref = $('link[rel="prev"]').prop('href'); + if (prevHref) { + window.location.href = prevHref; + return false; + } + break; + case 'ArrowRight': + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) + break; + var nextHref = $('link[rel="next"]').prop('href'); + if (nextHref) { + window.location.href = nextHref; + return false; + } + break; + case 'Escape': + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) + break; + Documentation.hideSearchWords(); + return false; + } + } + + // some keyboard layouts may need Shift to get / + switch (event.key) { + case '/': + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) + break; + Documentation.focusSearchBar(); + return false; + } + } + }); + } +}; + +// quick alias for translations +_ = Documentation.gettext; + +$(document).ready(function() { + Documentation.init(); +}); diff --git a/docs/_static/documentation_options.js b/docs/_static/documentation_options.js new file mode 100644 index 0000000..fe42da8 --- /dev/null +++ b/docs/_static/documentation_options.js @@ -0,0 +1,14 @@ +var DOCUMENTATION_OPTIONS = { + URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), + VERSION: '2.0.0', + LANGUAGE: 'None', + COLLAPSE_INDEX: false, + BUILDER: 'html', + FILE_SUFFIX: '.html', + LINK_SUFFIX: '.html', + HAS_SOURCE: false, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: false, + SHOW_SEARCH_SUMMARY: true, + ENABLE_SEARCH_SHORTCUTS: true, +}; \ No newline at end of file diff --git a/docs/_static/file.png b/docs/_static/file.png new file mode 100644 index 0000000..a858a41 Binary files /dev/null and b/docs/_static/file.png differ diff --git a/docs/_static/jquery-3.5.1.js b/docs/_static/jquery-3.5.1.js new file mode 100644 index 0000000..5093733 --- /dev/null +++ b/docs/_static/jquery-3.5.1.js @@ -0,0 +1,10872 @@ +/*! + * jQuery JavaScript Library v3.5.1 + * https://jquery.com/ + * + * Includes Sizzle.js + * https://sizzlejs.com/ + * + * Copyright JS Foundation and other contributors + * Released under the MIT license + * https://jquery.org/license + * + * Date: 2020-05-04T22:49Z + */ +( function( global, factory ) { + + "use strict"; + + if ( typeof module === "object" && typeof module.exports === "object" ) { + + // For CommonJS and CommonJS-like environments where a proper `window` + // is present, execute the factory and get jQuery. + // For environments that do not have a `window` with a `document` + // (such as Node.js), expose a factory as module.exports. + // This accentuates the need for the creation of a real `window`. + // e.g. var jQuery = require("jquery")(window); + // See ticket #14549 for more info. + module.exports = global.document ? + factory( global, true ) : + function( w ) { + if ( !w.document ) { + throw new Error( "jQuery requires a window with a document" ); + } + return factory( w ); + }; + } else { + factory( global ); + } + +// Pass this if window is not defined yet +} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { + +// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 +// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode +// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common +// enough that all such attempts are guarded in a try block. +"use strict"; + +var arr = []; + +var getProto = Object.getPrototypeOf; + +var slice = arr.slice; + +var flat = arr.flat ? function( array ) { + return arr.flat.call( array ); +} : function( array ) { + return arr.concat.apply( [], array ); +}; + + +var push = arr.push; + +var indexOf = arr.indexOf; + +var class2type = {}; + +var toString = class2type.toString; + +var hasOwn = class2type.hasOwnProperty; + +var fnToString = hasOwn.toString; + +var ObjectFunctionString = fnToString.call( Object ); + +var support = {}; + +var isFunction = function isFunction( obj ) { + + // Support: Chrome <=57, Firefox <=52 + // In some browsers, typeof returns "function" for HTML elements + // (i.e., `typeof document.createElement( "object" ) === "function"`). + // We don't want to classify *any* DOM node as a function. + return typeof obj === "function" && typeof obj.nodeType !== "number"; + }; + + +var isWindow = function isWindow( obj ) { + return obj != null && obj === obj.window; + }; + + +var document = window.document; + + + + var preservedScriptAttributes = { + type: true, + src: true, + nonce: true, + noModule: true + }; + + function DOMEval( code, node, doc ) { + doc = doc || document; + + var i, val, + script = doc.createElement( "script" ); + + script.text = code; + if ( node ) { + for ( i in preservedScriptAttributes ) { + + // Support: Firefox 64+, Edge 18+ + // Some browsers don't support the "nonce" property on scripts. + // On the other hand, just using `getAttribute` is not enough as + // the `nonce` attribute is reset to an empty string whenever it + // becomes browsing-context connected. + // See https://github.com/whatwg/html/issues/2369 + // See https://html.spec.whatwg.org/#nonce-attributes + // The `node.getAttribute` check was added for the sake of + // `jQuery.globalEval` so that it can fake a nonce-containing node + // via an object. + val = node[ i ] || node.getAttribute && node.getAttribute( i ); + if ( val ) { + script.setAttribute( i, val ); + } + } + } + doc.head.appendChild( script ).parentNode.removeChild( script ); + } + + +function toType( obj ) { + if ( obj == null ) { + return obj + ""; + } + + // Support: Android <=2.3 only (functionish RegExp) + return typeof obj === "object" || typeof obj === "function" ? + class2type[ toString.call( obj ) ] || "object" : + typeof obj; +} +/* global Symbol */ +// Defining this global in .eslintrc.json would create a danger of using the global +// unguarded in another place, it seems safer to define global only for this module + + + +var + version = "3.5.1", + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + + // The jQuery object is actually just the init constructor 'enhanced' + // Need init if jQuery is called (just allow error to be thrown if not included) + return new jQuery.fn.init( selector, context ); + }; + +jQuery.fn = jQuery.prototype = { + + // The current version of jQuery being used + jquery: version, + + constructor: jQuery, + + // The default length of a jQuery object is 0 + length: 0, + + toArray: function() { + return slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + + // Return all the elements in a clean array + if ( num == null ) { + return slice.call( this ); + } + + // Return just the one element from the set + return num < 0 ? this[ num + this.length ] : this[ num ]; + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + each: function( callback ) { + return jQuery.each( this, callback ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map( this, function( elem, i ) { + return callback.call( elem, i, elem ); + } ) ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + even: function() { + return this.pushStack( jQuery.grep( this, function( _elem, i ) { + return ( i + 1 ) % 2; + } ) ); + }, + + odd: function() { + return this.pushStack( jQuery.grep( this, function( _elem, i ) { + return i % 2; + } ) ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); + }, + + end: function() { + return this.prevObject || this.constructor(); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: arr.sort, + splice: arr.splice +}; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[ 0 ] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + + // Skip the boolean and the target + target = arguments[ i ] || {}; + i++; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !isFunction( target ) ) { + target = {}; + } + + // Extend jQuery itself if only one argument is passed + if ( i === length ) { + target = this; + i--; + } + + for ( ; i < length; i++ ) { + + // Only deal with non-null/undefined values + if ( ( options = arguments[ i ] ) != null ) { + + // Extend the base object + for ( name in options ) { + copy = options[ name ]; + + // Prevent Object.prototype pollution + // Prevent never-ending loop + if ( name === "__proto__" || target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject( copy ) || + ( copyIsArray = Array.isArray( copy ) ) ) ) { + src = target[ name ]; + + // Ensure proper type for the source value + if ( copyIsArray && !Array.isArray( src ) ) { + clone = []; + } else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) { + clone = {}; + } else { + clone = src; + } + copyIsArray = false; + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend( { + + // Unique for each copy of jQuery on the page + expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), + + // Assume jQuery is ready without the ready module + isReady: true, + + error: function( msg ) { + throw new Error( msg ); + }, + + noop: function() {}, + + isPlainObject: function( obj ) { + var proto, Ctor; + + // Detect obvious negatives + // Use toString instead of jQuery.type to catch host objects + if ( !obj || toString.call( obj ) !== "[object Object]" ) { + return false; + } + + proto = getProto( obj ); + + // Objects with no prototype (e.g., `Object.create( null )`) are plain + if ( !proto ) { + return true; + } + + // Objects with prototype are plain iff they were constructed by a global Object function + Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; + return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; + }, + + isEmptyObject: function( obj ) { + var name; + + for ( name in obj ) { + return false; + } + return true; + }, + + // Evaluates a script in a provided context; falls back to the global one + // if not specified. + globalEval: function( code, options, doc ) { + DOMEval( code, { nonce: options && options.nonce }, doc ); + }, + + each: function( obj, callback ) { + var length, i = 0; + + if ( isArrayLike( obj ) ) { + length = obj.length; + for ( ; i < length; i++ ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } else { + for ( i in obj ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } + + return obj; + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArrayLike( Object( arr ) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + return arr == null ? -1 : indexOf.call( arr, elem, i ); + }, + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + merge: function( first, second ) { + var len = +second.length, + j = 0, + i = first.length; + + for ( ; j < len; j++ ) { + first[ i++ ] = second[ j ]; + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, invert ) { + var callbackInverse, + matches = [], + i = 0, + length = elems.length, + callbackExpect = !invert; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + callbackInverse = !callback( elems[ i ], i ); + if ( callbackInverse !== callbackExpect ) { + matches.push( elems[ i ] ); + } + } + + return matches; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var length, value, + i = 0, + ret = []; + + // Go through the array, translating each of the items to their new values + if ( isArrayLike( elems ) ) { + length = elems.length; + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + } + + // Flatten any nested arrays + return flat( ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // jQuery.support is not used in Core but other projects attach their + // properties to it so it needs to exist. + support: support +} ); + +if ( typeof Symbol === "function" ) { + jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; +} + +// Populate the class2type map +jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), +function( _i, name ) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +} ); + +function isArrayLike( obj ) { + + // Support: real iOS 8.2 only (not reproducible in simulator) + // `in` check used to prevent JIT error (gh-2145) + // hasOwn isn't used here due to false negatives + // regarding Nodelist length in IE + var length = !!obj && "length" in obj && obj.length, + type = toType( obj ); + + if ( isFunction( obj ) || isWindow( obj ) ) { + return false; + } + + return type === "array" || length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj; +} +var Sizzle = +/*! + * Sizzle CSS Selector Engine v2.3.5 + * https://sizzlejs.com/ + * + * Copyright JS Foundation and other contributors + * Released under the MIT license + * https://js.foundation/ + * + * Date: 2020-03-14 + */ +( function( window ) { +var i, + support, + Expr, + getText, + isXML, + tokenize, + compile, + select, + outermostContext, + sortInput, + hasDuplicate, + + // Local document vars + setDocument, + document, + docElem, + documentIsHTML, + rbuggyQSA, + rbuggyMatches, + matches, + contains, + + // Instance-specific data + expando = "sizzle" + 1 * new Date(), + preferredDoc = window.document, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + nonnativeSelectorCache = createCache(), + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + } + return 0; + }, + + // Instance methods + hasOwn = ( {} ).hasOwnProperty, + arr = [], + pop = arr.pop, + pushNative = arr.push, + push = arr.push, + slice = arr.slice, + + // Use a stripped-down indexOf as it's faster than native + // https://jsperf.com/thor-indexof-vs-for/5 + indexOf = function( list, elem ) { + var i = 0, + len = list.length; + for ( ; i < len; i++ ) { + if ( list[ i ] === elem ) { + return i; + } + } + return -1; + }, + + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|" + + "ismap|loop|multiple|open|readonly|required|scoped", + + // Regular expressions + + // http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + + // https://www.w3.org/TR/css-syntax-3/#ident-token-diagram + identifier = "(?:\\\\[\\da-fA-F]{1,6}" + whitespace + + "?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+", + + // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors + attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + + + // Operator (capture 2) + "*([*^$|!~]?=)" + whitespace + + + // "Attribute values must be CSS identifiers [capture 5] + // or strings [capture 3 or capture 4]" + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + + whitespace + "*\\]", + + pseudos = ":(" + identifier + ")(?:\\((" + + + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: + // 1. quoted (capture 3; capture 4 or capture 5) + "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + + + // 2. simple (capture 6) + "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + + + // 3. anything else (capture 2) + ".*" + + ")\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rwhitespace = new RegExp( whitespace + "+", "g" ), + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + + "*" ), + rdescend = new RegExp( whitespace + "|>" ), + + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + "ID": new RegExp( "^#(" + identifier + ")" ), + "CLASS": new RegExp( "^\\.(" + identifier + ")" ), + "TAG": new RegExp( "^(" + identifier + "|[*])" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + + whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + + whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), + + // For use in libraries implementing .is() + // We use this for POS matching in `select` + "needsContext": new RegExp( "^" + whitespace + + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rhtml = /HTML$/i, + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + rnative = /^[^{]+\{\s*\[native \w/, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rsibling = /[+~]/, + + // CSS escapes + // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\[\\da-fA-F]{1,6}" + whitespace + "?|\\\\([^\\r\\n\\f])", "g" ), + funescape = function( escape, nonHex ) { + var high = "0x" + escape.slice( 1 ) - 0x10000; + + return nonHex ? + + // Strip the backslash prefix from a non-hex escape sequence + nonHex : + + // Replace a hexadecimal escape sequence with the encoded Unicode code point + // Support: IE <=11+ + // For values outside the Basic Multilingual Plane (BMP), manually construct a + // surrogate pair + high < 0 ? + String.fromCharCode( high + 0x10000 ) : + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }, + + // CSS string/identifier serialization + // https://drafts.csswg.org/cssom/#common-serializing-idioms + rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, + fcssescape = function( ch, asCodePoint ) { + if ( asCodePoint ) { + + // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER + if ( ch === "\0" ) { + return "\uFFFD"; + } + + // Control characters and (dependent upon position) numbers get escaped as code points + return ch.slice( 0, -1 ) + "\\" + + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; + } + + // Other potentially-special ASCII characters get backslash-escaped + return "\\" + ch; + }, + + // Used for iframes + // See setDocument() + // Removing the function wrapper causes a "Permission Denied" + // error in IE + unloadHandler = function() { + setDocument(); + }, + + inDisabledFieldset = addCombinator( + function( elem ) { + return elem.disabled === true && elem.nodeName.toLowerCase() === "fieldset"; + }, + { dir: "parentNode", next: "legend" } + ); + +// Optimize for push.apply( _, NodeList ) +try { + push.apply( + ( arr = slice.call( preferredDoc.childNodes ) ), + preferredDoc.childNodes + ); + + // Support: Android<4.0 + // Detect silently failing push.apply + // eslint-disable-next-line no-unused-expressions + arr[ preferredDoc.childNodes.length ].nodeType; +} catch ( e ) { + push = { apply: arr.length ? + + // Leverage slice if possible + function( target, els ) { + pushNative.apply( target, slice.call( els ) ); + } : + + // Support: IE<9 + // Otherwise append directly + function( target, els ) { + var j = target.length, + i = 0; + + // Can't trust NodeList.length + while ( ( target[ j++ ] = els[ i++ ] ) ) {} + target.length = j - 1; + } + }; +} + +function Sizzle( selector, context, results, seed ) { + var m, i, elem, nid, match, groups, newSelector, + newContext = context && context.ownerDocument, + + // nodeType defaults to 9, since context defaults to document + nodeType = context ? context.nodeType : 9; + + results = results || []; + + // Return early from calls with invalid selector or context + if ( typeof selector !== "string" || !selector || + nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { + + return results; + } + + // Try to shortcut find operations (as opposed to filters) in HTML documents + if ( !seed ) { + setDocument( context ); + context = context || document; + + if ( documentIsHTML ) { + + // If the selector is sufficiently simple, try using a "get*By*" DOM method + // (excepting DocumentFragment context, where the methods don't exist) + if ( nodeType !== 11 && ( match = rquickExpr.exec( selector ) ) ) { + + // ID selector + if ( ( m = match[ 1 ] ) ) { + + // Document context + if ( nodeType === 9 ) { + if ( ( elem = context.getElementById( m ) ) ) { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + + // Element context + } else { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( newContext && ( elem = newContext.getElementById( m ) ) && + contains( context, elem ) && + elem.id === m ) { + + results.push( elem ); + return results; + } + } + + // Type selector + } else if ( match[ 2 ] ) { + push.apply( results, context.getElementsByTagName( selector ) ); + return results; + + // Class selector + } else if ( ( m = match[ 3 ] ) && support.getElementsByClassName && + context.getElementsByClassName ) { + + push.apply( results, context.getElementsByClassName( m ) ); + return results; + } + } + + // Take advantage of querySelectorAll + if ( support.qsa && + !nonnativeSelectorCache[ selector + " " ] && + ( !rbuggyQSA || !rbuggyQSA.test( selector ) ) && + + // Support: IE 8 only + // Exclude object elements + ( nodeType !== 1 || context.nodeName.toLowerCase() !== "object" ) ) { + + newSelector = selector; + newContext = context; + + // qSA considers elements outside a scoping root when evaluating child or + // descendant combinators, which is not what we want. + // In such cases, we work around the behavior by prefixing every selector in the + // list with an ID selector referencing the scope context. + // The technique has to be used as well when a leading combinator is used + // as such selectors are not recognized by querySelectorAll. + // Thanks to Andrew Dupont for this technique. + if ( nodeType === 1 && + ( rdescend.test( selector ) || rcombinators.test( selector ) ) ) { + + // Expand context for sibling selectors + newContext = rsibling.test( selector ) && testContext( context.parentNode ) || + context; + + // We can use :scope instead of the ID hack if the browser + // supports it & if we're not changing the context. + if ( newContext !== context || !support.scope ) { + + // Capture the context ID, setting it first if necessary + if ( ( nid = context.getAttribute( "id" ) ) ) { + nid = nid.replace( rcssescape, fcssescape ); + } else { + context.setAttribute( "id", ( nid = expando ) ); + } + } + + // Prefix every selector in the list + groups = tokenize( selector ); + i = groups.length; + while ( i-- ) { + groups[ i ] = ( nid ? "#" + nid : ":scope" ) + " " + + toSelector( groups[ i ] ); + } + newSelector = groups.join( "," ); + } + + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch ( qsaError ) { + nonnativeSelectorCache( selector, true ); + } finally { + if ( nid === expando ) { + context.removeAttribute( "id" ); + } + } + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed ); +} + +/** + * Create key-value caches of limited size + * @returns {function(string, object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var keys = []; + + function cache( key, value ) { + + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + if ( keys.push( key + " " ) > Expr.cacheLength ) { + + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return ( cache[ key + " " ] = value ); + } + return cache; +} + +/** + * Mark a function for special use by Sizzle + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created element and returns a boolean result + */ +function assert( fn ) { + var el = document.createElement( "fieldset" ); + + try { + return !!fn( el ); + } catch ( e ) { + return false; + } finally { + + // Remove from its parent by default + if ( el.parentNode ) { + el.parentNode.removeChild( el ); + } + + // release memory in IE + el = null; + } +} + +/** + * Adds the same handler for all of the specified attrs + * @param {String} attrs Pipe-separated list of attributes + * @param {Function} handler The method that will be applied + */ +function addHandle( attrs, handler ) { + var arr = attrs.split( "|" ), + i = arr.length; + + while ( i-- ) { + Expr.attrHandle[ arr[ i ] ] = handler; + } +} + +/** + * Checks document order of two siblings + * @param {Element} a + * @param {Element} b + * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b + */ +function siblingCheck( a, b ) { + var cur = b && a, + diff = cur && a.nodeType === 1 && b.nodeType === 1 && + a.sourceIndex - b.sourceIndex; + + // Use IE sourceIndex if available on both nodes + if ( diff ) { + return diff; + } + + // Check if b follows a + if ( cur ) { + while ( ( cur = cur.nextSibling ) ) { + if ( cur === b ) { + return -1; + } + } + } + + return a ? 1 : -1; +} + +/** + * Returns a function to use in pseudos for input types + * @param {String} type + */ +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for buttons + * @param {String} type + */ +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return ( name === "input" || name === "button" ) && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for :enabled/:disabled + * @param {Boolean} disabled true for :disabled; false for :enabled + */ +function createDisabledPseudo( disabled ) { + + // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable + return function( elem ) { + + // Only certain elements can match :enabled or :disabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled + if ( "form" in elem ) { + + // Check for inherited disabledness on relevant non-disabled elements: + // * listed form-associated elements in a disabled fieldset + // https://html.spec.whatwg.org/multipage/forms.html#category-listed + // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled + // * option elements in a disabled optgroup + // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled + // All such elements have a "form" property. + if ( elem.parentNode && elem.disabled === false ) { + + // Option elements defer to a parent optgroup if present + if ( "label" in elem ) { + if ( "label" in elem.parentNode ) { + return elem.parentNode.disabled === disabled; + } else { + return elem.disabled === disabled; + } + } + + // Support: IE 6 - 11 + // Use the isDisabled shortcut property to check for disabled fieldset ancestors + return elem.isDisabled === disabled || + + // Where there is no isDisabled, check manually + /* jshint -W018 */ + elem.isDisabled !== !disabled && + inDisabledFieldset( elem ) === disabled; + } + + return elem.disabled === disabled; + + // Try to winnow out elements that can't be disabled before trusting the disabled property. + // Some victims get caught in our net (label, legend, menu, track), but it shouldn't + // even exist on them, let alone have a boolean value. + } else if ( "label" in elem ) { + return elem.disabled === disabled; + } + + // Remaining elements are neither :enabled nor :disabled + return false; + }; +} + +/** + * Returns a function to use in pseudos for positionals + * @param {Function} fn + */ +function createPositionalPseudo( fn ) { + return markFunction( function( argument ) { + argument = +argument; + return markFunction( function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ ( j = matchIndexes[ i ] ) ] ) { + seed[ j ] = !( matches[ j ] = seed[ j ] ); + } + } + } ); + } ); +} + +/** + * Checks a node for validity as a Sizzle context + * @param {Element|Object=} context + * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value + */ +function testContext( context ) { + return context && typeof context.getElementsByTagName !== "undefined" && context; +} + +// Expose support vars for convenience +support = Sizzle.support = {}; + +/** + * Detects XML nodes + * @param {Element|Object} elem An element or a document + * @returns {Boolean} True iff elem is a non-HTML XML node + */ +isXML = Sizzle.isXML = function( elem ) { + var namespace = elem.namespaceURI, + docElem = ( elem.ownerDocument || elem ).documentElement; + + // Support: IE <=8 + // Assume HTML when documentElement doesn't yet exist, such as inside loading iframes + // https://bugs.jquery.com/ticket/4833 + return !rhtml.test( namespace || docElem && docElem.nodeName || "HTML" ); +}; + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [doc] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +setDocument = Sizzle.setDocument = function( node ) { + var hasCompare, subWindow, + doc = node ? node.ownerDocument || node : preferredDoc; + + // Return early if doc is invalid or already selected + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( doc == document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Update global variables + document = doc; + docElem = document.documentElement; + documentIsHTML = !isXML( document ); + + // Support: IE 9 - 11+, Edge 12 - 18+ + // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( preferredDoc != document && + ( subWindow = document.defaultView ) && subWindow.top !== subWindow ) { + + // Support: IE 11, Edge + if ( subWindow.addEventListener ) { + subWindow.addEventListener( "unload", unloadHandler, false ); + + // Support: IE 9 - 10 only + } else if ( subWindow.attachEvent ) { + subWindow.attachEvent( "onunload", unloadHandler ); + } + } + + // Support: IE 8 - 11+, Edge 12 - 18+, Chrome <=16 - 25 only, Firefox <=3.6 - 31 only, + // Safari 4 - 5 only, Opera <=11.6 - 12.x only + // IE/Edge & older browsers don't support the :scope pseudo-class. + // Support: Safari 6.0 only + // Safari 6.0 supports :scope but it's an alias of :root there. + support.scope = assert( function( el ) { + docElem.appendChild( el ).appendChild( document.createElement( "div" ) ); + return typeof el.querySelectorAll !== "undefined" && + !el.querySelectorAll( ":scope fieldset div" ).length; + } ); + + /* Attributes + ---------------------------------------------------------------------- */ + + // Support: IE<8 + // Verify that getAttribute really returns attributes and not properties + // (excepting IE8 booleans) + support.attributes = assert( function( el ) { + el.className = "i"; + return !el.getAttribute( "className" ); + } ); + + /* getElement(s)By* + ---------------------------------------------------------------------- */ + + // Check if getElementsByTagName("*") returns only elements + support.getElementsByTagName = assert( function( el ) { + el.appendChild( document.createComment( "" ) ); + return !el.getElementsByTagName( "*" ).length; + } ); + + // Support: IE<9 + support.getElementsByClassName = rnative.test( document.getElementsByClassName ); + + // Support: IE<10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programmatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert( function( el ) { + docElem.appendChild( el ).id = expando; + return !document.getElementsByName || !document.getElementsByName( expando ).length; + } ); + + // ID filter and find + if ( support.getById ) { + Expr.filter[ "ID" ] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute( "id" ) === attrId; + }; + }; + Expr.find[ "ID" ] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var elem = context.getElementById( id ); + return elem ? [ elem ] : []; + } + }; + } else { + Expr.filter[ "ID" ] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== "undefined" && + elem.getAttributeNode( "id" ); + return node && node.value === attrId; + }; + }; + + // Support: IE 6 - 7 only + // getElementById is not reliable as a find shortcut + Expr.find[ "ID" ] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var node, i, elems, + elem = context.getElementById( id ); + + if ( elem ) { + + // Verify the id attribute + node = elem.getAttributeNode( "id" ); + if ( node && node.value === id ) { + return [ elem ]; + } + + // Fall back on getElementsByName + elems = context.getElementsByName( id ); + i = 0; + while ( ( elem = elems[ i++ ] ) ) { + node = elem.getAttributeNode( "id" ); + if ( node && node.value === id ) { + return [ elem ]; + } + } + } + + return []; + } + }; + } + + // Tag + Expr.find[ "TAG" ] = support.getElementsByTagName ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( tag ); + + // DocumentFragment nodes don't have gEBTN + } else if ( support.qsa ) { + return context.querySelectorAll( tag ); + } + } : + + function( tag, context ) { + var elem, + tmp = [], + i = 0, + + // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too + results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + while ( ( elem = results[ i++ ] ) ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }; + + // Class + Expr.find[ "CLASS" ] = support.getElementsByClassName && function( className, context ) { + if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { + return context.getElementsByClassName( className ); + } + }; + + /* QSA/matchesSelector + ---------------------------------------------------------------------- */ + + // QSA and matchesSelector support + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + rbuggyMatches = []; + + // qSa(:focus) reports false when true (Chrome 21) + // We allow this because of a bug in IE8/9 that throws an error + // whenever `document.activeElement` is accessed on an iframe + // So, we allow :focus to pass through QSA all the time to avoid the IE error + // See https://bugs.jquery.com/ticket/13378 + rbuggyQSA = []; + + if ( ( support.qsa = rnative.test( document.querySelectorAll ) ) ) { + + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert( function( el ) { + + var input; + + // Select is set to empty string on purpose + // This is to test IE's treatment of not explicitly + // setting a boolean content attribute, + // since its presence should be enough + // https://bugs.jquery.com/ticket/12359 + docElem.appendChild( el ).innerHTML = "" + + ""; + + // Support: IE8, Opera 11-12.16 + // Nothing should be selected when empty strings follow ^= or $= or *= + // The test attribute must be unknown in Opera but "safe" for WinRT + // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section + if ( el.querySelectorAll( "[msallowcapture^='']" ).length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); + } + + // Support: IE8 + // Boolean attributes and "value" are not treated correctly + if ( !el.querySelectorAll( "[selected]" ).length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); + } + + // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ + if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { + rbuggyQSA.push( "~=" ); + } + + // Support: IE 11+, Edge 15 - 18+ + // IE 11/Edge don't find elements on a `[name='']` query in some cases. + // Adding a temporary attribute to the document before the selection works + // around the issue. + // Interestingly, IE 10 & older don't seem to have the issue. + input = document.createElement( "input" ); + input.setAttribute( "name", "" ); + el.appendChild( input ); + if ( !el.querySelectorAll( "[name='']" ).length ) { + rbuggyQSA.push( "\\[" + whitespace + "*name" + whitespace + "*=" + + whitespace + "*(?:''|\"\")" ); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here and will not see later tests + if ( !el.querySelectorAll( ":checked" ).length ) { + rbuggyQSA.push( ":checked" ); + } + + // Support: Safari 8+, iOS 8+ + // https://bugs.webkit.org/show_bug.cgi?id=136851 + // In-page `selector#id sibling-combinator selector` fails + if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { + rbuggyQSA.push( ".#.+[+~]" ); + } + + // Support: Firefox <=3.6 - 5 only + // Old Firefox doesn't throw on a badly-escaped identifier. + el.querySelectorAll( "\\\f" ); + rbuggyQSA.push( "[\\r\\n\\f]" ); + } ); + + assert( function( el ) { + el.innerHTML = "" + + ""; + + // Support: Windows 8 Native Apps + // The type and name attributes are restricted during .innerHTML assignment + var input = document.createElement( "input" ); + input.setAttribute( "type", "hidden" ); + el.appendChild( input ).setAttribute( "name", "D" ); + + // Support: IE8 + // Enforce case-sensitivity of name attribute + if ( el.querySelectorAll( "[name=d]" ).length ) { + rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here and will not see later tests + if ( el.querySelectorAll( ":enabled" ).length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: IE9-11+ + // IE's :disabled selector does not pick up the children of disabled fieldsets + docElem.appendChild( el ).disabled = true; + if ( el.querySelectorAll( ":disabled" ).length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: Opera 10 - 11 only + // Opera 10-11 does not throw on post-comma invalid pseudos + el.querySelectorAll( "*,:x" ); + rbuggyQSA.push( ",.*:" ); + } ); + } + + if ( ( support.matchesSelector = rnative.test( ( matches = docElem.matches || + docElem.webkitMatchesSelector || + docElem.mozMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector ) ) ) ) { + + assert( function( el ) { + + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + support.disconnectedMatch = matches.call( el, "*" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( el, "[s!='']:x" ); + rbuggyMatches.push( "!=", pseudos ); + } ); + } + + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join( "|" ) ); + rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join( "|" ) ); + + /* Contains + ---------------------------------------------------------------------- */ + hasCompare = rnative.test( docElem.compareDocumentPosition ); + + // Element contains another + // Purposefully self-exclusive + // As in, an element does not contain itself + contains = hasCompare || rnative.test( docElem.contains ) ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && ( + adown.contains ? + adown.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + ) ); + } : + function( a, b ) { + if ( b ) { + while ( ( b = b.parentNode ) ) { + if ( b === a ) { + return true; + } + } + } + return false; + }; + + /* Sorting + ---------------------------------------------------------------------- */ + + // Document order sorting + sortOrder = hasCompare ? + function( a, b ) { + + // Flag for duplicate removal + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + // Sort on method existence if only one input has compareDocumentPosition + var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; + if ( compare ) { + return compare; + } + + // Calculate position if both inputs belong to the same document + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + compare = ( a.ownerDocument || a ) == ( b.ownerDocument || b ) ? + a.compareDocumentPosition( b ) : + + // Otherwise we know they are disconnected + 1; + + // Disconnected nodes + if ( compare & 1 || + ( !support.sortDetached && b.compareDocumentPosition( a ) === compare ) ) { + + // Choose the first element that is related to our preferred document + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( a == document || a.ownerDocument == preferredDoc && + contains( preferredDoc, a ) ) { + return -1; + } + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( b == document || b.ownerDocument == preferredDoc && + contains( preferredDoc, b ) ) { + return 1; + } + + // Maintain original order + return sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + } + + return compare & 4 ? -1 : 1; + } : + function( a, b ) { + + // Exit early if the nodes are identical + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + var cur, + i = 0, + aup = a.parentNode, + bup = b.parentNode, + ap = [ a ], + bp = [ b ]; + + // Parentless nodes are either documents or disconnected + if ( !aup || !bup ) { + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + /* eslint-disable eqeqeq */ + return a == document ? -1 : + b == document ? 1 : + /* eslint-enable eqeqeq */ + aup ? -1 : + bup ? 1 : + sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + + // If the nodes are siblings, we can do a quick check + } else if ( aup === bup ) { + return siblingCheck( a, b ); + } + + // Otherwise we need full lists of their ancestors for comparison + cur = a; + while ( ( cur = cur.parentNode ) ) { + ap.unshift( cur ); + } + cur = b; + while ( ( cur = cur.parentNode ) ) { + bp.unshift( cur ); + } + + // Walk down the tree looking for a discrepancy + while ( ap[ i ] === bp[ i ] ) { + i++; + } + + return i ? + + // Do a sibling check if the nodes have a common ancestor + siblingCheck( ap[ i ], bp[ i ] ) : + + // Otherwise nodes in our document sort first + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + /* eslint-disable eqeqeq */ + ap[ i ] == preferredDoc ? -1 : + bp[ i ] == preferredDoc ? 1 : + /* eslint-enable eqeqeq */ + 0; + }; + + return document; +}; + +Sizzle.matches = function( expr, elements ) { + return Sizzle( expr, null, null, elements ); +}; + +Sizzle.matchesSelector = function( elem, expr ) { + setDocument( elem ); + + if ( support.matchesSelector && documentIsHTML && + !nonnativeSelectorCache[ expr + " " ] && + ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && + ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { + + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || support.disconnectedMatch || + + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch ( e ) { + nonnativeSelectorCache( expr, true ); + } + } + + return Sizzle( expr, document, null, [ elem ] ).length > 0; +}; + +Sizzle.contains = function( context, elem ) { + + // Set document vars if needed + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( ( context.ownerDocument || context ) != document ) { + setDocument( context ); + } + return contains( context, elem ); +}; + +Sizzle.attr = function( elem, name ) { + + // Set document vars if needed + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( ( elem.ownerDocument || elem ) != document ) { + setDocument( elem ); + } + + var fn = Expr.attrHandle[ name.toLowerCase() ], + + // Don't get fooled by Object.prototype properties (jQuery #13807) + val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? + fn( elem, name, !documentIsHTML ) : + undefined; + + return val !== undefined ? + val : + support.attributes || !documentIsHTML ? + elem.getAttribute( name ) : + ( val = elem.getAttributeNode( name ) ) && val.specified ? + val.value : + null; +}; + +Sizzle.escape = function( sel ) { + return ( sel + "" ).replace( rcssescape, fcssescape ); +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Document sorting and removing duplicates + * @param {ArrayLike} results + */ +Sizzle.uniqueSort = function( results ) { + var elem, + duplicates = [], + j = 0, + i = 0; + + // Unless we *know* we can detect duplicates, assume their presence + hasDuplicate = !support.detectDuplicates; + sortInput = !support.sortStable && results.slice( 0 ); + results.sort( sortOrder ); + + if ( hasDuplicate ) { + while ( ( elem = results[ i++ ] ) ) { + if ( elem === results[ i ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + // Clear input after sorting to release objects + // See https://github.com/jquery/sizzle/pull/225 + sortInput = null; + + return results; +}; + +/** + * Utility function for retrieving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +getText = Sizzle.getText = function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( !nodeType ) { + + // If no nodeType, this is expected to be an array + while ( ( node = elem[ i++ ] ) ) { + + // Do not traverse comment nodes + ret += getText( node ); + } + } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + + // Use textContent for elements + // innerText usage removed for consistency of new lines (jQuery #11153) + if ( typeof elem.textContent === "string" ) { + return elem.textContent; + } else { + + // Traverse its children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + + // Do not include comment or processing instruction nodes + + return ret; +}; + +Expr = Sizzle.selectors = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + attrHandle: {}, + + find: {}, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + "ATTR": function( match ) { + match[ 1 ] = match[ 1 ].replace( runescape, funescape ); + + // Move the given value to match[3] whether quoted or unquoted + match[ 3 ] = ( match[ 3 ] || match[ 4 ] || + match[ 5 ] || "" ).replace( runescape, funescape ); + + if ( match[ 2 ] === "~=" ) { + match[ 3 ] = " " + match[ 3 ] + " "; + } + + return match.slice( 0, 4 ); + }, + + "CHILD": function( match ) { + + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 what (child|of-type) + 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 4 xn-component of xn+y argument ([+-]?\d*n|) + 5 sign of xn-component + 6 x of xn-component + 7 sign of y-component + 8 y of y-component + */ + match[ 1 ] = match[ 1 ].toLowerCase(); + + if ( match[ 1 ].slice( 0, 3 ) === "nth" ) { + + // nth-* requires argument + if ( !match[ 3 ] ) { + Sizzle.error( match[ 0 ] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[ 4 ] = +( match[ 4 ] ? + match[ 5 ] + ( match[ 6 ] || 1 ) : + 2 * ( match[ 3 ] === "even" || match[ 3 ] === "odd" ) ); + match[ 5 ] = +( ( match[ 7 ] + match[ 8 ] ) || match[ 3 ] === "odd" ); + + // other types prohibit arguments + } else if ( match[ 3 ] ) { + Sizzle.error( match[ 0 ] ); + } + + return match; + }, + + "PSEUDO": function( match ) { + var excess, + unquoted = !match[ 6 ] && match[ 2 ]; + + if ( matchExpr[ "CHILD" ].test( match[ 0 ] ) ) { + return null; + } + + // Accept quoted arguments as-is + if ( match[ 3 ] ) { + match[ 2 ] = match[ 4 ] || match[ 5 ] || ""; + + // Strip excess characters from unquoted arguments + } else if ( unquoted && rpseudo.test( unquoted ) && + + // Get excess from tokenize (recursively) + ( excess = tokenize( unquoted, true ) ) && + + // advance to the next closing parenthesis + ( excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length ) ) { + + // excess is a negative index + match[ 0 ] = match[ 0 ].slice( 0, excess ); + match[ 2 ] = unquoted.slice( 0, excess ); + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + + "TAG": function( nodeNameSelector ) { + var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); + return nodeNameSelector === "*" ? + function() { + return true; + } : + function( elem ) { + return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + }; + }, + + "CLASS": function( className ) { + var pattern = classCache[ className + " " ]; + + return pattern || + ( pattern = new RegExp( "(^|" + whitespace + + ")" + className + "(" + whitespace + "|$)" ) ) && classCache( + className, function( elem ) { + return pattern.test( + typeof elem.className === "string" && elem.className || + typeof elem.getAttribute !== "undefined" && + elem.getAttribute( "class" ) || + "" + ); + } ); + }, + + "ATTR": function( name, operator, check ) { + return function( elem ) { + var result = Sizzle.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + /* eslint-disable max-len */ + + return operator === "=" ? result === check : + operator === "!=" ? result !== check : + operator === "^=" ? check && result.indexOf( check ) === 0 : + operator === "*=" ? check && result.indexOf( check ) > -1 : + operator === "$=" ? check && result.slice( -check.length ) === check : + operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : + operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : + false; + /* eslint-enable max-len */ + + }; + }, + + "CHILD": function( type, what, _argument, first, last ) { + var simple = type.slice( 0, 3 ) !== "nth", + forward = type.slice( -4 ) !== "last", + ofType = what === "of-type"; + + return first === 1 && last === 0 ? + + // Shortcut for :nth-*(n) + function( elem ) { + return !!elem.parentNode; + } : + + function( elem, _context, xml ) { + var cache, uniqueCache, outerCache, node, nodeIndex, start, + dir = simple !== forward ? "nextSibling" : "previousSibling", + parent = elem.parentNode, + name = ofType && elem.nodeName.toLowerCase(), + useCache = !xml && !ofType, + diff = false; + + if ( parent ) { + + // :(first|last|only)-(child|of-type) + if ( simple ) { + while ( dir ) { + node = elem; + while ( ( node = node[ dir ] ) ) { + if ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) { + + return false; + } + } + + // Reverse direction for :only-* (if we haven't yet done so) + start = dir = type === "only" && !start && "nextSibling"; + } + return true; + } + + start = [ forward ? parent.firstChild : parent.lastChild ]; + + // non-xml :nth-child(...) stores cache data on `parent` + if ( forward && useCache ) { + + // Seek `elem` from a previously-cached index + + // ...in a gzip-friendly way + node = parent; + outerCache = node[ expando ] || ( node[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + ( outerCache[ node.uniqueID ] = {} ); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex && cache[ 2 ]; + node = nodeIndex && parent.childNodes[ nodeIndex ]; + + while ( ( node = ++nodeIndex && node && node[ dir ] || + + // Fallback to seeking `elem` from the start + ( diff = nodeIndex = 0 ) || start.pop() ) ) { + + // When found, cache indexes on `parent` and break + if ( node.nodeType === 1 && ++diff && node === elem ) { + uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; + break; + } + } + + } else { + + // Use previously-cached element index if available + if ( useCache ) { + + // ...in a gzip-friendly way + node = elem; + outerCache = node[ expando ] || ( node[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + ( outerCache[ node.uniqueID ] = {} ); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex; + } + + // xml :nth-child(...) + // or :nth-last-child(...) or :nth(-last)?-of-type(...) + if ( diff === false ) { + + // Use the same loop as above to seek `elem` from the start + while ( ( node = ++nodeIndex && node && node[ dir ] || + ( diff = nodeIndex = 0 ) || start.pop() ) ) { + + if ( ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) && + ++diff ) { + + // Cache the index of each encountered element + if ( useCache ) { + outerCache = node[ expando ] || + ( node[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + ( outerCache[ node.uniqueID ] = {} ); + + uniqueCache[ type ] = [ dirruns, diff ]; + } + + if ( node === elem ) { + break; + } + } + } + } + } + + // Incorporate the offset, then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + } + }; + }, + + "PSEUDO": function( pseudo, argument ) { + + // pseudo-class names are case-insensitive + // http://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + Sizzle.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as Sizzle does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction( function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf( seed, matched[ i ] ); + seed[ idx ] = !( matches[ idx ] = matched[ i ] ); + } + } ) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + + // Potentially complex pseudos + "not": markFunction( function( selector ) { + + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrim, "$1" ) ); + + return matcher[ expando ] ? + markFunction( function( seed, matches, _context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( ( elem = unmatched[ i ] ) ) { + seed[ i ] = !( matches[ i ] = elem ); + } + } + } ) : + function( elem, _context, xml ) { + input[ 0 ] = elem; + matcher( input, null, xml, results ); + + // Don't keep the element (issue #299) + input[ 0 ] = null; + return !results.pop(); + }; + } ), + + "has": markFunction( function( selector ) { + return function( elem ) { + return Sizzle( selector, elem ).length > 0; + }; + } ), + + "contains": markFunction( function( text ) { + text = text.replace( runescape, funescape ); + return function( elem ) { + return ( elem.textContent || getText( elem ) ).indexOf( text ) > -1; + }; + } ), + + // "Whether an element is represented by a :lang() selector + // is based solely on the element's language value + // being equal to the identifier C, + // or beginning with the identifier C immediately followed by "-". + // The matching of C against the element's language value is performed case-insensitively. + // The identifier C does not have to be a valid language name." + // http://www.w3.org/TR/selectors/#lang-pseudo + "lang": markFunction( function( lang ) { + + // lang value must be a valid identifier + if ( !ridentifier.test( lang || "" ) ) { + Sizzle.error( "unsupported lang: " + lang ); + } + lang = lang.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + var elemLang; + do { + if ( ( elemLang = documentIsHTML ? + elem.lang : + elem.getAttribute( "xml:lang" ) || elem.getAttribute( "lang" ) ) ) { + + elemLang = elemLang.toLowerCase(); + return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; + } + } while ( ( elem = elem.parentNode ) && elem.nodeType === 1 ); + return false; + }; + } ), + + // Miscellaneous + "target": function( elem ) { + var hash = window.location && window.location.hash; + return hash && hash.slice( 1 ) === elem.id; + }, + + "root": function( elem ) { + return elem === docElem; + }, + + "focus": function( elem ) { + return elem === document.activeElement && + ( !document.hasFocus || document.hasFocus() ) && + !!( elem.type || elem.href || ~elem.tabIndex ); + }, + + // Boolean properties + "enabled": createDisabledPseudo( false ), + "disabled": createDisabledPseudo( true ), + + "checked": function( elem ) { + + // In CSS3, :checked should return both checked and selected elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + var nodeName = elem.nodeName.toLowerCase(); + return ( nodeName === "input" && !!elem.checked ) || + ( nodeName === "option" && !!elem.selected ); + }, + + "selected": function( elem ) { + + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + // eslint-disable-next-line no-unused-expressions + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + // Contents + "empty": function( elem ) { + + // http://www.w3.org/TR/selectors/#empty-pseudo + // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), + // but not by others (comment: 8; processing instruction: 7; etc.) + // nodeType < 6 works because attributes (2) do not appear as children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + if ( elem.nodeType < 6 ) { + return false; + } + } + return true; + }, + + "parent": function( elem ) { + return !Expr.pseudos[ "empty" ]( elem ); + }, + + // Element/input types + "header": function( elem ) { + return rheader.test( elem.nodeName ); + }, + + "input": function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + "button": function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === "button" || name === "button"; + }, + + "text": function( elem ) { + var attr; + return elem.nodeName.toLowerCase() === "input" && + elem.type === "text" && + + // Support: IE<8 + // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" + ( ( attr = elem.getAttribute( "type" ) ) == null || + attr.toLowerCase() === "text" ); + }, + + // Position-in-collection + "first": createPositionalPseudo( function() { + return [ 0 ]; + } ), + + "last": createPositionalPseudo( function( _matchIndexes, length ) { + return [ length - 1 ]; + } ), + + "eq": createPositionalPseudo( function( _matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + } ), + + "even": createPositionalPseudo( function( matchIndexes, length ) { + var i = 0; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + "odd": createPositionalPseudo( function( matchIndexes, length ) { + var i = 1; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + "lt": createPositionalPseudo( function( matchIndexes, length, argument ) { + var i = argument < 0 ? + argument + length : + argument > length ? + length : + argument; + for ( ; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + "gt": createPositionalPseudo( function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ) + } +}; + +Expr.pseudos[ "nth" ] = Expr.pseudos[ "eq" ]; + +// Add button/input type pseudos +for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { + Expr.pseudos[ i ] = createInputPseudo( i ); +} +for ( i in { submit: true, reset: true } ) { + Expr.pseudos[ i ] = createButtonPseudo( i ); +} + +// Easy API for creating new setFilters +function setFilters() {} +setFilters.prototype = Expr.filters = Expr.pseudos; +Expr.setFilters = new setFilters(); + +tokenize = Sizzle.tokenize = function( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || ( match = rcomma.exec( soFar ) ) ) { + if ( match ) { + + // Don't consume trailing commas as valid + soFar = soFar.slice( match[ 0 ].length ) || soFar; + } + groups.push( ( tokens = [] ) ); + } + + matched = false; + + // Combinators + if ( ( match = rcombinators.exec( soFar ) ) ) { + matched = match.shift(); + tokens.push( { + value: matched, + + // Cast descendant combinators to space + type: match[ 0 ].replace( rtrim, " " ) + } ); + soFar = soFar.slice( matched.length ); + } + + // Filters + for ( type in Expr.filter ) { + if ( ( match = matchExpr[ type ].exec( soFar ) ) && ( !preFilters[ type ] || + ( match = preFilters[ type ]( match ) ) ) ) { + matched = match.shift(); + tokens.push( { + value: matched, + type: type, + matches: match + } ); + soFar = soFar.slice( matched.length ); + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + return parseOnly ? + soFar.length : + soFar ? + Sizzle.error( selector ) : + + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +}; + +function toSelector( tokens ) { + var i = 0, + len = tokens.length, + selector = ""; + for ( ; i < len; i++ ) { + selector += tokens[ i ].value; + } + return selector; +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + skip = combinator.next, + key = skip || dir, + checkNonElements = base && key === "parentNode", + doneName = done++; + + return combinator.first ? + + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + return matcher( elem, context, xml ); + } + } + return false; + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + var oldCache, uniqueCache, outerCache, + newCache = [ dirruns, doneName ]; + + // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching + if ( xml ) { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + if ( matcher( elem, context, xml ) ) { + return true; + } + } + } + } else { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + outerCache = elem[ expando ] || ( elem[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ elem.uniqueID ] || + ( outerCache[ elem.uniqueID ] = {} ); + + if ( skip && skip === elem.nodeName.toLowerCase() ) { + elem = elem[ dir ] || elem; + } else if ( ( oldCache = uniqueCache[ key ] ) && + oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { + + // Assign to newCache so results back-propagate to previous elements + return ( newCache[ 2 ] = oldCache[ 2 ] ); + } else { + + // Reuse newcache so results back-propagate to previous elements + uniqueCache[ key ] = newCache; + + // A match means we're done; a fail means we have to keep checking + if ( ( newCache[ 2 ] = matcher( elem, context, xml ) ) ) { + return true; + } + } + } + } + } + return false; + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[ i ]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[ 0 ]; +} + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + Sizzle( selector, contexts[ i ], results ); + } + return results; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( ( elem = unmatched[ i ] ) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction( function( seed, results, context, xml ) { + var temp, i, elem, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || multipleContexts( + selector || "*", + context.nodeType ? [ context ] : context, + [] + ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems, + + matcherOut = matcher ? + + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, + postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results : + matcherIn; + + // Find primary matches + if ( matcher ) { + matcher( matcherIn, matcherOut, context, xml ); + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( ( elem = temp[ i ] ) ) { + matcherOut[ postMap[ i ] ] = !( matcherIn[ postMap[ i ] ] = elem ); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( ( elem = matcherOut[ i ] ) ) { + + // Restore matcherIn since elem is not yet a final match + temp.push( ( matcherIn[ i ] = elem ) ); + } + } + postFinder( null, ( matcherOut = [] ), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( ( elem = matcherOut[ i ] ) && + ( temp = postFinder ? indexOf( seed, elem ) : preMap[ i ] ) > -1 ) { + + seed[ temp ] = !( results[ temp ] = elem ); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + } ); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[ 0 ].type ], + implicitRelative = leadingRelative || Expr.relative[ " " ], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + ( checkContext = context ).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + + // Avoid hanging onto element (issue #299) + checkContext = null; + return ret; + } ]; + + for ( ; i < len; i++ ) { + if ( ( matcher = Expr.relative[ tokens[ i ].type ] ) ) { + matchers = [ addCombinator( elementMatcher( matchers ), matcher ) ]; + } else { + matcher = Expr.filter[ tokens[ i ].type ].apply( null, tokens[ i ].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[ j ].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && toSelector( + + // If the preceding token was a descendant combinator, insert an implicit any-element `*` + tokens + .slice( 0, i - 1 ) + .concat( { value: tokens[ i - 2 ].type === " " ? "*" : "" } ) + ).replace( rtrim, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( ( tokens = tokens.slice( j ) ) ), + j < len && toSelector( tokens ) + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + var bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, outermost ) { + var elem, j, matcher, + matchedCount = 0, + i = "0", + unmatched = seed && [], + setMatched = [], + contextBackup = outermostContext, + + // We must always have either seed elements or outermost context + elems = seed || byElement && Expr.find[ "TAG" ]( "*", outermost ), + + // Use integer dirruns iff this is the outermost matcher + dirrunsUnique = ( dirruns += contextBackup == null ? 1 : Math.random() || 0.1 ), + len = elems.length; + + if ( outermost ) { + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + outermostContext = context == document || context || outermost; + } + + // Add elements passing elementMatchers directly to results + // Support: IE<9, Safari + // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id + for ( ; i !== len && ( elem = elems[ i ] ) != null; i++ ) { + if ( byElement && elem ) { + j = 0; + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( !context && elem.ownerDocument != document ) { + setDocument( elem ); + xml = !documentIsHTML; + } + while ( ( matcher = elementMatchers[ j++ ] ) ) { + if ( matcher( elem, context || document, xml ) ) { + results.push( elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + + // They will have gone through all possible matchers + if ( ( elem = !matcher && elem ) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // `i` is now the count of elements visited above, and adding it to `matchedCount` + // makes the latter nonnegative. + matchedCount += i; + + // Apply set filters to unmatched elements + // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` + // equals `i`), unless we didn't visit _any_ elements in the above loop because we have + // no element matchers and no seed. + // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that + // case, which will result in a "00" `matchedCount` that differs from `i` but is also + // numerically zero. + if ( bySet && i !== matchedCount ) { + j = 0; + while ( ( matcher = setMatchers[ j++ ] ) ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !( unmatched[ i ] || setMatched[ i ] ) ) { + setMatched[ i ] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + Sizzle.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ selector + " " ]; + + if ( !cached ) { + + // Generate a function of recursive functions that can be used to check each element + if ( !match ) { + match = tokenize( selector ); + } + i = match.length; + while ( i-- ) { + cached = matcherFromTokens( match[ i ] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( + selector, + matcherFromGroupMatchers( elementMatchers, setMatchers ) + ); + + // Save selector and tokenization + cached.selector = selector; + } + return cached; +}; + +/** + * A low-level selection function that works with Sizzle's compiled + * selector functions + * @param {String|Function} selector A selector or a pre-compiled + * selector function built with Sizzle.compile + * @param {Element} context + * @param {Array} [results] + * @param {Array} [seed] A set of elements to match against + */ +select = Sizzle.select = function( selector, context, results, seed ) { + var i, tokens, token, type, find, + compiled = typeof selector === "function" && selector, + match = !seed && tokenize( ( selector = compiled.selector || selector ) ); + + results = results || []; + + // Try to minimize operations if there is only one selector in the list and no seed + // (the latter of which guarantees us context) + if ( match.length === 1 ) { + + // Reduce context if the leading compound selector is an ID + tokens = match[ 0 ] = match[ 0 ].slice( 0 ); + if ( tokens.length > 2 && ( token = tokens[ 0 ] ).type === "ID" && + context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[ 1 ].type ] ) { + + context = ( Expr.find[ "ID" ]( token.matches[ 0 ] + .replace( runescape, funescape ), context ) || [] )[ 0 ]; + if ( !context ) { + return results; + + // Precompiled matchers will still verify ancestry, so step up a level + } else if ( compiled ) { + context = context.parentNode; + } + + selector = selector.slice( tokens.shift().value.length ); + } + + // Fetch a seed set for right-to-left matching + i = matchExpr[ "needsContext" ].test( selector ) ? 0 : tokens.length; + while ( i-- ) { + token = tokens[ i ]; + + // Abort if we hit a combinator + if ( Expr.relative[ ( type = token.type ) ] ) { + break; + } + if ( ( find = Expr.find[ type ] ) ) { + + // Search, expanding context for leading sibling combinators + if ( ( seed = find( + token.matches[ 0 ].replace( runescape, funescape ), + rsibling.test( tokens[ 0 ].type ) && testContext( context.parentNode ) || + context + ) ) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && toSelector( tokens ); + if ( !selector ) { + push.apply( results, seed ); + return results; + } + + break; + } + } + } + } + + // Compile and execute a filtering function if one is not provided + // Provide `match` to avoid retokenization if we modified the selector above + ( compiled || compile( selector, match ) )( + seed, + context, + !documentIsHTML, + results, + !context || rsibling.test( selector ) && testContext( context.parentNode ) || context + ); + return results; +}; + +// One-time assignments + +// Sort stability +support.sortStable = expando.split( "" ).sort( sortOrder ).join( "" ) === expando; + +// Support: Chrome 14-35+ +// Always assume duplicates if they aren't passed to the comparison function +support.detectDuplicates = !!hasDuplicate; + +// Initialize against the default document +setDocument(); + +// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) +// Detached nodes confoundingly follow *each other* +support.sortDetached = assert( function( el ) { + + // Should return 1, but returns 4 (following) + return el.compareDocumentPosition( document.createElement( "fieldset" ) ) & 1; +} ); + +// Support: IE<8 +// Prevent attribute/property "interpolation" +// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx +if ( !assert( function( el ) { + el.innerHTML = ""; + return el.firstChild.getAttribute( "href" ) === "#"; +} ) ) { + addHandle( "type|href|height|width", function( elem, name, isXML ) { + if ( !isXML ) { + return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); + } + } ); +} + +// Support: IE<9 +// Use defaultValue in place of getAttribute("value") +if ( !support.attributes || !assert( function( el ) { + el.innerHTML = ""; + el.firstChild.setAttribute( "value", "" ); + return el.firstChild.getAttribute( "value" ) === ""; +} ) ) { + addHandle( "value", function( elem, _name, isXML ) { + if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { + return elem.defaultValue; + } + } ); +} + +// Support: IE<9 +// Use getAttributeNode to fetch booleans when getAttribute lies +if ( !assert( function( el ) { + return el.getAttribute( "disabled" ) == null; +} ) ) { + addHandle( booleans, function( elem, name, isXML ) { + var val; + if ( !isXML ) { + return elem[ name ] === true ? name.toLowerCase() : + ( val = elem.getAttributeNode( name ) ) && val.specified ? + val.value : + null; + } + } ); +} + +return Sizzle; + +} )( window ); + + + +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; + +// Deprecated +jQuery.expr[ ":" ] = jQuery.expr.pseudos; +jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; +jQuery.escapeSelector = Sizzle.escape; + + + + +var dir = function( elem, dir, until ) { + var matched = [], + truncate = until !== undefined; + + while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { + if ( elem.nodeType === 1 ) { + if ( truncate && jQuery( elem ).is( until ) ) { + break; + } + matched.push( elem ); + } + } + return matched; +}; + + +var siblings = function( n, elem ) { + var matched = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + matched.push( n ); + } + } + + return matched; +}; + + +var rneedsContext = jQuery.expr.match.needsContext; + + + +function nodeName( elem, name ) { + + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + +}; +var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); + + + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, not ) { + if ( isFunction( qualifier ) ) { + return jQuery.grep( elements, function( elem, i ) { + return !!qualifier.call( elem, i, elem ) !== not; + } ); + } + + // Single element + if ( qualifier.nodeType ) { + return jQuery.grep( elements, function( elem ) { + return ( elem === qualifier ) !== not; + } ); + } + + // Arraylike of elements (jQuery, arguments, Array) + if ( typeof qualifier !== "string" ) { + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) > -1 ) !== not; + } ); + } + + // Filtered directly for both simple and complex selectors + return jQuery.filter( qualifier, elements, not ); +} + +jQuery.filter = function( expr, elems, not ) { + var elem = elems[ 0 ]; + + if ( not ) { + expr = ":not(" + expr + ")"; + } + + if ( elems.length === 1 && elem.nodeType === 1 ) { + return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : []; + } + + return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { + return elem.nodeType === 1; + } ) ); +}; + +jQuery.fn.extend( { + find: function( selector ) { + var i, ret, + len = this.length, + self = this; + + if ( typeof selector !== "string" ) { + return this.pushStack( jQuery( selector ).filter( function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + } ) ); + } + + ret = this.pushStack( [] ); + + for ( i = 0; i < len; i++ ) { + jQuery.find( selector, self[ i ], ret ); + } + + return len > 1 ? jQuery.uniqueSort( ret ) : ret; + }, + filter: function( selector ) { + return this.pushStack( winnow( this, selector || [], false ) ); + }, + not: function( selector ) { + return this.pushStack( winnow( this, selector || [], true ) ); + }, + is: function( selector ) { + return !!winnow( + this, + + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + typeof selector === "string" && rneedsContext.test( selector ) ? + jQuery( selector ) : + selector || [], + false + ).length; + } +} ); + + +// Initialize a jQuery object + + +// A central reference to the root jQuery(document) +var rootjQuery, + + // A simple way to check for HTML strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + // Strict HTML recognition (#11290: must start with <) + // Shortcut simple #id case for speed + rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, + + init = jQuery.fn.init = function( selector, context, root ) { + var match, elem; + + // HANDLE: $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Method init() accepts an alternate rootjQuery + // so migrate can support jQuery.sub (gh-2101) + root = root || rootjQuery; + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector[ 0 ] === "<" && + selector[ selector.length - 1 ] === ">" && + selector.length >= 3 ) { + + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && ( match[ 1 ] || !context ) ) { + + // HANDLE: $(html) -> $(array) + if ( match[ 1 ] ) { + context = context instanceof jQuery ? context[ 0 ] : context; + + // Option to run scripts is true for back-compat + // Intentionally let the error be thrown if parseHTML is not present + jQuery.merge( this, jQuery.parseHTML( + match[ 1 ], + context && context.nodeType ? context.ownerDocument || context : document, + true + ) ); + + // HANDLE: $(html, props) + if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { + for ( match in context ) { + + // Properties of context are called as methods if possible + if ( isFunction( this[ match ] ) ) { + this[ match ]( context[ match ] ); + + // ...and otherwise set as attributes + } else { + this.attr( match, context[ match ] ); + } + } + } + + return this; + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[ 2 ] ); + + if ( elem ) { + + // Inject the element directly into the jQuery object + this[ 0 ] = elem; + this.length = 1; + } + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || root ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(DOMElement) + } else if ( selector.nodeType ) { + this[ 0 ] = selector; + this.length = 1; + return this; + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( isFunction( selector ) ) { + return root.ready !== undefined ? + root.ready( selector ) : + + // Execute immediately if ready is not present + selector( jQuery ); + } + + return jQuery.makeArray( selector, this ); + }; + +// Give the init function the jQuery prototype for later instantiation +init.prototype = jQuery.fn; + +// Initialize central reference +rootjQuery = jQuery( document ); + + +var rparentsprev = /^(?:parents|prev(?:Until|All))/, + + // Methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend( { + has: function( target ) { + var targets = jQuery( target, this ), + l = targets.length; + + return this.filter( function() { + var i = 0; + for ( ; i < l; i++ ) { + if ( jQuery.contains( this, targets[ i ] ) ) { + return true; + } + } + } ); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + matched = [], + targets = typeof selectors !== "string" && jQuery( selectors ); + + // Positional selectors never match, since there's no _selection_ context + if ( !rneedsContext.test( selectors ) ) { + for ( ; i < l; i++ ) { + for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { + + // Always skip document fragments + if ( cur.nodeType < 11 && ( targets ? + targets.index( cur ) > -1 : + + // Don't pass non-elements to Sizzle + cur.nodeType === 1 && + jQuery.find.matchesSelector( cur, selectors ) ) ) { + + matched.push( cur ); + break; + } + } + } + } + + return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); + }, + + // Determine the position of an element within the set + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; + } + + // Index in selector + if ( typeof elem === "string" ) { + return indexOf.call( jQuery( elem ), this[ 0 ] ); + } + + // Locate the position of the desired element + return indexOf.call( this, + + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[ 0 ] : elem + ); + }, + + add: function( selector, context ) { + return this.pushStack( + jQuery.uniqueSort( + jQuery.merge( this.get(), jQuery( selector, context ) ) + ) + ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter( selector ) + ); + } +} ); + +function sibling( cur, dir ) { + while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} + return cur; +} + +jQuery.each( { + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, _i, until ) { + return dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, _i, until ) { + return dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, _i, until ) { + return dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return siblings( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return siblings( elem.firstChild ); + }, + contents: function( elem ) { + if ( elem.contentDocument != null && + + // Support: IE 11+ + // elements with no `data` attribute has an object + // `contentDocument` with a `null` prototype. + getProto( elem.contentDocument ) ) { + + return elem.contentDocument; + } + + // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only + // Treat the template element as a regular one in browsers that + // don't support it. + if ( nodeName( elem, "template" ) ) { + elem = elem.content || elem; + } + + return jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var matched = jQuery.map( this, fn, until ); + + if ( name.slice( -5 ) !== "Until" ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + matched = jQuery.filter( selector, matched ); + } + + if ( this.length > 1 ) { + + // Remove duplicates + if ( !guaranteedUnique[ name ] ) { + jQuery.uniqueSort( matched ); + } + + // Reverse order for parents* and prev-derivatives + if ( rparentsprev.test( name ) ) { + matched.reverse(); + } + } + + return this.pushStack( matched ); + }; +} ); +var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g ); + + + +// Convert String-formatted options into Object-formatted ones +function createOptions( options ) { + var object = {}; + jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) { + object[ flag ] = true; + } ); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + createOptions( options ) : + jQuery.extend( {}, options ); + + var // Flag to know if list is currently firing + firing, + + // Last fire value for non-forgettable lists + memory, + + // Flag to know if list was already fired + fired, + + // Flag to prevent firing + locked, + + // Actual callback list + list = [], + + // Queue of execution data for repeatable lists + queue = [], + + // Index of currently firing callback (modified by add/remove as needed) + firingIndex = -1, + + // Fire callbacks + fire = function() { + + // Enforce single-firing + locked = locked || options.once; + + // Execute callbacks for all pending executions, + // respecting firingIndex overrides and runtime changes + fired = firing = true; + for ( ; queue.length; firingIndex = -1 ) { + memory = queue.shift(); + while ( ++firingIndex < list.length ) { + + // Run callback and check for early termination + if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && + options.stopOnFalse ) { + + // Jump to end and forget the data so .add doesn't re-fire + firingIndex = list.length; + memory = false; + } + } + } + + // Forget the data if we're done with it + if ( !options.memory ) { + memory = false; + } + + firing = false; + + // Clean up if we're done firing for good + if ( locked ) { + + // Keep an empty list if we have data for future add calls + if ( memory ) { + list = []; + + // Otherwise, this object is spent + } else { + list = ""; + } + } + }, + + // Actual Callbacks object + self = { + + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + + // If we have memory from a past run, we should fire after adding + if ( memory && !firing ) { + firingIndex = list.length - 1; + queue.push( memory ); + } + + ( function add( args ) { + jQuery.each( args, function( _, arg ) { + if ( isFunction( arg ) ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && toType( arg ) !== "string" ) { + + // Inspect recursively + add( arg ); + } + } ); + } )( arguments ); + + if ( memory && !firing ) { + fire(); + } + } + return this; + }, + + // Remove a callback from the list + remove: function() { + jQuery.each( arguments, function( _, arg ) { + var index; + while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + + // Handle firing indexes + if ( index <= firingIndex ) { + firingIndex--; + } + } + } ); + return this; + }, + + // Check if a given callback is in the list. + // If no argument is given, return whether or not list has callbacks attached. + has: function( fn ) { + return fn ? + jQuery.inArray( fn, list ) > -1 : + list.length > 0; + }, + + // Remove all callbacks from the list + empty: function() { + if ( list ) { + list = []; + } + return this; + }, + + // Disable .fire and .add + // Abort any current/pending executions + // Clear all callbacks and values + disable: function() { + locked = queue = []; + list = memory = ""; + return this; + }, + disabled: function() { + return !list; + }, + + // Disable .fire + // Also disable .add unless we have memory (since it would have no effect) + // Abort any pending executions + lock: function() { + locked = queue = []; + if ( !memory && !firing ) { + list = memory = ""; + } + return this; + }, + locked: function() { + return !!locked; + }, + + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( !locked ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + queue.push( args ); + if ( !firing ) { + fire(); + } + } + return this; + }, + + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; + + +function Identity( v ) { + return v; +} +function Thrower( ex ) { + throw ex; +} + +function adoptValue( value, resolve, reject, noValue ) { + var method; + + try { + + // Check for promise aspect first to privilege synchronous behavior + if ( value && isFunction( ( method = value.promise ) ) ) { + method.call( value ).done( resolve ).fail( reject ); + + // Other thenables + } else if ( value && isFunction( ( method = value.then ) ) ) { + method.call( value, resolve, reject ); + + // Other non-thenables + } else { + + // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: + // * false: [ value ].slice( 0 ) => resolve( value ) + // * true: [ value ].slice( 1 ) => resolve() + resolve.apply( undefined, [ value ].slice( noValue ) ); + } + + // For Promises/A+, convert exceptions into rejections + // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in + // Deferred#then to conditionally suppress rejection. + } catch ( value ) { + + // Support: Android 4.0 only + // Strict mode functions invoked without .call/.apply get global-object context + reject.apply( undefined, [ value ] ); + } +} + +jQuery.extend( { + + Deferred: function( func ) { + var tuples = [ + + // action, add listener, callbacks, + // ... .then handlers, argument index, [final state] + [ "notify", "progress", jQuery.Callbacks( "memory" ), + jQuery.Callbacks( "memory" ), 2 ], + [ "resolve", "done", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 0, "resolved" ], + [ "reject", "fail", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 1, "rejected" ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + "catch": function( fn ) { + return promise.then( null, fn ); + }, + + // Keep pipe for back-compat + pipe: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + + return jQuery.Deferred( function( newDefer ) { + jQuery.each( tuples, function( _i, tuple ) { + + // Map tuples (progress, done, fail) to arguments (done, fail, progress) + var fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; + + // deferred.progress(function() { bind to newDefer or newDefer.notify }) + // deferred.done(function() { bind to newDefer or newDefer.resolve }) + // deferred.fail(function() { bind to newDefer or newDefer.reject }) + deferred[ tuple[ 1 ] ]( function() { + var returned = fn && fn.apply( this, arguments ); + if ( returned && isFunction( returned.promise ) ) { + returned.promise() + .progress( newDefer.notify ) + .done( newDefer.resolve ) + .fail( newDefer.reject ); + } else { + newDefer[ tuple[ 0 ] + "With" ]( + this, + fn ? [ returned ] : arguments + ); + } + } ); + } ); + fns = null; + } ).promise(); + }, + then: function( onFulfilled, onRejected, onProgress ) { + var maxDepth = 0; + function resolve( depth, deferred, handler, special ) { + return function() { + var that = this, + args = arguments, + mightThrow = function() { + var returned, then; + + // Support: Promises/A+ section 2.3.3.3.3 + // https://promisesaplus.com/#point-59 + // Ignore double-resolution attempts + if ( depth < maxDepth ) { + return; + } + + returned = handler.apply( that, args ); + + // Support: Promises/A+ section 2.3.1 + // https://promisesaplus.com/#point-48 + if ( returned === deferred.promise() ) { + throw new TypeError( "Thenable self-resolution" ); + } + + // Support: Promises/A+ sections 2.3.3.1, 3.5 + // https://promisesaplus.com/#point-54 + // https://promisesaplus.com/#point-75 + // Retrieve `then` only once + then = returned && + + // Support: Promises/A+ section 2.3.4 + // https://promisesaplus.com/#point-64 + // Only check objects and functions for thenability + ( typeof returned === "object" || + typeof returned === "function" ) && + returned.then; + + // Handle a returned thenable + if ( isFunction( then ) ) { + + // Special processors (notify) just wait for resolution + if ( special ) { + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ) + ); + + // Normal processors (resolve) also hook into progress + } else { + + // ...and disregard older resolution values + maxDepth++; + + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ), + resolve( maxDepth, deferred, Identity, + deferred.notifyWith ) + ); + } + + // Handle all other returned values + } else { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Identity ) { + that = undefined; + args = [ returned ]; + } + + // Process the value(s) + // Default process is resolve + ( special || deferred.resolveWith )( that, args ); + } + }, + + // Only normal processors (resolve) catch and reject exceptions + process = special ? + mightThrow : + function() { + try { + mightThrow(); + } catch ( e ) { + + if ( jQuery.Deferred.exceptionHook ) { + jQuery.Deferred.exceptionHook( e, + process.stackTrace ); + } + + // Support: Promises/A+ section 2.3.3.3.4.1 + // https://promisesaplus.com/#point-61 + // Ignore post-resolution exceptions + if ( depth + 1 >= maxDepth ) { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Thrower ) { + that = undefined; + args = [ e ]; + } + + deferred.rejectWith( that, args ); + } + } + }; + + // Support: Promises/A+ section 2.3.3.3.1 + // https://promisesaplus.com/#point-57 + // Re-resolve promises immediately to dodge false rejection from + // subsequent errors + if ( depth ) { + process(); + } else { + + // Call an optional hook to record the stack, in case of exception + // since it's otherwise lost when execution goes async + if ( jQuery.Deferred.getStackHook ) { + process.stackTrace = jQuery.Deferred.getStackHook(); + } + window.setTimeout( process ); + } + }; + } + + return jQuery.Deferred( function( newDefer ) { + + // progress_handlers.add( ... ) + tuples[ 0 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onProgress ) ? + onProgress : + Identity, + newDefer.notifyWith + ) + ); + + // fulfilled_handlers.add( ... ) + tuples[ 1 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onFulfilled ) ? + onFulfilled : + Identity + ) + ); + + // rejected_handlers.add( ... ) + tuples[ 2 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onRejected ) ? + onRejected : + Thrower + ) + ); + } ).promise(); + }, + + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 5 ]; + + // promise.progress = list.add + // promise.done = list.add + // promise.fail = list.add + promise[ tuple[ 1 ] ] = list.add; + + // Handle state + if ( stateString ) { + list.add( + function() { + + // state = "resolved" (i.e., fulfilled) + // state = "rejected" + state = stateString; + }, + + // rejected_callbacks.disable + // fulfilled_callbacks.disable + tuples[ 3 - i ][ 2 ].disable, + + // rejected_handlers.disable + // fulfilled_handlers.disable + tuples[ 3 - i ][ 3 ].disable, + + // progress_callbacks.lock + tuples[ 0 ][ 2 ].lock, + + // progress_handlers.lock + tuples[ 0 ][ 3 ].lock + ); + } + + // progress_handlers.fire + // fulfilled_handlers.fire + // rejected_handlers.fire + list.add( tuple[ 3 ].fire ); + + // deferred.notify = function() { deferred.notifyWith(...) } + // deferred.resolve = function() { deferred.resolveWith(...) } + // deferred.reject = function() { deferred.rejectWith(...) } + deferred[ tuple[ 0 ] ] = function() { + deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); + return this; + }; + + // deferred.notifyWith = list.fireWith + // deferred.resolveWith = list.fireWith + // deferred.rejectWith = list.fireWith + deferred[ tuple[ 0 ] + "With" ] = list.fireWith; + } ); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( singleValue ) { + var + + // count of uncompleted subordinates + remaining = arguments.length, + + // count of unprocessed arguments + i = remaining, + + // subordinate fulfillment data + resolveContexts = Array( i ), + resolveValues = slice.call( arguments ), + + // the master Deferred + master = jQuery.Deferred(), + + // subordinate callback factory + updateFunc = function( i ) { + return function( value ) { + resolveContexts[ i ] = this; + resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; + if ( !( --remaining ) ) { + master.resolveWith( resolveContexts, resolveValues ); + } + }; + }; + + // Single- and empty arguments are adopted like Promise.resolve + if ( remaining <= 1 ) { + adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject, + !remaining ); + + // Use .then() to unwrap secondary thenables (cf. gh-3000) + if ( master.state() === "pending" || + isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { + + return master.then(); + } + } + + // Multiple arguments are aggregated like Promise.all array elements + while ( i-- ) { + adoptValue( resolveValues[ i ], updateFunc( i ), master.reject ); + } + + return master.promise(); + } +} ); + + +// These usually indicate a programmer mistake during development, +// warn about them ASAP rather than swallowing them by default. +var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; + +jQuery.Deferred.exceptionHook = function( error, stack ) { + + // Support: IE 8 - 9 only + // Console exists when dev tools are open, which can happen at any time + if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { + window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack ); + } +}; + + + + +jQuery.readyException = function( error ) { + window.setTimeout( function() { + throw error; + } ); +}; + + + + +// The deferred used on DOM ready +var readyList = jQuery.Deferred(); + +jQuery.fn.ready = function( fn ) { + + readyList + .then( fn ) + + // Wrap jQuery.readyException in a function so that the lookup + // happens at the time of error handling instead of callback + // registration. + .catch( function( error ) { + jQuery.readyException( error ); + } ); + + return this; +}; + +jQuery.extend( { + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + } +} ); + +jQuery.ready.then = readyList.then; + +// The ready event handler and self cleanup method +function completed() { + document.removeEventListener( "DOMContentLoaded", completed ); + window.removeEventListener( "load", completed ); + jQuery.ready(); +} + +// Catch cases where $(document).ready() is called +// after the browser event has already occurred. +// Support: IE <=9 - 10 only +// Older IE sometimes signals "interactive" too soon +if ( document.readyState === "complete" || + ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { + + // Handle it asynchronously to allow scripts the opportunity to delay ready + window.setTimeout( jQuery.ready ); + +} else { + + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", completed ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", completed ); +} + + + + +// Multifunctional method to get and set values of a collection +// The value/s can optionally be executed if it's a function +var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { + var i = 0, + len = elems.length, + bulk = key == null; + + // Sets many values + if ( toType( key ) === "object" ) { + chainable = true; + for ( i in key ) { + access( elems, fn, i, key[ i ], true, emptyGet, raw ); + } + + // Sets one value + } else if ( value !== undefined ) { + chainable = true; + + if ( !isFunction( value ) ) { + raw = true; + } + + if ( bulk ) { + + // Bulk operations run against the entire set + if ( raw ) { + fn.call( elems, value ); + fn = null; + + // ...except when executing function values + } else { + bulk = fn; + fn = function( elem, _key, value ) { + return bulk.call( jQuery( elem ), value ); + }; + } + } + + if ( fn ) { + for ( ; i < len; i++ ) { + fn( + elems[ i ], key, raw ? + value : + value.call( elems[ i ], i, fn( elems[ i ], key ) ) + ); + } + } + } + + if ( chainable ) { + return elems; + } + + // Gets + if ( bulk ) { + return fn.call( elems ); + } + + return len ? fn( elems[ 0 ], key ) : emptyGet; +}; + + +// Matches dashed string for camelizing +var rmsPrefix = /^-ms-/, + rdashAlpha = /-([a-z])/g; + +// Used by camelCase as callback to replace() +function fcamelCase( _all, letter ) { + return letter.toUpperCase(); +} + +// Convert dashed to camelCase; used by the css and data modules +// Support: IE <=9 - 11, Edge 12 - 15 +// Microsoft forgot to hump their vendor prefix (#9572) +function camelCase( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); +} +var acceptData = function( owner ) { + + // Accepts only: + // - Node + // - Node.ELEMENT_NODE + // - Node.DOCUMENT_NODE + // - Object + // - Any + return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); +}; + + + + +function Data() { + this.expando = jQuery.expando + Data.uid++; +} + +Data.uid = 1; + +Data.prototype = { + + cache: function( owner ) { + + // Check if the owner object already has a cache + var value = owner[ this.expando ]; + + // If not, create one + if ( !value ) { + value = {}; + + // We can accept data for non-element nodes in modern browsers, + // but we should not, see #8335. + // Always return an empty object. + if ( acceptData( owner ) ) { + + // If it is a node unlikely to be stringify-ed or looped over + // use plain assignment + if ( owner.nodeType ) { + owner[ this.expando ] = value; + + // Otherwise secure it in a non-enumerable property + // configurable must be true to allow the property to be + // deleted when data is removed + } else { + Object.defineProperty( owner, this.expando, { + value: value, + configurable: true + } ); + } + } + } + + return value; + }, + set: function( owner, data, value ) { + var prop, + cache = this.cache( owner ); + + // Handle: [ owner, key, value ] args + // Always use camelCase key (gh-2257) + if ( typeof data === "string" ) { + cache[ camelCase( data ) ] = value; + + // Handle: [ owner, { properties } ] args + } else { + + // Copy the properties one-by-one to the cache object + for ( prop in data ) { + cache[ camelCase( prop ) ] = data[ prop ]; + } + } + return cache; + }, + get: function( owner, key ) { + return key === undefined ? + this.cache( owner ) : + + // Always use camelCase key (gh-2257) + owner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ]; + }, + access: function( owner, key, value ) { + + // In cases where either: + // + // 1. No key was specified + // 2. A string key was specified, but no value provided + // + // Take the "read" path and allow the get method to determine + // which value to return, respectively either: + // + // 1. The entire cache object + // 2. The data stored at the key + // + if ( key === undefined || + ( ( key && typeof key === "string" ) && value === undefined ) ) { + + return this.get( owner, key ); + } + + // When the key is not a string, or both a key and value + // are specified, set or extend (existing objects) with either: + // + // 1. An object of properties + // 2. A key and value + // + this.set( owner, key, value ); + + // Since the "set" path can have two possible entry points + // return the expected data based on which path was taken[*] + return value !== undefined ? value : key; + }, + remove: function( owner, key ) { + var i, + cache = owner[ this.expando ]; + + if ( cache === undefined ) { + return; + } + + if ( key !== undefined ) { + + // Support array or space separated string of keys + if ( Array.isArray( key ) ) { + + // If key is an array of keys... + // We always set camelCase keys, so remove that. + key = key.map( camelCase ); + } else { + key = camelCase( key ); + + // If a key with the spaces exists, use it. + // Otherwise, create an array by matching non-whitespace + key = key in cache ? + [ key ] : + ( key.match( rnothtmlwhite ) || [] ); + } + + i = key.length; + + while ( i-- ) { + delete cache[ key[ i ] ]; + } + } + + // Remove the expando if there's no more data + if ( key === undefined || jQuery.isEmptyObject( cache ) ) { + + // Support: Chrome <=35 - 45 + // Webkit & Blink performance suffers when deleting properties + // from DOM nodes, so set to undefined instead + // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) + if ( owner.nodeType ) { + owner[ this.expando ] = undefined; + } else { + delete owner[ this.expando ]; + } + } + }, + hasData: function( owner ) { + var cache = owner[ this.expando ]; + return cache !== undefined && !jQuery.isEmptyObject( cache ); + } +}; +var dataPriv = new Data(); + +var dataUser = new Data(); + + + +// Implementation Summary +// +// 1. Enforce API surface and semantic compatibility with 1.9.x branch +// 2. Improve the module's maintainability by reducing the storage +// paths to a single mechanism. +// 3. Use the same single mechanism to support "private" and "user" data. +// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) +// 5. Avoid exposing implementation details on user objects (eg. expando properties) +// 6. Provide a clear path for implementation upgrade to WeakMap in 2014 + +var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, + rmultiDash = /[A-Z]/g; + +function getData( data ) { + if ( data === "true" ) { + return true; + } + + if ( data === "false" ) { + return false; + } + + if ( data === "null" ) { + return null; + } + + // Only convert to a number if it doesn't change the string + if ( data === +data + "" ) { + return +data; + } + + if ( rbrace.test( data ) ) { + return JSON.parse( data ); + } + + return data; +} + +function dataAttr( elem, key, data ) { + var name; + + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = getData( data ); + } catch ( e ) {} + + // Make sure we set the data so it isn't changed later + dataUser.set( elem, key, data ); + } else { + data = undefined; + } + } + return data; +} + +jQuery.extend( { + hasData: function( elem ) { + return dataUser.hasData( elem ) || dataPriv.hasData( elem ); + }, + + data: function( elem, name, data ) { + return dataUser.access( elem, name, data ); + }, + + removeData: function( elem, name ) { + dataUser.remove( elem, name ); + }, + + // TODO: Now that all calls to _data and _removeData have been replaced + // with direct calls to dataPriv methods, these can be deprecated. + _data: function( elem, name, data ) { + return dataPriv.access( elem, name, data ); + }, + + _removeData: function( elem, name ) { + dataPriv.remove( elem, name ); + } +} ); + +jQuery.fn.extend( { + data: function( key, value ) { + var i, name, data, + elem = this[ 0 ], + attrs = elem && elem.attributes; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = dataUser.get( elem ); + + if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { + i = attrs.length; + while ( i-- ) { + + // Support: IE 11 only + // The attrs elements can be null (#14894) + if ( attrs[ i ] ) { + name = attrs[ i ].name; + if ( name.indexOf( "data-" ) === 0 ) { + name = camelCase( name.slice( 5 ) ); + dataAttr( elem, name, data[ name ] ); + } + } + } + dataPriv.set( elem, "hasDataAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each( function() { + dataUser.set( this, key ); + } ); + } + + return access( this, function( value ) { + var data; + + // The calling jQuery object (element matches) is not empty + // (and therefore has an element appears at this[ 0 ]) and the + // `value` parameter was not undefined. An empty jQuery object + // will result in `undefined` for elem = this[ 0 ] which will + // throw an exception if an attempt to read a data cache is made. + if ( elem && value === undefined ) { + + // Attempt to get data from the cache + // The key will always be camelCased in Data + data = dataUser.get( elem, key ); + if ( data !== undefined ) { + return data; + } + + // Attempt to "discover" the data in + // HTML5 custom data-* attrs + data = dataAttr( elem, key ); + if ( data !== undefined ) { + return data; + } + + // We tried really hard, but the data doesn't exist. + return; + } + + // Set the data... + this.each( function() { + + // We always store the camelCased key + dataUser.set( this, key, value ); + } ); + }, null, value, arguments.length > 1, null, true ); + }, + + removeData: function( key ) { + return this.each( function() { + dataUser.remove( this, key ); + } ); + } +} ); + + +jQuery.extend( { + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = dataPriv.get( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || Array.isArray( data ) ) { + queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // Clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // Not public - generate a queueHooks object, or return the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { + empty: jQuery.Callbacks( "once memory" ).add( function() { + dataPriv.remove( elem, [ type + "queue", key ] ); + } ) + } ); + } +} ); + +jQuery.fn.extend( { + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[ 0 ], type ); + } + + return data === undefined ? + this : + this.each( function() { + var queue = jQuery.queue( this, type, data ); + + // Ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + } ); + }, + dequeue: function( type ) { + return this.each( function() { + jQuery.dequeue( this, type ); + } ); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while ( i-- ) { + tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +} ); +var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; + +var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); + + +var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; + +var documentElement = document.documentElement; + + + + var isAttached = function( elem ) { + return jQuery.contains( elem.ownerDocument, elem ); + }, + composed = { composed: true }; + + // Support: IE 9 - 11+, Edge 12 - 18+, iOS 10.0 - 10.2 only + // Check attachment across shadow DOM boundaries when possible (gh-3504) + // Support: iOS 10.0-10.2 only + // Early iOS 10 versions support `attachShadow` but not `getRootNode`, + // leading to errors. We need to check for `getRootNode`. + if ( documentElement.getRootNode ) { + isAttached = function( elem ) { + return jQuery.contains( elem.ownerDocument, elem ) || + elem.getRootNode( composed ) === elem.ownerDocument; + }; + } +var isHiddenWithinTree = function( elem, el ) { + + // isHiddenWithinTree might be called from jQuery#filter function; + // in that case, element will be second argument + elem = el || elem; + + // Inline style trumps all + return elem.style.display === "none" || + elem.style.display === "" && + + // Otherwise, check computed style + // Support: Firefox <=43 - 45 + // Disconnected elements can have computed display: none, so first confirm that elem is + // in the document. + isAttached( elem ) && + + jQuery.css( elem, "display" ) === "none"; + }; + + + +function adjustCSS( elem, prop, valueParts, tween ) { + var adjusted, scale, + maxIterations = 20, + currentValue = tween ? + function() { + return tween.cur(); + } : + function() { + return jQuery.css( elem, prop, "" ); + }, + initial = currentValue(), + unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), + + // Starting value computation is required for potential unit mismatches + initialInUnit = elem.nodeType && + ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && + rcssNum.exec( jQuery.css( elem, prop ) ); + + if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { + + // Support: Firefox <=54 + // Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144) + initial = initial / 2; + + // Trust units reported by jQuery.css + unit = unit || initialInUnit[ 3 ]; + + // Iteratively approximate from a nonzero starting point + initialInUnit = +initial || 1; + + while ( maxIterations-- ) { + + // Evaluate and update our best guess (doubling guesses that zero out). + // Finish if the scale equals or crosses 1 (making the old*new product non-positive). + jQuery.style( elem, prop, initialInUnit + unit ); + if ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) { + maxIterations = 0; + } + initialInUnit = initialInUnit / scale; + + } + + initialInUnit = initialInUnit * 2; + jQuery.style( elem, prop, initialInUnit + unit ); + + // Make sure we update the tween properties later on + valueParts = valueParts || []; + } + + if ( valueParts ) { + initialInUnit = +initialInUnit || +initial || 0; + + // Apply relative offset (+=/-=) if specified + adjusted = valueParts[ 1 ] ? + initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : + +valueParts[ 2 ]; + if ( tween ) { + tween.unit = unit; + tween.start = initialInUnit; + tween.end = adjusted; + } + } + return adjusted; +} + + +var defaultDisplayMap = {}; + +function getDefaultDisplay( elem ) { + var temp, + doc = elem.ownerDocument, + nodeName = elem.nodeName, + display = defaultDisplayMap[ nodeName ]; + + if ( display ) { + return display; + } + + temp = doc.body.appendChild( doc.createElement( nodeName ) ); + display = jQuery.css( temp, "display" ); + + temp.parentNode.removeChild( temp ); + + if ( display === "none" ) { + display = "block"; + } + defaultDisplayMap[ nodeName ] = display; + + return display; +} + +function showHide( elements, show ) { + var display, elem, + values = [], + index = 0, + length = elements.length; + + // Determine new display value for elements that need to change + for ( ; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + + display = elem.style.display; + if ( show ) { + + // Since we force visibility upon cascade-hidden elements, an immediate (and slow) + // check is required in this first loop unless we have a nonempty display value (either + // inline or about-to-be-restored) + if ( display === "none" ) { + values[ index ] = dataPriv.get( elem, "display" ) || null; + if ( !values[ index ] ) { + elem.style.display = ""; + } + } + if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) { + values[ index ] = getDefaultDisplay( elem ); + } + } else { + if ( display !== "none" ) { + values[ index ] = "none"; + + // Remember what we're overwriting + dataPriv.set( elem, "display", display ); + } + } + } + + // Set the display of the elements in a second loop to avoid constant reflow + for ( index = 0; index < length; index++ ) { + if ( values[ index ] != null ) { + elements[ index ].style.display = values[ index ]; + } + } + + return elements; +} + +jQuery.fn.extend( { + show: function() { + return showHide( this, true ); + }, + hide: function() { + return showHide( this ); + }, + toggle: function( state ) { + if ( typeof state === "boolean" ) { + return state ? this.show() : this.hide(); + } + + return this.each( function() { + if ( isHiddenWithinTree( this ) ) { + jQuery( this ).show(); + } else { + jQuery( this ).hide(); + } + } ); + } +} ); +var rcheckableType = ( /^(?:checkbox|radio)$/i ); + +var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]*)/i ); + +var rscriptType = ( /^$|^module$|\/(?:java|ecma)script/i ); + + + +( function() { + var fragment = document.createDocumentFragment(), + div = fragment.appendChild( document.createElement( "div" ) ), + input = document.createElement( "input" ); + + // Support: Android 4.0 - 4.3 only + // Check state lost if the name is set (#11217) + // Support: Windows Web Apps (WWA) + // `name` and `type` must use .setAttribute for WWA (#14901) + input.setAttribute( "type", "radio" ); + input.setAttribute( "checked", "checked" ); + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + + // Support: Android <=4.1 only + // Older WebKit doesn't clone checked state correctly in fragments + support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE <=11 only + // Make sure textarea (and checkbox) defaultValue is properly cloned + div.innerHTML = ""; + support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; + + // Support: IE <=9 only + // IE <=9 replaces "; + support.option = !!div.lastChild; +} )(); + + +// We have to close these tags to support XHTML (#13200) +var wrapMap = { + + // XHTML parsers do not magically insert elements in the + // same way that tag soup parsers do. So we cannot shorten + // this by omitting or other required elements. + thead: [ 1, "", "
" ], + col: [ 2, "", "
" ], + tr: [ 2, "", "
" ], + td: [ 3, "", "
" ], + + _default: [ 0, "", "" ] +}; + +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +// Support: IE <=9 only +if ( !support.option ) { + wrapMap.optgroup = wrapMap.option = [ 1, "" ]; +} + + +function getAll( context, tag ) { + + // Support: IE <=9 - 11 only + // Use typeof to avoid zero-argument method invocation on host objects (#15151) + var ret; + + if ( typeof context.getElementsByTagName !== "undefined" ) { + ret = context.getElementsByTagName( tag || "*" ); + + } else if ( typeof context.querySelectorAll !== "undefined" ) { + ret = context.querySelectorAll( tag || "*" ); + + } else { + ret = []; + } + + if ( tag === undefined || tag && nodeName( context, tag ) ) { + return jQuery.merge( [ context ], ret ); + } + + return ret; +} + + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + dataPriv.set( + elems[ i ], + "globalEval", + !refElements || dataPriv.get( refElements[ i ], "globalEval" ) + ); + } +} + + +var rhtml = /<|&#?\w+;/; + +function buildFragment( elems, context, scripts, selection, ignored ) { + var elem, tmp, tag, wrap, attached, j, + fragment = context.createDocumentFragment(), + nodes = [], + i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + elem = elems[ i ]; + + if ( elem || elem === 0 ) { + + // Add nodes directly + if ( toType( elem ) === "object" ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); + + // Convert non-html into a text node + } else if ( !rhtml.test( elem ) ) { + nodes.push( context.createTextNode( elem ) ); + + // Convert html into DOM nodes + } else { + tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); + + // Deserialize a standard representation + tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; + + // Descend through wrappers to the right content + j = wrap[ 0 ]; + while ( j-- ) { + tmp = tmp.lastChild; + } + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, tmp.childNodes ); + + // Remember the top-level container + tmp = fragment.firstChild; + + // Ensure the created nodes are orphaned (#12392) + tmp.textContent = ""; + } + } + } + + // Remove wrapper from fragment + fragment.textContent = ""; + + i = 0; + while ( ( elem = nodes[ i++ ] ) ) { + + // Skip elements already in the context collection (trac-4087) + if ( selection && jQuery.inArray( elem, selection ) > -1 ) { + if ( ignored ) { + ignored.push( elem ); + } + continue; + } + + attached = isAttached( elem ); + + // Append to fragment + tmp = getAll( fragment.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( attached ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( ( elem = tmp[ j++ ] ) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + return fragment; +} + + +var + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, + rtypenamespace = /^([^.]*)(?:\.(.+)|)/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +// Support: IE <=9 - 11+ +// focus() and blur() are asynchronous, except when they are no-op. +// So expect focus to be synchronous when the element is already active, +// and blur to be synchronous when the element is not already active. +// (focus and blur are always synchronous in other supported browsers, +// this just defines when we can count on it). +function expectSync( elem, type ) { + return ( elem === safeActiveElement() ) === ( type === "focus" ); +} + +// Support: IE <=9 only +// Accessing document.activeElement can throw unexpectedly +// https://bugs.jquery.com/ticket/13393 +function safeActiveElement() { + try { + return document.activeElement; + } catch ( err ) { } +} + +function on( elem, types, selector, data, fn, one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + on( elem, type, selector, data, types[ type ], one ); + } + return elem; + } + + if ( data == null && fn == null ) { + + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return elem; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return elem.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + } ); +} + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + global: {}, + + add: function( elem, types, handler, data, selector ) { + + var handleObjIn, eventHandle, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.get( elem ); + + // Only attach events to objects that accept data + if ( !acceptData( elem ) ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Ensure that invalid selectors throw exceptions at attach time + // Evaluate against documentElement in case elem is a non-element node (e.g., document) + if ( selector ) { + jQuery.find.matchesSelector( documentElement, selector ); + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + if ( !( events = elemData.events ) ) { + events = elemData.events = Object.create( null ); + } + if ( !( eventHandle = elemData.handle ) ) { + eventHandle = elemData.handle = function( e ) { + + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? + jQuery.event.dispatch.apply( elem, arguments ) : undefined; + }; + } + + // Handle multiple events separated by a space + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // There *must* be a type, no attaching namespace-only handlers + if ( !type ) { + continue; + } + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend( { + type: type, + origType: origType, + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join( "." ) + }, handleObjIn ); + + // Init the event handler queue if we're the first + if ( !( handlers = events[ type ] ) ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener if the special events handler returns false + if ( !special.setup || + special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + }, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + + var j, origCount, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); + + if ( !elemData || !( events = elemData.events ) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector ? special.delegateType : special.bindType ) || type; + handlers = events[ type ] || []; + tmp = tmp[ 2 ] && + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); + + // Remove matching events + origCount = j = handlers.length; + while ( j-- ) { + handleObj = handlers[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !tmp || tmp.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || + selector === "**" && handleObj.selector ) ) { + handlers.splice( j, 1 ); + + if ( handleObj.selector ) { + handlers.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( origCount && !handlers.length ) { + if ( !special.teardown || + special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove data and the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + dataPriv.remove( elem, "handle events" ); + } + }, + + dispatch: function( nativeEvent ) { + + var i, j, ret, matched, handleObj, handlerQueue, + args = new Array( arguments.length ), + + // Make a writable jQuery.Event from the native event object + event = jQuery.event.fix( nativeEvent ), + + handlers = ( + dataPriv.get( this, "events" ) || Object.create( null ) + )[ event.type ] || [], + special = jQuery.event.special[ event.type ] || {}; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[ 0 ] = event; + + for ( i = 1; i < arguments.length; i++ ) { + args[ i ] = arguments[ i ]; + } + + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( ( handleObj = matched.handlers[ j++ ] ) && + !event.isImmediatePropagationStopped() ) { + + // If the event is namespaced, then each handler is only invoked if it is + // specially universal or its namespaces are a superset of the event's. + if ( !event.rnamespace || handleObj.namespace === false || + event.rnamespace.test( handleObj.namespace ) ) { + + event.handleObj = handleObj; + event.data = handleObj.data; + + ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || + handleObj.handler ).apply( matched.elem, args ); + + if ( ret !== undefined ) { + if ( ( event.result = ret ) === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + handlers: function( event, handlers ) { + var i, handleObj, sel, matchedHandlers, matchedSelectors, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Find delegate handlers + if ( delegateCount && + + // Support: IE <=9 + // Black-hole SVG instance trees (trac-13180) + cur.nodeType && + + // Support: Firefox <=42 + // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861) + // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click + // Support: IE 11 only + // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343) + !( event.type === "click" && event.button >= 1 ) ) { + + for ( ; cur !== this; cur = cur.parentNode || this ) { + + // Don't check non-elements (#13208) + // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { + matchedHandlers = []; + matchedSelectors = {}; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (#13203) + sel = handleObj.selector + " "; + + if ( matchedSelectors[ sel ] === undefined ) { + matchedSelectors[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) > -1 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matchedSelectors[ sel ] ) { + matchedHandlers.push( handleObj ); + } + } + if ( matchedHandlers.length ) { + handlerQueue.push( { elem: cur, handlers: matchedHandlers } ); + } + } + } + } + + // Add the remaining (directly-bound) handlers + cur = this; + if ( delegateCount < handlers.length ) { + handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } ); + } + + return handlerQueue; + }, + + addProp: function( name, hook ) { + Object.defineProperty( jQuery.Event.prototype, name, { + enumerable: true, + configurable: true, + + get: isFunction( hook ) ? + function() { + if ( this.originalEvent ) { + return hook( this.originalEvent ); + } + } : + function() { + if ( this.originalEvent ) { + return this.originalEvent[ name ]; + } + }, + + set: function( value ) { + Object.defineProperty( this, name, { + enumerable: true, + configurable: true, + writable: true, + value: value + } ); + } + } ); + }, + + fix: function( originalEvent ) { + return originalEvent[ jQuery.expando ] ? + originalEvent : + new jQuery.Event( originalEvent ); + }, + + special: { + load: { + + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + click: { + + // Utilize native event to ensure correct state for checkable inputs + setup: function( data ) { + + // For mutual compressibility with _default, replace `this` access with a local var. + // `|| data` is dead code meant only to preserve the variable through minification. + var el = this || data; + + // Claim the first handler + if ( rcheckableType.test( el.type ) && + el.click && nodeName( el, "input" ) ) { + + // dataPriv.set( el, "click", ... ) + leverageNative( el, "click", returnTrue ); + } + + // Return false to allow normal processing in the caller + return false; + }, + trigger: function( data ) { + + // For mutual compressibility with _default, replace `this` access with a local var. + // `|| data` is dead code meant only to preserve the variable through minification. + var el = this || data; + + // Force setup before triggering a click + if ( rcheckableType.test( el.type ) && + el.click && nodeName( el, "input" ) ) { + + leverageNative( el, "click" ); + } + + // Return non-false to allow normal event-path propagation + return true; + }, + + // For cross-browser consistency, suppress native .click() on links + // Also prevent it if we're currently inside a leveraged native-event stack + _default: function( event ) { + var target = event.target; + return rcheckableType.test( target.type ) && + target.click && nodeName( target, "input" ) && + dataPriv.get( target, "click" ) || + nodeName( target, "a" ); + } + }, + + beforeunload: { + postDispatch: function( event ) { + + // Support: Firefox 20+ + // Firefox doesn't alert if the returnValue field is not set. + if ( event.result !== undefined && event.originalEvent ) { + event.originalEvent.returnValue = event.result; + } + } + } + } +}; + +// Ensure the presence of an event listener that handles manually-triggered +// synthetic events by interrupting progress until reinvoked in response to +// *native* events that it fires directly, ensuring that state changes have +// already occurred before other listeners are invoked. +function leverageNative( el, type, expectSync ) { + + // Missing expectSync indicates a trigger call, which must force setup through jQuery.event.add + if ( !expectSync ) { + if ( dataPriv.get( el, type ) === undefined ) { + jQuery.event.add( el, type, returnTrue ); + } + return; + } + + // Register the controller as a special universal handler for all event namespaces + dataPriv.set( el, type, false ); + jQuery.event.add( el, type, { + namespace: false, + handler: function( event ) { + var notAsync, result, + saved = dataPriv.get( this, type ); + + if ( ( event.isTrigger & 1 ) && this[ type ] ) { + + // Interrupt processing of the outer synthetic .trigger()ed event + // Saved data should be false in such cases, but might be a leftover capture object + // from an async native handler (gh-4350) + if ( !saved.length ) { + + // Store arguments for use when handling the inner native event + // There will always be at least one argument (an event object), so this array + // will not be confused with a leftover capture object. + saved = slice.call( arguments ); + dataPriv.set( this, type, saved ); + + // Trigger the native event and capture its result + // Support: IE <=9 - 11+ + // focus() and blur() are asynchronous + notAsync = expectSync( this, type ); + this[ type ](); + result = dataPriv.get( this, type ); + if ( saved !== result || notAsync ) { + dataPriv.set( this, type, false ); + } else { + result = {}; + } + if ( saved !== result ) { + + // Cancel the outer synthetic event + event.stopImmediatePropagation(); + event.preventDefault(); + return result.value; + } + + // If this is an inner synthetic event for an event with a bubbling surrogate + // (focus or blur), assume that the surrogate already propagated from triggering the + // native event and prevent that from happening again here. + // This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the + // bubbling surrogate propagates *after* the non-bubbling base), but that seems + // less bad than duplication. + } else if ( ( jQuery.event.special[ type ] || {} ).delegateType ) { + event.stopPropagation(); + } + + // If this is a native event triggered above, everything is now in order + // Fire an inner synthetic event with the original arguments + } else if ( saved.length ) { + + // ...and capture the result + dataPriv.set( this, type, { + value: jQuery.event.trigger( + + // Support: IE <=9 - 11+ + // Extend with the prototype to reset the above stopImmediatePropagation() + jQuery.extend( saved[ 0 ], jQuery.Event.prototype ), + saved.slice( 1 ), + this + ) + } ); + + // Abort handling of the native event + event.stopImmediatePropagation(); + } + } + } ); +} + +jQuery.removeEvent = function( elem, type, handle ) { + + // This "if" is needed for plain objects + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle ); + } +}; + +jQuery.Event = function( src, props ) { + + // Allow instantiation without the 'new' keyword + if ( !( this instanceof jQuery.Event ) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = src.defaultPrevented || + src.defaultPrevented === undefined && + + // Support: Android <=2.3 only + src.returnValue === false ? + returnTrue : + returnFalse; + + // Create target properties + // Support: Safari <=6 - 7 only + // Target should not be a text node (#504, #13143) + this.target = ( src.target && src.target.nodeType === 3 ) ? + src.target.parentNode : + src.target; + + this.currentTarget = src.currentTarget; + this.relatedTarget = src.relatedTarget; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || Date.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + constructor: jQuery.Event, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + isSimulated: false, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + + if ( e && !this.isSimulated ) { + e.preventDefault(); + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopPropagation(); + } + }, + stopImmediatePropagation: function() { + var e = this.originalEvent; + + this.isImmediatePropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopImmediatePropagation(); + } + + this.stopPropagation(); + } +}; + +// Includes all common event props including KeyEvent and MouseEvent specific props +jQuery.each( { + altKey: true, + bubbles: true, + cancelable: true, + changedTouches: true, + ctrlKey: true, + detail: true, + eventPhase: true, + metaKey: true, + pageX: true, + pageY: true, + shiftKey: true, + view: true, + "char": true, + code: true, + charCode: true, + key: true, + keyCode: true, + button: true, + buttons: true, + clientX: true, + clientY: true, + offsetX: true, + offsetY: true, + pointerId: true, + pointerType: true, + screenX: true, + screenY: true, + targetTouches: true, + toElement: true, + touches: true, + + which: function( event ) { + var button = event.button; + + // Add which for key events + if ( event.which == null && rkeyEvent.test( event.type ) ) { + return event.charCode != null ? event.charCode : event.keyCode; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) { + if ( button & 1 ) { + return 1; + } + + if ( button & 2 ) { + return 3; + } + + if ( button & 4 ) { + return 2; + } + + return 0; + } + + return event.which; + } +}, jQuery.event.addProp ); + +jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateType ) { + jQuery.event.special[ type ] = { + + // Utilize native event if possible so blur/focus sequence is correct + setup: function() { + + // Claim the first handler + // dataPriv.set( this, "focus", ... ) + // dataPriv.set( this, "blur", ... ) + leverageNative( this, type, expectSync ); + + // Return false to allow normal processing in the caller + return false; + }, + trigger: function() { + + // Force setup before trigger + leverageNative( this, type ); + + // Return non-false to allow normal event-path propagation + return true; + }, + + delegateType: delegateType + }; +} ); + +// Create mouseenter/leave events using mouseover/out and event-time checks +// so that event delegation works in jQuery. +// Do the same for pointerenter/pointerleave and pointerover/pointerout +// +// Support: Safari 7 only +// Safari sends mouseenter too often; see: +// https://bugs.chromium.org/p/chromium/issues/detail?id=470258 +// for the description of the bug (it existed in older Chrome versions as well). +jQuery.each( { + mouseenter: "mouseover", + mouseleave: "mouseout", + pointerenter: "pointerover", + pointerleave: "pointerout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mouseenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +} ); + +jQuery.fn.extend( { + + on: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn ); + }, + one: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? + handleObj.origType + "." + handleObj.namespace : + handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each( function() { + jQuery.event.remove( this, types, fn, selector ); + } ); + } +} ); + + +var + + // Support: IE <=10 - 11, Edge 12 - 13 only + // In IE/Edge using regex groups here causes severe slowdowns. + // See https://connect.microsoft.com/IE/feedback/details/1736512/ + rnoInnerhtml = /\s*$/g; + +// Prefer a tbody over its parent table for containing new rows +function manipulationTarget( elem, content ) { + if ( nodeName( elem, "table" ) && + nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { + + return jQuery( elem ).children( "tbody" )[ 0 ] || elem; + } + + return elem; +} + +// Replace/restore the type attribute of script elements for safe DOM manipulation +function disableScript( elem ) { + elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; + return elem; +} +function restoreScript( elem ) { + if ( ( elem.type || "" ).slice( 0, 5 ) === "true/" ) { + elem.type = elem.type.slice( 5 ); + } else { + elem.removeAttribute( "type" ); + } + + return elem; +} + +function cloneCopyEvent( src, dest ) { + var i, l, type, pdataOld, udataOld, udataCur, events; + + if ( dest.nodeType !== 1 ) { + return; + } + + // 1. Copy private data: events, handlers, etc. + if ( dataPriv.hasData( src ) ) { + pdataOld = dataPriv.get( src ); + events = pdataOld.events; + + if ( events ) { + dataPriv.remove( dest, "handle events" ); + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + } + + // 2. Copy user data + if ( dataUser.hasData( src ) ) { + udataOld = dataUser.access( src ); + udataCur = jQuery.extend( {}, udataOld ); + + dataUser.set( dest, udataCur ); + } +} + +// Fix IE bugs, see support tests +function fixInput( src, dest ) { + var nodeName = dest.nodeName.toLowerCase(); + + // Fails to persist the checked state of a cloned checkbox or radio button. + if ( nodeName === "input" && rcheckableType.test( src.type ) ) { + dest.checked = src.checked; + + // Fails to return the selected option to the default selected state when cloning options + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +function domManip( collection, args, callback, ignored ) { + + // Flatten any nested arrays + args = flat( args ); + + var fragment, first, scripts, hasScripts, node, doc, + i = 0, + l = collection.length, + iNoClone = l - 1, + value = args[ 0 ], + valueIsFunction = isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( valueIsFunction || + ( l > 1 && typeof value === "string" && + !support.checkClone && rchecked.test( value ) ) ) { + return collection.each( function( index ) { + var self = collection.eq( index ); + if ( valueIsFunction ) { + args[ 0 ] = value.call( this, index, self.html() ); + } + domManip( self, args, callback, ignored ); + } ); + } + + if ( l ) { + fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + // Require either new content or an interest in ignored elements to invoke the callback + if ( first || ignored ) { + scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); + hasScripts = scripts.length; + + // Use the original fragment for the last item + // instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( collection[ i ], node, i ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Reenable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !dataPriv.access( node, "globalEval" ) && + jQuery.contains( doc, node ) ) { + + if ( node.src && ( node.type || "" ).toLowerCase() !== "module" ) { + + // Optional AJAX dependency, but won't run scripts if not present + if ( jQuery._evalUrl && !node.noModule ) { + jQuery._evalUrl( node.src, { + nonce: node.nonce || node.getAttribute( "nonce" ) + }, doc ); + } + } else { + DOMEval( node.textContent.replace( rcleanScript, "" ), node, doc ); + } + } + } + } + } + } + + return collection; +} + +function remove( elem, selector, keepData ) { + var node, + nodes = selector ? jQuery.filter( selector, elem ) : elem, + i = 0; + + for ( ; ( node = nodes[ i ] ) != null; i++ ) { + if ( !keepData && node.nodeType === 1 ) { + jQuery.cleanData( getAll( node ) ); + } + + if ( node.parentNode ) { + if ( keepData && isAttached( node ) ) { + setGlobalEval( getAll( node, "script" ) ); + } + node.parentNode.removeChild( node ); + } + } + + return elem; +} + +jQuery.extend( { + htmlPrefilter: function( html ) { + return html; + }, + + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var i, l, srcElements, destElements, + clone = elem.cloneNode( true ), + inPage = isAttached( elem ); + + // Fix IE cloning issues + if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && + !jQuery.isXMLDoc( elem ) ) { + + // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + fixInput( srcElements[ i ], destElements[ i ] ); + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + cloneCopyEvent( srcElements[ i ], destElements[ i ] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + // Return the cloned set + return clone; + }, + + cleanData: function( elems ) { + var data, elem, type, + special = jQuery.event.special, + i = 0; + + for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { + if ( acceptData( elem ) ) { + if ( ( data = elem[ dataPriv.expando ] ) ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataPriv.expando ] = undefined; + } + if ( elem[ dataUser.expando ] ) { + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataUser.expando ] = undefined; + } + } + } + } +} ); + +jQuery.fn.extend( { + detach: function( selector ) { + return remove( this, selector, true ); + }, + + remove: function( selector ) { + return remove( this, selector ); + }, + + text: function( value ) { + return access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().each( function() { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + this.textContent = value; + } + } ); + }, null, value, arguments.length ); + }, + + append: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.appendChild( elem ); + } + } ); + }, + + prepend: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.insertBefore( elem, target.firstChild ); + } + } ); + }, + + before: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + } ); + }, + + after: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + } ); + }, + + empty: function() { + var elem, + i = 0; + + for ( ; ( elem = this[ i ] ) != null; i++ ) { + if ( elem.nodeType === 1 ) { + + // Prevent memory leaks + jQuery.cleanData( getAll( elem, false ) ); + + // Remove any remaining nodes + elem.textContent = ""; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map( function() { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + } ); + }, + + html: function( value ) { + return access( this, function( value ) { + var elem = this[ 0 ] || {}, + i = 0, + l = this.length; + + if ( value === undefined && elem.nodeType === 1 ) { + return elem.innerHTML; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { + + value = jQuery.htmlPrefilter( value ); + + try { + for ( ; i < l; i++ ) { + elem = this[ i ] || {}; + + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch ( e ) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function() { + var ignored = []; + + // Make the changes, replacing each non-ignored context element with the new content + return domManip( this, arguments, function( elem ) { + var parent = this.parentNode; + + if ( jQuery.inArray( this, ignored ) < 0 ) { + jQuery.cleanData( getAll( this ) ); + if ( parent ) { + parent.replaceChild( elem, this ); + } + } + + // Force callback invocation + }, ignored ); + } +} ); + +jQuery.each( { + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1, + i = 0; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone( true ); + jQuery( insert[ i ] )[ original ]( elems ); + + // Support: Android <=4.0 only, PhantomJS 1 only + // .get() because push.apply(_, arraylike) throws on ancient WebKit + push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +} ); +var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); + +var getStyles = function( elem ) { + + // Support: IE <=11 only, Firefox <=30 (#15098, #14150) + // IE throws on elements created in popups + // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" + var view = elem.ownerDocument.defaultView; + + if ( !view || !view.opener ) { + view = window; + } + + return view.getComputedStyle( elem ); + }; + +var swap = function( elem, options, callback ) { + var ret, name, + old = {}; + + // Remember the old values, and insert the new ones + for ( name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + ret = callback.call( elem ); + + // Revert the old values + for ( name in options ) { + elem.style[ name ] = old[ name ]; + } + + return ret; +}; + + +var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" ); + + + +( function() { + + // Executing both pixelPosition & boxSizingReliable tests require only one layout + // so they're executed at the same time to save the second computation. + function computeStyleTests() { + + // This is a singleton, we need to execute it only once + if ( !div ) { + return; + } + + container.style.cssText = "position:absolute;left:-11111px;width:60px;" + + "margin-top:1px;padding:0;border:0"; + div.style.cssText = + "position:relative;display:block;box-sizing:border-box;overflow:scroll;" + + "margin:auto;border:1px;padding:1px;" + + "width:60%;top:1%"; + documentElement.appendChild( container ).appendChild( div ); + + var divStyle = window.getComputedStyle( div ); + pixelPositionVal = divStyle.top !== "1%"; + + // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 + reliableMarginLeftVal = roundPixelMeasures( divStyle.marginLeft ) === 12; + + // Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3 + // Some styles come back with percentage values, even though they shouldn't + div.style.right = "60%"; + pixelBoxStylesVal = roundPixelMeasures( divStyle.right ) === 36; + + // Support: IE 9 - 11 only + // Detect misreporting of content dimensions for box-sizing:border-box elements + boxSizingReliableVal = roundPixelMeasures( divStyle.width ) === 36; + + // Support: IE 9 only + // Detect overflow:scroll screwiness (gh-3699) + // Support: Chrome <=64 + // Don't get tricked when zoom affects offsetWidth (gh-4029) + div.style.position = "absolute"; + scrollboxSizeVal = roundPixelMeasures( div.offsetWidth / 3 ) === 12; + + documentElement.removeChild( container ); + + // Nullify the div so it wouldn't be stored in the memory and + // it will also be a sign that checks already performed + div = null; + } + + function roundPixelMeasures( measure ) { + return Math.round( parseFloat( measure ) ); + } + + var pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal, + reliableTrDimensionsVal, reliableMarginLeftVal, + container = document.createElement( "div" ), + div = document.createElement( "div" ); + + // Finish early in limited (non-browser) environments + if ( !div.style ) { + return; + } + + // Support: IE <=9 - 11 only + // Style of cloned element affects source element cloned (#8908) + div.style.backgroundClip = "content-box"; + div.cloneNode( true ).style.backgroundClip = ""; + support.clearCloneStyle = div.style.backgroundClip === "content-box"; + + jQuery.extend( support, { + boxSizingReliable: function() { + computeStyleTests(); + return boxSizingReliableVal; + }, + pixelBoxStyles: function() { + computeStyleTests(); + return pixelBoxStylesVal; + }, + pixelPosition: function() { + computeStyleTests(); + return pixelPositionVal; + }, + reliableMarginLeft: function() { + computeStyleTests(); + return reliableMarginLeftVal; + }, + scrollboxSize: function() { + computeStyleTests(); + return scrollboxSizeVal; + }, + + // Support: IE 9 - 11+, Edge 15 - 18+ + // IE/Edge misreport `getComputedStyle` of table rows with width/height + // set in CSS while `offset*` properties report correct values. + // Behavior in IE 9 is more subtle than in newer versions & it passes + // some versions of this test; make sure not to make it pass there! + reliableTrDimensions: function() { + var table, tr, trChild, trStyle; + if ( reliableTrDimensionsVal == null ) { + table = document.createElement( "table" ); + tr = document.createElement( "tr" ); + trChild = document.createElement( "div" ); + + table.style.cssText = "position:absolute;left:-11111px"; + tr.style.height = "1px"; + trChild.style.height = "9px"; + + documentElement + .appendChild( table ) + .appendChild( tr ) + .appendChild( trChild ); + + trStyle = window.getComputedStyle( tr ); + reliableTrDimensionsVal = parseInt( trStyle.height ) > 3; + + documentElement.removeChild( table ); + } + return reliableTrDimensionsVal; + } + } ); +} )(); + + +function curCSS( elem, name, computed ) { + var width, minWidth, maxWidth, ret, + + // Support: Firefox 51+ + // Retrieving style before computed somehow + // fixes an issue with getting wrong values + // on detached elements + style = elem.style; + + computed = computed || getStyles( elem ); + + // getPropertyValue is needed for: + // .css('filter') (IE 9 only, #12537) + // .css('--customProperty) (#3144) + if ( computed ) { + ret = computed.getPropertyValue( name ) || computed[ name ]; + + if ( ret === "" && !isAttached( elem ) ) { + ret = jQuery.style( elem, name ); + } + + // A tribute to the "awesome hack by Dean Edwards" + // Android Browser returns percentage for some values, + // but width seems to be reliably pixels. + // This is against the CSSOM draft spec: + // https://drafts.csswg.org/cssom/#resolved-values + if ( !support.pixelBoxStyles() && rnumnonpx.test( ret ) && rboxStyle.test( name ) ) { + + // Remember the original values + width = style.width; + minWidth = style.minWidth; + maxWidth = style.maxWidth; + + // Put in the new values to get a computed value out + style.minWidth = style.maxWidth = style.width = ret; + ret = computed.width; + + // Revert the changed values + style.width = width; + style.minWidth = minWidth; + style.maxWidth = maxWidth; + } + } + + return ret !== undefined ? + + // Support: IE <=9 - 11 only + // IE returns zIndex value as an integer. + ret + "" : + ret; +} + + +function addGetHookIf( conditionFn, hookFn ) { + + // Define the hook, we'll check on the first run if it's really needed. + return { + get: function() { + if ( conditionFn() ) { + + // Hook not needed (or it's not possible to use it due + // to missing dependency), remove it. + delete this.get; + return; + } + + // Hook needed; redefine it so that the support test is not executed again. + return ( this.get = hookFn ).apply( this, arguments ); + } + }; +} + + +var cssPrefixes = [ "Webkit", "Moz", "ms" ], + emptyStyle = document.createElement( "div" ).style, + vendorProps = {}; + +// Return a vendor-prefixed property or undefined +function vendorPropName( name ) { + + // Check for vendor prefixed names + var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), + i = cssPrefixes.length; + + while ( i-- ) { + name = cssPrefixes[ i ] + capName; + if ( name in emptyStyle ) { + return name; + } + } +} + +// Return a potentially-mapped jQuery.cssProps or vendor prefixed property +function finalPropName( name ) { + var final = jQuery.cssProps[ name ] || vendorProps[ name ]; + + if ( final ) { + return final; + } + if ( name in emptyStyle ) { + return name; + } + return vendorProps[ name ] = vendorPropName( name ) || name; +} + + +var + + // Swappable if display is none or starts with table + // except "table", "table-cell", or "table-caption" + // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display + rdisplayswap = /^(none|table(?!-c[ea]).+)/, + rcustomProp = /^--/, + cssShow = { position: "absolute", visibility: "hidden", display: "block" }, + cssNormalTransform = { + letterSpacing: "0", + fontWeight: "400" + }; + +function setPositiveNumber( _elem, value, subtract ) { + + // Any relative (+/-) values have already been + // normalized at this point + var matches = rcssNum.exec( value ); + return matches ? + + // Guard against undefined "subtract", e.g., when used as in cssHooks + Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : + value; +} + +function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) { + var i = dimension === "width" ? 1 : 0, + extra = 0, + delta = 0; + + // Adjustment may not be necessary + if ( box === ( isBorderBox ? "border" : "content" ) ) { + return 0; + } + + for ( ; i < 4; i += 2 ) { + + // Both box models exclude margin + if ( box === "margin" ) { + delta += jQuery.css( elem, box + cssExpand[ i ], true, styles ); + } + + // If we get here with a content-box, we're seeking "padding" or "border" or "margin" + if ( !isBorderBox ) { + + // Add padding + delta += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + + // For "border" or "margin", add border + if ( box !== "padding" ) { + delta += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + + // But still keep track of it otherwise + } else { + extra += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + + // If we get here with a border-box (content + padding + border), we're seeking "content" or + // "padding" or "margin" + } else { + + // For "content", subtract padding + if ( box === "content" ) { + delta -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + } + + // For "content" or "padding", subtract border + if ( box !== "margin" ) { + delta -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } + } + + // Account for positive content-box scroll gutter when requested by providing computedVal + if ( !isBorderBox && computedVal >= 0 ) { + + // offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border + // Assuming integer scroll gutter, subtract the rest and round down + delta += Math.max( 0, Math.ceil( + elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - + computedVal - + delta - + extra - + 0.5 + + // If offsetWidth/offsetHeight is unknown, then we can't determine content-box scroll gutter + // Use an explicit zero to avoid NaN (gh-3964) + ) ) || 0; + } + + return delta; +} + +function getWidthOrHeight( elem, dimension, extra ) { + + // Start with computed style + var styles = getStyles( elem ), + + // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-4322). + // Fake content-box until we know it's needed to know the true value. + boxSizingNeeded = !support.boxSizingReliable() || extra, + isBorderBox = boxSizingNeeded && + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + valueIsBorderBox = isBorderBox, + + val = curCSS( elem, dimension, styles ), + offsetProp = "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ); + + // Support: Firefox <=54 + // Return a confounding non-pixel value or feign ignorance, as appropriate. + if ( rnumnonpx.test( val ) ) { + if ( !extra ) { + return val; + } + val = "auto"; + } + + + // Support: IE 9 - 11 only + // Use offsetWidth/offsetHeight for when box sizing is unreliable. + // In those cases, the computed value can be trusted to be border-box. + if ( ( !support.boxSizingReliable() && isBorderBox || + + // Support: IE 10 - 11+, Edge 15 - 18+ + // IE/Edge misreport `getComputedStyle` of table rows with width/height + // set in CSS while `offset*` properties report correct values. + // Interestingly, in some cases IE 9 doesn't suffer from this issue. + !support.reliableTrDimensions() && nodeName( elem, "tr" ) || + + // Fall back to offsetWidth/offsetHeight when value is "auto" + // This happens for inline elements with no explicit setting (gh-3571) + val === "auto" || + + // Support: Android <=4.1 - 4.3 only + // Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602) + !parseFloat( val ) && jQuery.css( elem, "display", false, styles ) === "inline" ) && + + // Make sure the element is visible & connected + elem.getClientRects().length ) { + + isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; + + // Where available, offsetWidth/offsetHeight approximate border box dimensions. + // Where not available (e.g., SVG), assume unreliable box-sizing and interpret the + // retrieved value as a content box dimension. + valueIsBorderBox = offsetProp in elem; + if ( valueIsBorderBox ) { + val = elem[ offsetProp ]; + } + } + + // Normalize "" and auto + val = parseFloat( val ) || 0; + + // Adjust for the element's box model + return ( val + + boxModelAdjustment( + elem, + dimension, + extra || ( isBorderBox ? "border" : "content" ), + valueIsBorderBox, + styles, + + // Provide the current computed size to request scroll gutter calculation (gh-3589) + val + ) + ) + "px"; +} + +jQuery.extend( { + + // Add in style property hooks for overriding the default + // behavior of getting and setting a style property + cssHooks: { + opacity: { + get: function( elem, computed ) { + if ( computed ) { + + // We should always get a number back from opacity + var ret = curCSS( elem, "opacity" ); + return ret === "" ? "1" : ret; + } + } + } + }, + + // Don't automatically add "px" to these possibly-unitless properties + cssNumber: { + "animationIterationCount": true, + "columnCount": true, + "fillOpacity": true, + "flexGrow": true, + "flexShrink": true, + "fontWeight": true, + "gridArea": true, + "gridColumn": true, + "gridColumnEnd": true, + "gridColumnStart": true, + "gridRow": true, + "gridRowEnd": true, + "gridRowStart": true, + "lineHeight": true, + "opacity": true, + "order": true, + "orphans": true, + "widows": true, + "zIndex": true, + "zoom": true + }, + + // Add in properties whose names you wish to fix before + // setting or getting the value + cssProps: {}, + + // Get and set the style property on a DOM Node + style: function( elem, name, value, extra ) { + + // Don't set styles on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { + return; + } + + // Make sure that we're working with the right name + var ret, type, hooks, + origName = camelCase( name ), + isCustomProp = rcustomProp.test( name ), + style = elem.style; + + // Make sure that we're working with the right name. We don't + // want to query the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Gets hook for the prefixed version, then unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // Check if we're setting a value + if ( value !== undefined ) { + type = typeof value; + + // Convert "+=" or "-=" to relative numbers (#7345) + if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { + value = adjustCSS( elem, name, ret ); + + // Fixes bug #9237 + type = "number"; + } + + // Make sure that null and NaN values aren't set (#7116) + if ( value == null || value !== value ) { + return; + } + + // If a number was passed in, add the unit (except for certain CSS properties) + // The isCustomProp check can be removed in jQuery 4.0 when we only auto-append + // "px" to a few hardcoded values. + if ( type === "number" && !isCustomProp ) { + value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); + } + + // background-* props affect original clone's values + if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { + style[ name ] = "inherit"; + } + + // If a hook was provided, use that value, otherwise just set the specified value + if ( !hooks || !( "set" in hooks ) || + ( value = hooks.set( elem, value, extra ) ) !== undefined ) { + + if ( isCustomProp ) { + style.setProperty( name, value ); + } else { + style[ name ] = value; + } + } + + } else { + + // If a hook was provided get the non-computed value from there + if ( hooks && "get" in hooks && + ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { + + return ret; + } + + // Otherwise just get the value from the style object + return style[ name ]; + } + }, + + css: function( elem, name, extra, styles ) { + var val, num, hooks, + origName = camelCase( name ), + isCustomProp = rcustomProp.test( name ); + + // Make sure that we're working with the right name. We don't + // want to modify the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Try prefixed name followed by the unprefixed name + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // If a hook was provided get the computed value from there + if ( hooks && "get" in hooks ) { + val = hooks.get( elem, true, extra ); + } + + // Otherwise, if a way to get the computed value exists, use that + if ( val === undefined ) { + val = curCSS( elem, name, styles ); + } + + // Convert "normal" to computed value + if ( val === "normal" && name in cssNormalTransform ) { + val = cssNormalTransform[ name ]; + } + + // Make numeric if forced or a qualifier was provided and val looks numeric + if ( extra === "" || extra ) { + num = parseFloat( val ); + return extra === true || isFinite( num ) ? num || 0 : val; + } + + return val; + } +} ); + +jQuery.each( [ "height", "width" ], function( _i, dimension ) { + jQuery.cssHooks[ dimension ] = { + get: function( elem, computed, extra ) { + if ( computed ) { + + // Certain elements can have dimension info if we invisibly show them + // but it must have a current display style that would benefit + return rdisplayswap.test( jQuery.css( elem, "display" ) ) && + + // Support: Safari 8+ + // Table columns in Safari have non-zero offsetWidth & zero + // getBoundingClientRect().width unless display is changed. + // Support: IE <=11 only + // Running getBoundingClientRect on a disconnected node + // in IE throws an error. + ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? + swap( elem, cssShow, function() { + return getWidthOrHeight( elem, dimension, extra ); + } ) : + getWidthOrHeight( elem, dimension, extra ); + } + }, + + set: function( elem, value, extra ) { + var matches, + styles = getStyles( elem ), + + // Only read styles.position if the test has a chance to fail + // to avoid forcing a reflow. + scrollboxSizeBuggy = !support.scrollboxSize() && + styles.position === "absolute", + + // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-3991) + boxSizingNeeded = scrollboxSizeBuggy || extra, + isBorderBox = boxSizingNeeded && + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + subtract = extra ? + boxModelAdjustment( + elem, + dimension, + extra, + isBorderBox, + styles + ) : + 0; + + // Account for unreliable border-box dimensions by comparing offset* to computed and + // faking a content-box to get border and padding (gh-3699) + if ( isBorderBox && scrollboxSizeBuggy ) { + subtract -= Math.ceil( + elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - + parseFloat( styles[ dimension ] ) - + boxModelAdjustment( elem, dimension, "border", false, styles ) - + 0.5 + ); + } + + // Convert to pixels if value adjustment is needed + if ( subtract && ( matches = rcssNum.exec( value ) ) && + ( matches[ 3 ] || "px" ) !== "px" ) { + + elem.style[ dimension ] = value; + value = jQuery.css( elem, dimension ); + } + + return setPositiveNumber( elem, value, subtract ); + } + }; +} ); + +jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, + function( elem, computed ) { + if ( computed ) { + return ( parseFloat( curCSS( elem, "marginLeft" ) ) || + elem.getBoundingClientRect().left - + swap( elem, { marginLeft: 0 }, function() { + return elem.getBoundingClientRect().left; + } ) + ) + "px"; + } + } +); + +// These hooks are used by animate to expand properties +jQuery.each( { + margin: "", + padding: "", + border: "Width" +}, function( prefix, suffix ) { + jQuery.cssHooks[ prefix + suffix ] = { + expand: function( value ) { + var i = 0, + expanded = {}, + + // Assumes a single number if not a string + parts = typeof value === "string" ? value.split( " " ) : [ value ]; + + for ( ; i < 4; i++ ) { + expanded[ prefix + cssExpand[ i ] + suffix ] = + parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; + } + + return expanded; + } + }; + + if ( prefix !== "margin" ) { + jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; + } +} ); + +jQuery.fn.extend( { + css: function( name, value ) { + return access( this, function( elem, name, value ) { + var styles, len, + map = {}, + i = 0; + + if ( Array.isArray( name ) ) { + styles = getStyles( elem ); + len = name.length; + + for ( ; i < len; i++ ) { + map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); + } + + return map; + } + + return value !== undefined ? + jQuery.style( elem, name, value ) : + jQuery.css( elem, name ); + }, name, value, arguments.length > 1 ); + } +} ); + + +function Tween( elem, options, prop, end, easing ) { + return new Tween.prototype.init( elem, options, prop, end, easing ); +} +jQuery.Tween = Tween; + +Tween.prototype = { + constructor: Tween, + init: function( elem, options, prop, end, easing, unit ) { + this.elem = elem; + this.prop = prop; + this.easing = easing || jQuery.easing._default; + this.options = options; + this.start = this.now = this.cur(); + this.end = end; + this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); + }, + cur: function() { + var hooks = Tween.propHooks[ this.prop ]; + + return hooks && hooks.get ? + hooks.get( this ) : + Tween.propHooks._default.get( this ); + }, + run: function( percent ) { + var eased, + hooks = Tween.propHooks[ this.prop ]; + + if ( this.options.duration ) { + this.pos = eased = jQuery.easing[ this.easing ]( + percent, this.options.duration * percent, 0, 1, this.options.duration + ); + } else { + this.pos = eased = percent; + } + this.now = ( this.end - this.start ) * eased + this.start; + + if ( this.options.step ) { + this.options.step.call( this.elem, this.now, this ); + } + + if ( hooks && hooks.set ) { + hooks.set( this ); + } else { + Tween.propHooks._default.set( this ); + } + return this; + } +}; + +Tween.prototype.init.prototype = Tween.prototype; + +Tween.propHooks = { + _default: { + get: function( tween ) { + var result; + + // Use a property on the element directly when it is not a DOM element, + // or when there is no matching style property that exists. + if ( tween.elem.nodeType !== 1 || + tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { + return tween.elem[ tween.prop ]; + } + + // Passing an empty string as a 3rd parameter to .css will automatically + // attempt a parseFloat and fallback to a string if the parse fails. + // Simple values such as "10px" are parsed to Float; + // complex values such as "rotate(1rad)" are returned as-is. + result = jQuery.css( tween.elem, tween.prop, "" ); + + // Empty strings, null, undefined and "auto" are converted to 0. + return !result || result === "auto" ? 0 : result; + }, + set: function( tween ) { + + // Use step hook for back compat. + // Use cssHook if its there. + // Use .style if available and use plain properties where available. + if ( jQuery.fx.step[ tween.prop ] ) { + jQuery.fx.step[ tween.prop ]( tween ); + } else if ( tween.elem.nodeType === 1 && ( + jQuery.cssHooks[ tween.prop ] || + tween.elem.style[ finalPropName( tween.prop ) ] != null ) ) { + jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); + } else { + tween.elem[ tween.prop ] = tween.now; + } + } + } +}; + +// Support: IE <=9 only +// Panic based approach to setting things on disconnected nodes +Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { + set: function( tween ) { + if ( tween.elem.nodeType && tween.elem.parentNode ) { + tween.elem[ tween.prop ] = tween.now; + } + } +}; + +jQuery.easing = { + linear: function( p ) { + return p; + }, + swing: function( p ) { + return 0.5 - Math.cos( p * Math.PI ) / 2; + }, + _default: "swing" +}; + +jQuery.fx = Tween.prototype.init; + +// Back compat <1.8 extension point +jQuery.fx.step = {}; + + + + +var + fxNow, inProgress, + rfxtypes = /^(?:toggle|show|hide)$/, + rrun = /queueHooks$/; + +function schedule() { + if ( inProgress ) { + if ( document.hidden === false && window.requestAnimationFrame ) { + window.requestAnimationFrame( schedule ); + } else { + window.setTimeout( schedule, jQuery.fx.interval ); + } + + jQuery.fx.tick(); + } +} + +// Animations created synchronously will run synchronously +function createFxNow() { + window.setTimeout( function() { + fxNow = undefined; + } ); + return ( fxNow = Date.now() ); +} + +// Generate parameters to create a standard animation +function genFx( type, includeWidth ) { + var which, + i = 0, + attrs = { height: type }; + + // If we include width, step value is 1 to do all cssExpand values, + // otherwise step value is 2 to skip over Left and Right + includeWidth = includeWidth ? 1 : 0; + for ( ; i < 4; i += 2 - includeWidth ) { + which = cssExpand[ i ]; + attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; + } + + if ( includeWidth ) { + attrs.opacity = attrs.width = type; + } + + return attrs; +} + +function createTween( value, prop, animation ) { + var tween, + collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), + index = 0, + length = collection.length; + for ( ; index < length; index++ ) { + if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) { + + // We're done with this property + return tween; + } + } +} + +function defaultPrefilter( elem, props, opts ) { + var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, + isBox = "width" in props || "height" in props, + anim = this, + orig = {}, + style = elem.style, + hidden = elem.nodeType && isHiddenWithinTree( elem ), + dataShow = dataPriv.get( elem, "fxshow" ); + + // Queue-skipping animations hijack the fx hooks + if ( !opts.queue ) { + hooks = jQuery._queueHooks( elem, "fx" ); + if ( hooks.unqueued == null ) { + hooks.unqueued = 0; + oldfire = hooks.empty.fire; + hooks.empty.fire = function() { + if ( !hooks.unqueued ) { + oldfire(); + } + }; + } + hooks.unqueued++; + + anim.always( function() { + + // Ensure the complete handler is called before this completes + anim.always( function() { + hooks.unqueued--; + if ( !jQuery.queue( elem, "fx" ).length ) { + hooks.empty.fire(); + } + } ); + } ); + } + + // Detect show/hide animations + for ( prop in props ) { + value = props[ prop ]; + if ( rfxtypes.test( value ) ) { + delete props[ prop ]; + toggle = toggle || value === "toggle"; + if ( value === ( hidden ? "hide" : "show" ) ) { + + // Pretend to be hidden if this is a "show" and + // there is still data from a stopped show/hide + if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { + hidden = true; + + // Ignore all other no-op show/hide data + } else { + continue; + } + } + orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); + } + } + + // Bail out if this is a no-op like .hide().hide() + propTween = !jQuery.isEmptyObject( props ); + if ( !propTween && jQuery.isEmptyObject( orig ) ) { + return; + } + + // Restrict "overflow" and "display" styles during box animations + if ( isBox && elem.nodeType === 1 ) { + + // Support: IE <=9 - 11, Edge 12 - 15 + // Record all 3 overflow attributes because IE does not infer the shorthand + // from identically-valued overflowX and overflowY and Edge just mirrors + // the overflowX value there. + opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; + + // Identify a display type, preferring old show/hide data over the CSS cascade + restoreDisplay = dataShow && dataShow.display; + if ( restoreDisplay == null ) { + restoreDisplay = dataPriv.get( elem, "display" ); + } + display = jQuery.css( elem, "display" ); + if ( display === "none" ) { + if ( restoreDisplay ) { + display = restoreDisplay; + } else { + + // Get nonempty value(s) by temporarily forcing visibility + showHide( [ elem ], true ); + restoreDisplay = elem.style.display || restoreDisplay; + display = jQuery.css( elem, "display" ); + showHide( [ elem ] ); + } + } + + // Animate inline elements as inline-block + if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) { + if ( jQuery.css( elem, "float" ) === "none" ) { + + // Restore the original display value at the end of pure show/hide animations + if ( !propTween ) { + anim.done( function() { + style.display = restoreDisplay; + } ); + if ( restoreDisplay == null ) { + display = style.display; + restoreDisplay = display === "none" ? "" : display; + } + } + style.display = "inline-block"; + } + } + } + + if ( opts.overflow ) { + style.overflow = "hidden"; + anim.always( function() { + style.overflow = opts.overflow[ 0 ]; + style.overflowX = opts.overflow[ 1 ]; + style.overflowY = opts.overflow[ 2 ]; + } ); + } + + // Implement show/hide animations + propTween = false; + for ( prop in orig ) { + + // General show/hide setup for this element animation + if ( !propTween ) { + if ( dataShow ) { + if ( "hidden" in dataShow ) { + hidden = dataShow.hidden; + } + } else { + dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } ); + } + + // Store hidden/visible for toggle so `.stop().toggle()` "reverses" + if ( toggle ) { + dataShow.hidden = !hidden; + } + + // Show elements before animating them + if ( hidden ) { + showHide( [ elem ], true ); + } + + /* eslint-disable no-loop-func */ + + anim.done( function() { + + /* eslint-enable no-loop-func */ + + // The final step of a "hide" animation is actually hiding the element + if ( !hidden ) { + showHide( [ elem ] ); + } + dataPriv.remove( elem, "fxshow" ); + for ( prop in orig ) { + jQuery.style( elem, prop, orig[ prop ] ); + } + } ); + } + + // Per-property setup + propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); + if ( !( prop in dataShow ) ) { + dataShow[ prop ] = propTween.start; + if ( hidden ) { + propTween.end = propTween.start; + propTween.start = 0; + } + } + } +} + +function propFilter( props, specialEasing ) { + var index, name, easing, value, hooks; + + // camelCase, specialEasing and expand cssHook pass + for ( index in props ) { + name = camelCase( index ); + easing = specialEasing[ name ]; + value = props[ index ]; + if ( Array.isArray( value ) ) { + easing = value[ 1 ]; + value = props[ index ] = value[ 0 ]; + } + + if ( index !== name ) { + props[ name ] = value; + delete props[ index ]; + } + + hooks = jQuery.cssHooks[ name ]; + if ( hooks && "expand" in hooks ) { + value = hooks.expand( value ); + delete props[ name ]; + + // Not quite $.extend, this won't overwrite existing keys. + // Reusing 'index' because we have the correct "name" + for ( index in value ) { + if ( !( index in props ) ) { + props[ index ] = value[ index ]; + specialEasing[ index ] = easing; + } + } + } else { + specialEasing[ name ] = easing; + } + } +} + +function Animation( elem, properties, options ) { + var result, + stopped, + index = 0, + length = Animation.prefilters.length, + deferred = jQuery.Deferred().always( function() { + + // Don't match elem in the :animated selector + delete tick.elem; + } ), + tick = function() { + if ( stopped ) { + return false; + } + var currentTime = fxNow || createFxNow(), + remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), + + // Support: Android 2.3 only + // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497) + temp = remaining / animation.duration || 0, + percent = 1 - temp, + index = 0, + length = animation.tweens.length; + + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( percent ); + } + + deferred.notifyWith( elem, [ animation, percent, remaining ] ); + + // If there's more to do, yield + if ( percent < 1 && length ) { + return remaining; + } + + // If this was an empty animation, synthesize a final progress notification + if ( !length ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + } + + // Resolve the animation and report its conclusion + deferred.resolveWith( elem, [ animation ] ); + return false; + }, + animation = deferred.promise( { + elem: elem, + props: jQuery.extend( {}, properties ), + opts: jQuery.extend( true, { + specialEasing: {}, + easing: jQuery.easing._default + }, options ), + originalProperties: properties, + originalOptions: options, + startTime: fxNow || createFxNow(), + duration: options.duration, + tweens: [], + createTween: function( prop, end ) { + var tween = jQuery.Tween( elem, animation.opts, prop, end, + animation.opts.specialEasing[ prop ] || animation.opts.easing ); + animation.tweens.push( tween ); + return tween; + }, + stop: function( gotoEnd ) { + var index = 0, + + // If we are going to the end, we want to run all the tweens + // otherwise we skip this part + length = gotoEnd ? animation.tweens.length : 0; + if ( stopped ) { + return this; + } + stopped = true; + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( 1 ); + } + + // Resolve when we played the last frame; otherwise, reject + if ( gotoEnd ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + deferred.resolveWith( elem, [ animation, gotoEnd ] ); + } else { + deferred.rejectWith( elem, [ animation, gotoEnd ] ); + } + return this; + } + } ), + props = animation.props; + + propFilter( props, animation.opts.specialEasing ); + + for ( ; index < length; index++ ) { + result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); + if ( result ) { + if ( isFunction( result.stop ) ) { + jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = + result.stop.bind( result ); + } + return result; + } + } + + jQuery.map( props, createTween, animation ); + + if ( isFunction( animation.opts.start ) ) { + animation.opts.start.call( elem, animation ); + } + + // Attach callbacks from options + animation + .progress( animation.opts.progress ) + .done( animation.opts.done, animation.opts.complete ) + .fail( animation.opts.fail ) + .always( animation.opts.always ); + + jQuery.fx.timer( + jQuery.extend( tick, { + elem: elem, + anim: animation, + queue: animation.opts.queue + } ) + ); + + return animation; +} + +jQuery.Animation = jQuery.extend( Animation, { + + tweeners: { + "*": [ function( prop, value ) { + var tween = this.createTween( prop, value ); + adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); + return tween; + } ] + }, + + tweener: function( props, callback ) { + if ( isFunction( props ) ) { + callback = props; + props = [ "*" ]; + } else { + props = props.match( rnothtmlwhite ); + } + + var prop, + index = 0, + length = props.length; + + for ( ; index < length; index++ ) { + prop = props[ index ]; + Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; + Animation.tweeners[ prop ].unshift( callback ); + } + }, + + prefilters: [ defaultPrefilter ], + + prefilter: function( callback, prepend ) { + if ( prepend ) { + Animation.prefilters.unshift( callback ); + } else { + Animation.prefilters.push( callback ); + } + } +} ); + +jQuery.speed = function( speed, easing, fn ) { + var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { + complete: fn || !fn && easing || + isFunction( speed ) && speed, + duration: speed, + easing: fn && easing || easing && !isFunction( easing ) && easing + }; + + // Go to the end state if fx are off + if ( jQuery.fx.off ) { + opt.duration = 0; + + } else { + if ( typeof opt.duration !== "number" ) { + if ( opt.duration in jQuery.fx.speeds ) { + opt.duration = jQuery.fx.speeds[ opt.duration ]; + + } else { + opt.duration = jQuery.fx.speeds._default; + } + } + } + + // Normalize opt.queue - true/undefined/null -> "fx" + if ( opt.queue == null || opt.queue === true ) { + opt.queue = "fx"; + } + + // Queueing + opt.old = opt.complete; + + opt.complete = function() { + if ( isFunction( opt.old ) ) { + opt.old.call( this ); + } + + if ( opt.queue ) { + jQuery.dequeue( this, opt.queue ); + } + }; + + return opt; +}; + +jQuery.fn.extend( { + fadeTo: function( speed, to, easing, callback ) { + + // Show any hidden elements after setting opacity to 0 + return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show() + + // Animate to the value specified + .end().animate( { opacity: to }, speed, easing, callback ); + }, + animate: function( prop, speed, easing, callback ) { + var empty = jQuery.isEmptyObject( prop ), + optall = jQuery.speed( speed, easing, callback ), + doAnimation = function() { + + // Operate on a copy of prop so per-property easing won't be lost + var anim = Animation( this, jQuery.extend( {}, prop ), optall ); + + // Empty animations, or finishing resolves immediately + if ( empty || dataPriv.get( this, "finish" ) ) { + anim.stop( true ); + } + }; + doAnimation.finish = doAnimation; + + return empty || optall.queue === false ? + this.each( doAnimation ) : + this.queue( optall.queue, doAnimation ); + }, + stop: function( type, clearQueue, gotoEnd ) { + var stopQueue = function( hooks ) { + var stop = hooks.stop; + delete hooks.stop; + stop( gotoEnd ); + }; + + if ( typeof type !== "string" ) { + gotoEnd = clearQueue; + clearQueue = type; + type = undefined; + } + if ( clearQueue ) { + this.queue( type || "fx", [] ); + } + + return this.each( function() { + var dequeue = true, + index = type != null && type + "queueHooks", + timers = jQuery.timers, + data = dataPriv.get( this ); + + if ( index ) { + if ( data[ index ] && data[ index ].stop ) { + stopQueue( data[ index ] ); + } + } else { + for ( index in data ) { + if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { + stopQueue( data[ index ] ); + } + } + } + + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && + ( type == null || timers[ index ].queue === type ) ) { + + timers[ index ].anim.stop( gotoEnd ); + dequeue = false; + timers.splice( index, 1 ); + } + } + + // Start the next in the queue if the last step wasn't forced. + // Timers currently will call their complete callbacks, which + // will dequeue but only if they were gotoEnd. + if ( dequeue || !gotoEnd ) { + jQuery.dequeue( this, type ); + } + } ); + }, + finish: function( type ) { + if ( type !== false ) { + type = type || "fx"; + } + return this.each( function() { + var index, + data = dataPriv.get( this ), + queue = data[ type + "queue" ], + hooks = data[ type + "queueHooks" ], + timers = jQuery.timers, + length = queue ? queue.length : 0; + + // Enable finishing flag on private data + data.finish = true; + + // Empty the queue first + jQuery.queue( this, type, [] ); + + if ( hooks && hooks.stop ) { + hooks.stop.call( this, true ); + } + + // Look for any active animations, and finish them + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && timers[ index ].queue === type ) { + timers[ index ].anim.stop( true ); + timers.splice( index, 1 ); + } + } + + // Look for any animations in the old queue and finish them + for ( index = 0; index < length; index++ ) { + if ( queue[ index ] && queue[ index ].finish ) { + queue[ index ].finish.call( this ); + } + } + + // Turn off finishing flag + delete data.finish; + } ); + } +} ); + +jQuery.each( [ "toggle", "show", "hide" ], function( _i, name ) { + var cssFn = jQuery.fn[ name ]; + jQuery.fn[ name ] = function( speed, easing, callback ) { + return speed == null || typeof speed === "boolean" ? + cssFn.apply( this, arguments ) : + this.animate( genFx( name, true ), speed, easing, callback ); + }; +} ); + +// Generate shortcuts for custom animations +jQuery.each( { + slideDown: genFx( "show" ), + slideUp: genFx( "hide" ), + slideToggle: genFx( "toggle" ), + fadeIn: { opacity: "show" }, + fadeOut: { opacity: "hide" }, + fadeToggle: { opacity: "toggle" } +}, function( name, props ) { + jQuery.fn[ name ] = function( speed, easing, callback ) { + return this.animate( props, speed, easing, callback ); + }; +} ); + +jQuery.timers = []; +jQuery.fx.tick = function() { + var timer, + i = 0, + timers = jQuery.timers; + + fxNow = Date.now(); + + for ( ; i < timers.length; i++ ) { + timer = timers[ i ]; + + // Run the timer and safely remove it when done (allowing for external removal) + if ( !timer() && timers[ i ] === timer ) { + timers.splice( i--, 1 ); + } + } + + if ( !timers.length ) { + jQuery.fx.stop(); + } + fxNow = undefined; +}; + +jQuery.fx.timer = function( timer ) { + jQuery.timers.push( timer ); + jQuery.fx.start(); +}; + +jQuery.fx.interval = 13; +jQuery.fx.start = function() { + if ( inProgress ) { + return; + } + + inProgress = true; + schedule(); +}; + +jQuery.fx.stop = function() { + inProgress = null; +}; + +jQuery.fx.speeds = { + slow: 600, + fast: 200, + + // Default speed + _default: 400 +}; + + +// Based off of the plugin by Clint Helfers, with permission. +// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/ +jQuery.fn.delay = function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; + type = type || "fx"; + + return this.queue( type, function( next, hooks ) { + var timeout = window.setTimeout( next, time ); + hooks.stop = function() { + window.clearTimeout( timeout ); + }; + } ); +}; + + +( function() { + var input = document.createElement( "input" ), + select = document.createElement( "select" ), + opt = select.appendChild( document.createElement( "option" ) ); + + input.type = "checkbox"; + + // Support: Android <=4.3 only + // Default value for a checkbox should be "on" + support.checkOn = input.value !== ""; + + // Support: IE <=11 only + // Must access selectedIndex to make default options select + support.optSelected = opt.selected; + + // Support: IE <=11 only + // An input loses its value after becoming a radio + input = document.createElement( "input" ); + input.value = "t"; + input.type = "radio"; + support.radioValue = input.value === "t"; +} )(); + + +var boolHook, + attrHandle = jQuery.expr.attrHandle; + +jQuery.fn.extend( { + attr: function( name, value ) { + return access( this, jQuery.attr, name, value, arguments.length > 1 ); + }, + + removeAttr: function( name ) { + return this.each( function() { + jQuery.removeAttr( this, name ); + } ); + } +} ); + +jQuery.extend( { + attr: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set attributes on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === "undefined" ) { + return jQuery.prop( elem, name, value ); + } + + // Attribute hooks are determined by the lowercase version + // Grab necessary hook if one is defined + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + hooks = jQuery.attrHooks[ name.toLowerCase() ] || + ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined ); + } + + if ( value !== undefined ) { + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return; + } + + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + elem.setAttribute( name, value + "" ); + return value; + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + ret = jQuery.find.attr( elem, name ); + + // Non-existent attributes return null, we normalize to undefined + return ret == null ? undefined : ret; + }, + + attrHooks: { + type: { + set: function( elem, value ) { + if ( !support.radioValue && value === "radio" && + nodeName( elem, "input" ) ) { + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + } + }, + + removeAttr: function( elem, value ) { + var name, + i = 0, + + // Attribute names can contain non-HTML whitespace characters + // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 + attrNames = value && value.match( rnothtmlwhite ); + + if ( attrNames && elem.nodeType === 1 ) { + while ( ( name = attrNames[ i++ ] ) ) { + elem.removeAttribute( name ); + } + } + } +} ); + +// Hooks for boolean attributes +boolHook = { + set: function( elem, value, name ) { + if ( value === false ) { + + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + elem.setAttribute( name, name ); + } + return name; + } +}; + +jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( _i, name ) { + var getter = attrHandle[ name ] || jQuery.find.attr; + + attrHandle[ name ] = function( elem, name, isXML ) { + var ret, handle, + lowercaseName = name.toLowerCase(); + + if ( !isXML ) { + + // Avoid an infinite loop by temporarily removing this function from the getter + handle = attrHandle[ lowercaseName ]; + attrHandle[ lowercaseName ] = ret; + ret = getter( elem, name, isXML ) != null ? + lowercaseName : + null; + attrHandle[ lowercaseName ] = handle; + } + return ret; + }; +} ); + + + + +var rfocusable = /^(?:input|select|textarea|button)$/i, + rclickable = /^(?:a|area)$/i; + +jQuery.fn.extend( { + prop: function( name, value ) { + return access( this, jQuery.prop, name, value, arguments.length > 1 ); + }, + + removeProp: function( name ) { + return this.each( function() { + delete this[ jQuery.propFix[ name ] || name ]; + } ); + } +} ); + +jQuery.extend( { + prop: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set properties on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + return ( elem[ name ] = value ); + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + return elem[ name ]; + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + + // Support: IE <=9 - 11 only + // elem.tabIndex doesn't always return the + // correct value when it hasn't been explicitly set + // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + // Use proper attribute retrieval(#12072) + var tabindex = jQuery.find.attr( elem, "tabindex" ); + + if ( tabindex ) { + return parseInt( tabindex, 10 ); + } + + if ( + rfocusable.test( elem.nodeName ) || + rclickable.test( elem.nodeName ) && + elem.href + ) { + return 0; + } + + return -1; + } + } + }, + + propFix: { + "for": "htmlFor", + "class": "className" + } +} ); + +// Support: IE <=11 only +// Accessing the selectedIndex property +// forces the browser to respect setting selected +// on the option +// The getter ensures a default option is selected +// when in an optgroup +// eslint rule "no-unused-expressions" is disabled for this code +// since it considers such accessions noop +if ( !support.optSelected ) { + jQuery.propHooks.selected = { + get: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent && parent.parentNode ) { + parent.parentNode.selectedIndex; + } + return null; + }, + set: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent ) { + parent.selectedIndex; + + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + } + }; +} + +jQuery.each( [ + "tabIndex", + "readOnly", + "maxLength", + "cellSpacing", + "cellPadding", + "rowSpan", + "colSpan", + "useMap", + "frameBorder", + "contentEditable" +], function() { + jQuery.propFix[ this.toLowerCase() ] = this; +} ); + + + + + // Strip and collapse whitespace according to HTML spec + // https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace + function stripAndCollapse( value ) { + var tokens = value.match( rnothtmlwhite ) || []; + return tokens.join( " " ); + } + + +function getClass( elem ) { + return elem.getAttribute && elem.getAttribute( "class" ) || ""; +} + +function classesToArray( value ) { + if ( Array.isArray( value ) ) { + return value; + } + if ( typeof value === "string" ) { + return value.match( rnothtmlwhite ) || []; + } + return []; +} + +jQuery.fn.extend( { + addClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + classes = classesToArray( value ); + + if ( classes.length ) { + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + if ( cur.indexOf( " " + clazz + " " ) < 0 ) { + cur += clazz + " "; + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + if ( !arguments.length ) { + return this.attr( "class", "" ); + } + + classes = classesToArray( value ); + + if ( classes.length ) { + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + + // This expression is here for better compressibility (see addClass) + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + + // Remove *all* instances + while ( cur.indexOf( " " + clazz + " " ) > -1 ) { + cur = cur.replace( " " + clazz + " ", " " ); + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value, + isValidValue = type === "string" || Array.isArray( value ); + + if ( typeof stateVal === "boolean" && isValidValue ) { + return stateVal ? this.addClass( value ) : this.removeClass( value ); + } + + if ( isFunction( value ) ) { + return this.each( function( i ) { + jQuery( this ).toggleClass( + value.call( this, i, getClass( this ), stateVal ), + stateVal + ); + } ); + } + + return this.each( function() { + var className, i, self, classNames; + + if ( isValidValue ) { + + // Toggle individual class names + i = 0; + self = jQuery( this ); + classNames = classesToArray( value ); + + while ( ( className = classNames[ i++ ] ) ) { + + // Check each className given, space separated list + if ( self.hasClass( className ) ) { + self.removeClass( className ); + } else { + self.addClass( className ); + } + } + + // Toggle whole class name + } else if ( value === undefined || type === "boolean" ) { + className = getClass( this ); + if ( className ) { + + // Store className if set + dataPriv.set( this, "__className__", className ); + } + + // If the element has a class name or if we're passed `false`, + // then remove the whole classname (if there was one, the above saved it). + // Otherwise bring back whatever was previously saved (if anything), + // falling back to the empty string if nothing was stored. + if ( this.setAttribute ) { + this.setAttribute( "class", + className || value === false ? + "" : + dataPriv.get( this, "__className__" ) || "" + ); + } + } + } ); + }, + + hasClass: function( selector ) { + var className, elem, + i = 0; + + className = " " + selector + " "; + while ( ( elem = this[ i++ ] ) ) { + if ( elem.nodeType === 1 && + ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { + return true; + } + } + + return false; + } +} ); + + + + +var rreturn = /\r/g; + +jQuery.fn.extend( { + val: function( value ) { + var hooks, ret, valueIsFunction, + elem = this[ 0 ]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.type ] || + jQuery.valHooks[ elem.nodeName.toLowerCase() ]; + + if ( hooks && + "get" in hooks && + ( ret = hooks.get( elem, "value" ) ) !== undefined + ) { + return ret; + } + + ret = elem.value; + + // Handle most common string cases + if ( typeof ret === "string" ) { + return ret.replace( rreturn, "" ); + } + + // Handle cases where value is null/undef or number + return ret == null ? "" : ret; + } + + return; + } + + valueIsFunction = isFunction( value ); + + return this.each( function( i ) { + var val; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( valueIsFunction ) { + val = value.call( this, i, jQuery( this ).val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + + } else if ( typeof val === "number" ) { + val += ""; + + } else if ( Array.isArray( val ) ) { + val = jQuery.map( val, function( value ) { + return value == null ? "" : value + ""; + } ); + } + + hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + } ); + } +} ); + +jQuery.extend( { + valHooks: { + option: { + get: function( elem ) { + + var val = jQuery.find.attr( elem, "value" ); + return val != null ? + val : + + // Support: IE <=10 - 11 only + // option.text throws exceptions (#14686, #14858) + // Strip and collapse whitespace + // https://html.spec.whatwg.org/#strip-and-collapse-whitespace + stripAndCollapse( jQuery.text( elem ) ); + } + }, + select: { + get: function( elem ) { + var value, option, i, + options = elem.options, + index = elem.selectedIndex, + one = elem.type === "select-one", + values = one ? null : [], + max = one ? index + 1 : options.length; + + if ( index < 0 ) { + i = max; + + } else { + i = one ? index : 0; + } + + // Loop through all the selected options + for ( ; i < max; i++ ) { + option = options[ i ]; + + // Support: IE <=9 only + // IE8-9 doesn't update selected after form reset (#2551) + if ( ( option.selected || i === index ) && + + // Don't return options that are disabled or in a disabled optgroup + !option.disabled && + ( !option.parentNode.disabled || + !nodeName( option.parentNode, "optgroup" ) ) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + }, + + set: function( elem, value ) { + var optionSet, option, + options = elem.options, + values = jQuery.makeArray( value ), + i = options.length; + + while ( i-- ) { + option = options[ i ]; + + /* eslint-disable no-cond-assign */ + + if ( option.selected = + jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 + ) { + optionSet = true; + } + + /* eslint-enable no-cond-assign */ + } + + // Force browsers to behave consistently when non-matching value is set + if ( !optionSet ) { + elem.selectedIndex = -1; + } + return values; + } + } + } +} ); + +// Radios and checkboxes getter/setter +jQuery.each( [ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + set: function( elem, value ) { + if ( Array.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); + } + } + }; + if ( !support.checkOn ) { + jQuery.valHooks[ this ].get = function( elem ) { + return elem.getAttribute( "value" ) === null ? "on" : elem.value; + }; + } +} ); + + + + +// Return jQuery for attributes-only inclusion + + +support.focusin = "onfocusin" in window; + + +var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, + stopPropagationCallback = function( e ) { + e.stopPropagation(); + }; + +jQuery.extend( jQuery.event, { + + trigger: function( event, data, elem, onlyHandlers ) { + + var i, cur, tmp, bubbleType, ontype, handle, special, lastElement, + eventPath = [ elem || document ], + type = hasOwn.call( event, "type" ) ? event.type : event, + namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; + + cur = lastElement = tmp = elem = elem || document; + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf( "." ) > -1 ) { + + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split( "." ); + type = namespaces.shift(); + namespaces.sort(); + } + ontype = type.indexOf( ":" ) < 0 && "on" + type; + + // Caller can pass in a jQuery.Event object, Object, or just an event type string + event = event[ jQuery.expando ] ? + event : + new jQuery.Event( type, typeof event === "object" && event ); + + // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) + event.isTrigger = onlyHandlers ? 2 : 3; + event.namespace = namespaces.join( "." ); + event.rnamespace = event.namespace ? + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : + null; + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data == null ? + [ event ] : + jQuery.makeArray( data, [ event ] ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + if ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + if ( !rfocusMorph.test( bubbleType + type ) ) { + cur = cur.parentNode; + } + for ( ; cur; cur = cur.parentNode ) { + eventPath.push( cur ); + tmp = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( tmp === ( elem.ownerDocument || document ) ) { + eventPath.push( tmp.defaultView || tmp.parentWindow || window ); + } + } + + // Fire handlers on the event path + i = 0; + while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { + lastElement = cur; + event.type = i > 1 ? + bubbleType : + special.bindType || type; + + // jQuery handler + handle = ( + dataPriv.get( cur, "events" ) || Object.create( null ) + )[ event.type ] && + dataPriv.get( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + + // Native handler + handle = ontype && cur[ ontype ]; + if ( handle && handle.apply && acceptData( cur ) ) { + event.result = handle.apply( cur, data ); + if ( event.result === false ) { + event.preventDefault(); + } + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( ( !special._default || + special._default.apply( eventPath.pop(), data ) === false ) && + acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name as the event. + // Don't do default actions on window, that's where global variables be (#6170) + if ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + tmp = elem[ ontype ]; + + if ( tmp ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + + if ( event.isPropagationStopped() ) { + lastElement.addEventListener( type, stopPropagationCallback ); + } + + elem[ type ](); + + if ( event.isPropagationStopped() ) { + lastElement.removeEventListener( type, stopPropagationCallback ); + } + + jQuery.event.triggered = undefined; + + if ( tmp ) { + elem[ ontype ] = tmp; + } + } + } + } + + return event.result; + }, + + // Piggyback on a donor event to simulate a different one + // Used only for `focus(in | out)` events + simulate: function( type, elem, event ) { + var e = jQuery.extend( + new jQuery.Event(), + event, + { + type: type, + isSimulated: true + } + ); + + jQuery.event.trigger( e, null, elem ); + } + +} ); + +jQuery.fn.extend( { + + trigger: function( type, data ) { + return this.each( function() { + jQuery.event.trigger( type, data, this ); + } ); + }, + triggerHandler: function( type, data ) { + var elem = this[ 0 ]; + if ( elem ) { + return jQuery.event.trigger( type, data, elem, true ); + } + } +} ); + + +// Support: Firefox <=44 +// Firefox doesn't have focus(in | out) events +// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 +// +// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 +// focus(in | out) events fire after focus & blur events, +// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order +// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 +if ( !support.focusin ) { + jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler on the document while someone wants focusin/focusout + var handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + + // Handle: regular nodes (via `this.ownerDocument`), window + // (via `this.document`) & document (via `this`). + var doc = this.ownerDocument || this.document || this, + attaches = dataPriv.access( doc, fix ); + + if ( !attaches ) { + doc.addEventListener( orig, handler, true ); + } + dataPriv.access( doc, fix, ( attaches || 0 ) + 1 ); + }, + teardown: function() { + var doc = this.ownerDocument || this.document || this, + attaches = dataPriv.access( doc, fix ) - 1; + + if ( !attaches ) { + doc.removeEventListener( orig, handler, true ); + dataPriv.remove( doc, fix ); + + } else { + dataPriv.access( doc, fix, attaches ); + } + } + }; + } ); +} +var location = window.location; + +var nonce = { guid: Date.now() }; + +var rquery = ( /\?/ ); + + + +// Cross-browser xml parsing +jQuery.parseXML = function( data ) { + var xml; + if ( !data || typeof data !== "string" ) { + return null; + } + + // Support: IE 9 - 11 only + // IE throws on parseFromString with invalid input. + try { + xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); + } catch ( e ) { + xml = undefined; + } + + if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) { + jQuery.error( "Invalid XML: " + data ); + } + return xml; +}; + + +var + rbracket = /\[\]$/, + rCRLF = /\r?\n/g, + rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, + rsubmittable = /^(?:input|select|textarea|keygen)/i; + +function buildParams( prefix, obj, traditional, add ) { + var name; + + if ( Array.isArray( obj ) ) { + + // Serialize array item. + jQuery.each( obj, function( i, v ) { + if ( traditional || rbracket.test( prefix ) ) { + + // Treat each array item as a scalar. + add( prefix, v ); + + } else { + + // Item is non-scalar (array or object), encode its numeric index. + buildParams( + prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", + v, + traditional, + add + ); + } + } ); + + } else if ( !traditional && toType( obj ) === "object" ) { + + // Serialize object item. + for ( name in obj ) { + buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); + } + + } else { + + // Serialize scalar item. + add( prefix, obj ); + } +} + +// Serialize an array of form elements or a set of +// key/values into a query string +jQuery.param = function( a, traditional ) { + var prefix, + s = [], + add = function( key, valueOrFunction ) { + + // If value is a function, invoke it and use its return value + var value = isFunction( valueOrFunction ) ? + valueOrFunction() : + valueOrFunction; + + s[ s.length ] = encodeURIComponent( key ) + "=" + + encodeURIComponent( value == null ? "" : value ); + }; + + if ( a == null ) { + return ""; + } + + // If an array was passed in, assume that it is an array of form elements. + if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { + + // Serialize the form elements + jQuery.each( a, function() { + add( this.name, this.value ); + } ); + + } else { + + // If traditional, encode the "old" way (the way 1.3.2 or older + // did it), otherwise encode params recursively. + for ( prefix in a ) { + buildParams( prefix, a[ prefix ], traditional, add ); + } + } + + // Return the resulting serialization + return s.join( "&" ); +}; + +jQuery.fn.extend( { + serialize: function() { + return jQuery.param( this.serializeArray() ); + }, + serializeArray: function() { + return this.map( function() { + + // Can add propHook for "elements" to filter or add form elements + var elements = jQuery.prop( this, "elements" ); + return elements ? jQuery.makeArray( elements ) : this; + } ) + .filter( function() { + var type = this.type; + + // Use .is( ":disabled" ) so that fieldset[disabled] works + return this.name && !jQuery( this ).is( ":disabled" ) && + rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && + ( this.checked || !rcheckableType.test( type ) ); + } ) + .map( function( _i, elem ) { + var val = jQuery( this ).val(); + + if ( val == null ) { + return null; + } + + if ( Array.isArray( val ) ) { + return jQuery.map( val, function( val ) { + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ); + } + + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ).get(); + } +} ); + + +var + r20 = /%20/g, + rhash = /#.*$/, + rantiCache = /([?&])_=[^&]*/, + rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, + + // #7653, #8125, #8152: local protocol detection + rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, + rnoContent = /^(?:GET|HEAD)$/, + rprotocol = /^\/\//, + + /* Prefilters + * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) + * 2) These are called: + * - BEFORE asking for a transport + * - AFTER param serialization (s.data is a string if s.processData is true) + * 3) key is the dataType + * 4) the catchall symbol "*" can be used + * 5) execution will start with transport dataType and THEN continue down to "*" if needed + */ + prefilters = {}, + + /* Transports bindings + * 1) key is the dataType + * 2) the catchall symbol "*" can be used + * 3) selection will start with transport dataType and THEN go to "*" if needed + */ + transports = {}, + + // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression + allTypes = "*/".concat( "*" ), + + // Anchor tag for parsing the document origin + originAnchor = document.createElement( "a" ); + originAnchor.href = location.href; + +// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport +function addToPrefiltersOrTransports( structure ) { + + // dataTypeExpression is optional and defaults to "*" + return function( dataTypeExpression, func ) { + + if ( typeof dataTypeExpression !== "string" ) { + func = dataTypeExpression; + dataTypeExpression = "*"; + } + + var dataType, + i = 0, + dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || []; + + if ( isFunction( func ) ) { + + // For each dataType in the dataTypeExpression + while ( ( dataType = dataTypes[ i++ ] ) ) { + + // Prepend if requested + if ( dataType[ 0 ] === "+" ) { + dataType = dataType.slice( 1 ) || "*"; + ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); + + // Otherwise append + } else { + ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); + } + } + } + }; +} + +// Base inspection function for prefilters and transports +function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { + + var inspected = {}, + seekingTransport = ( structure === transports ); + + function inspect( dataType ) { + var selected; + inspected[ dataType ] = true; + jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { + var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); + if ( typeof dataTypeOrTransport === "string" && + !seekingTransport && !inspected[ dataTypeOrTransport ] ) { + + options.dataTypes.unshift( dataTypeOrTransport ); + inspect( dataTypeOrTransport ); + return false; + } else if ( seekingTransport ) { + return !( selected = dataTypeOrTransport ); + } + } ); + return selected; + } + + return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); +} + +// A special extend for ajax options +// that takes "flat" options (not to be deep extended) +// Fixes #9887 +function ajaxExtend( target, src ) { + var key, deep, + flatOptions = jQuery.ajaxSettings.flatOptions || {}; + + for ( key in src ) { + if ( src[ key ] !== undefined ) { + ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; + } + } + if ( deep ) { + jQuery.extend( true, target, deep ); + } + + return target; +} + +/* Handles responses to an ajax request: + * - finds the right dataType (mediates between content-type and expected dataType) + * - returns the corresponding response + */ +function ajaxHandleResponses( s, jqXHR, responses ) { + + var ct, type, finalDataType, firstDataType, + contents = s.contents, + dataTypes = s.dataTypes; + + // Remove auto dataType and get content-type in the process + while ( dataTypes[ 0 ] === "*" ) { + dataTypes.shift(); + if ( ct === undefined ) { + ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); + } + } + + // Check if we're dealing with a known content-type + if ( ct ) { + for ( type in contents ) { + if ( contents[ type ] && contents[ type ].test( ct ) ) { + dataTypes.unshift( type ); + break; + } + } + } + + // Check to see if we have a response for the expected dataType + if ( dataTypes[ 0 ] in responses ) { + finalDataType = dataTypes[ 0 ]; + } else { + + // Try convertible dataTypes + for ( type in responses ) { + if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { + finalDataType = type; + break; + } + if ( !firstDataType ) { + firstDataType = type; + } + } + + // Or just use first one + finalDataType = finalDataType || firstDataType; + } + + // If we found a dataType + // We add the dataType to the list if needed + // and return the corresponding response + if ( finalDataType ) { + if ( finalDataType !== dataTypes[ 0 ] ) { + dataTypes.unshift( finalDataType ); + } + return responses[ finalDataType ]; + } +} + +/* Chain conversions given the request and the original response + * Also sets the responseXXX fields on the jqXHR instance + */ +function ajaxConvert( s, response, jqXHR, isSuccess ) { + var conv2, current, conv, tmp, prev, + converters = {}, + + // Work with a copy of dataTypes in case we need to modify it for conversion + dataTypes = s.dataTypes.slice(); + + // Create converters map with lowercased keys + if ( dataTypes[ 1 ] ) { + for ( conv in s.converters ) { + converters[ conv.toLowerCase() ] = s.converters[ conv ]; + } + } + + current = dataTypes.shift(); + + // Convert to each sequential dataType + while ( current ) { + + if ( s.responseFields[ current ] ) { + jqXHR[ s.responseFields[ current ] ] = response; + } + + // Apply the dataFilter if provided + if ( !prev && isSuccess && s.dataFilter ) { + response = s.dataFilter( response, s.dataType ); + } + + prev = current; + current = dataTypes.shift(); + + if ( current ) { + + // There's only work to do if current dataType is non-auto + if ( current === "*" ) { + + current = prev; + + // Convert response if prev dataType is non-auto and differs from current + } else if ( prev !== "*" && prev !== current ) { + + // Seek a direct converter + conv = converters[ prev + " " + current ] || converters[ "* " + current ]; + + // If none found, seek a pair + if ( !conv ) { + for ( conv2 in converters ) { + + // If conv2 outputs current + tmp = conv2.split( " " ); + if ( tmp[ 1 ] === current ) { + + // If prev can be converted to accepted input + conv = converters[ prev + " " + tmp[ 0 ] ] || + converters[ "* " + tmp[ 0 ] ]; + if ( conv ) { + + // Condense equivalence converters + if ( conv === true ) { + conv = converters[ conv2 ]; + + // Otherwise, insert the intermediate dataType + } else if ( converters[ conv2 ] !== true ) { + current = tmp[ 0 ]; + dataTypes.unshift( tmp[ 1 ] ); + } + break; + } + } + } + } + + // Apply converter (if not an equivalence) + if ( conv !== true ) { + + // Unless errors are allowed to bubble, catch and return them + if ( conv && s.throws ) { + response = conv( response ); + } else { + try { + response = conv( response ); + } catch ( e ) { + return { + state: "parsererror", + error: conv ? e : "No conversion from " + prev + " to " + current + }; + } + } + } + } + } + } + + return { state: "success", data: response }; +} + +jQuery.extend( { + + // Counter for holding the number of active queries + active: 0, + + // Last-Modified header cache for next request + lastModified: {}, + etag: {}, + + ajaxSettings: { + url: location.href, + type: "GET", + isLocal: rlocalProtocol.test( location.protocol ), + global: true, + processData: true, + async: true, + contentType: "application/x-www-form-urlencoded; charset=UTF-8", + + /* + timeout: 0, + data: null, + dataType: null, + username: null, + password: null, + cache: null, + throws: false, + traditional: false, + headers: {}, + */ + + accepts: { + "*": allTypes, + text: "text/plain", + html: "text/html", + xml: "application/xml, text/xml", + json: "application/json, text/javascript" + }, + + contents: { + xml: /\bxml\b/, + html: /\bhtml/, + json: /\bjson\b/ + }, + + responseFields: { + xml: "responseXML", + text: "responseText", + json: "responseJSON" + }, + + // Data converters + // Keys separate source (or catchall "*") and destination types with a single space + converters: { + + // Convert anything to text + "* text": String, + + // Text to html (true = no transformation) + "text html": true, + + // Evaluate text as a json expression + "text json": JSON.parse, + + // Parse text as xml + "text xml": jQuery.parseXML + }, + + // For options that shouldn't be deep extended: + // you can add your own custom options here if + // and when you create one that shouldn't be + // deep extended (see ajaxExtend) + flatOptions: { + url: true, + context: true + } + }, + + // Creates a full fledged settings object into target + // with both ajaxSettings and settings fields. + // If target is omitted, writes into ajaxSettings. + ajaxSetup: function( target, settings ) { + return settings ? + + // Building a settings object + ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : + + // Extending ajaxSettings + ajaxExtend( jQuery.ajaxSettings, target ); + }, + + ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), + ajaxTransport: addToPrefiltersOrTransports( transports ), + + // Main method + ajax: function( url, options ) { + + // If url is an object, simulate pre-1.5 signature + if ( typeof url === "object" ) { + options = url; + url = undefined; + } + + // Force options to be an object + options = options || {}; + + var transport, + + // URL without anti-cache param + cacheURL, + + // Response headers + responseHeadersString, + responseHeaders, + + // timeout handle + timeoutTimer, + + // Url cleanup var + urlAnchor, + + // Request state (becomes false upon send and true upon completion) + completed, + + // To know if global events are to be dispatched + fireGlobals, + + // Loop variable + i, + + // uncached part of the url + uncached, + + // Create the final options object + s = jQuery.ajaxSetup( {}, options ), + + // Callbacks context + callbackContext = s.context || s, + + // Context for global events is callbackContext if it is a DOM node or jQuery collection + globalEventContext = s.context && + ( callbackContext.nodeType || callbackContext.jquery ) ? + jQuery( callbackContext ) : + jQuery.event, + + // Deferreds + deferred = jQuery.Deferred(), + completeDeferred = jQuery.Callbacks( "once memory" ), + + // Status-dependent callbacks + statusCode = s.statusCode || {}, + + // Headers (they are sent all at once) + requestHeaders = {}, + requestHeadersNames = {}, + + // Default abort message + strAbort = "canceled", + + // Fake xhr + jqXHR = { + readyState: 0, + + // Builds headers hashtable if needed + getResponseHeader: function( key ) { + var match; + if ( completed ) { + if ( !responseHeaders ) { + responseHeaders = {}; + while ( ( match = rheaders.exec( responseHeadersString ) ) ) { + responseHeaders[ match[ 1 ].toLowerCase() + " " ] = + ( responseHeaders[ match[ 1 ].toLowerCase() + " " ] || [] ) + .concat( match[ 2 ] ); + } + } + match = responseHeaders[ key.toLowerCase() + " " ]; + } + return match == null ? null : match.join( ", " ); + }, + + // Raw string + getAllResponseHeaders: function() { + return completed ? responseHeadersString : null; + }, + + // Caches the header + setRequestHeader: function( name, value ) { + if ( completed == null ) { + name = requestHeadersNames[ name.toLowerCase() ] = + requestHeadersNames[ name.toLowerCase() ] || name; + requestHeaders[ name ] = value; + } + return this; + }, + + // Overrides response content-type header + overrideMimeType: function( type ) { + if ( completed == null ) { + s.mimeType = type; + } + return this; + }, + + // Status-dependent callbacks + statusCode: function( map ) { + var code; + if ( map ) { + if ( completed ) { + + // Execute the appropriate callbacks + jqXHR.always( map[ jqXHR.status ] ); + } else { + + // Lazy-add the new callbacks in a way that preserves old ones + for ( code in map ) { + statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; + } + } + } + return this; + }, + + // Cancel the request + abort: function( statusText ) { + var finalText = statusText || strAbort; + if ( transport ) { + transport.abort( finalText ); + } + done( 0, finalText ); + return this; + } + }; + + // Attach deferreds + deferred.promise( jqXHR ); + + // Add protocol if not provided (prefilters might expect it) + // Handle falsy url in the settings object (#10093: consistency with old signature) + // We also use the url parameter if available + s.url = ( ( url || s.url || location.href ) + "" ) + .replace( rprotocol, location.protocol + "//" ); + + // Alias method option to type as per ticket #12004 + s.type = options.method || options.type || s.method || s.type; + + // Extract dataTypes list + s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ]; + + // A cross-domain request is in order when the origin doesn't match the current origin. + if ( s.crossDomain == null ) { + urlAnchor = document.createElement( "a" ); + + // Support: IE <=8 - 11, Edge 12 - 15 + // IE throws exception on accessing the href property if url is malformed, + // e.g. http://example.com:80x/ + try { + urlAnchor.href = s.url; + + // Support: IE <=8 - 11 only + // Anchor's host property isn't correctly set when s.url is relative + urlAnchor.href = urlAnchor.href; + s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== + urlAnchor.protocol + "//" + urlAnchor.host; + } catch ( e ) { + + // If there is an error parsing the URL, assume it is crossDomain, + // it can be rejected by the transport if it is invalid + s.crossDomain = true; + } + } + + // Convert data if not already a string + if ( s.data && s.processData && typeof s.data !== "string" ) { + s.data = jQuery.param( s.data, s.traditional ); + } + + // Apply prefilters + inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); + + // If request was aborted inside a prefilter, stop there + if ( completed ) { + return jqXHR; + } + + // We can fire global events as of now if asked to + // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118) + fireGlobals = jQuery.event && s.global; + + // Watch for a new set of requests + if ( fireGlobals && jQuery.active++ === 0 ) { + jQuery.event.trigger( "ajaxStart" ); + } + + // Uppercase the type + s.type = s.type.toUpperCase(); + + // Determine if request has content + s.hasContent = !rnoContent.test( s.type ); + + // Save the URL in case we're toying with the If-Modified-Since + // and/or If-None-Match header later on + // Remove hash to simplify url manipulation + cacheURL = s.url.replace( rhash, "" ); + + // More options handling for requests with no content + if ( !s.hasContent ) { + + // Remember the hash so we can put it back + uncached = s.url.slice( cacheURL.length ); + + // If data is available and should be processed, append data to url + if ( s.data && ( s.processData || typeof s.data === "string" ) ) { + cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; + + // #9682: remove data so that it's not used in an eventual retry + delete s.data; + } + + // Add or update anti-cache param if needed + if ( s.cache === false ) { + cacheURL = cacheURL.replace( rantiCache, "$1" ); + uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce.guid++ ) + + uncached; + } + + // Put hash and anti-cache on the URL that will be requested (gh-1732) + s.url = cacheURL + uncached; + + // Change '%20' to '+' if this is encoded form body content (gh-2658) + } else if ( s.data && s.processData && + ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { + s.data = s.data.replace( r20, "+" ); + } + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + if ( jQuery.lastModified[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); + } + if ( jQuery.etag[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); + } + } + + // Set the correct header, if data is being sent + if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { + jqXHR.setRequestHeader( "Content-Type", s.contentType ); + } + + // Set the Accepts header for the server, depending on the dataType + jqXHR.setRequestHeader( + "Accept", + s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? + s.accepts[ s.dataTypes[ 0 ] ] + + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : + s.accepts[ "*" ] + ); + + // Check for headers option + for ( i in s.headers ) { + jqXHR.setRequestHeader( i, s.headers[ i ] ); + } + + // Allow custom headers/mimetypes and early abort + if ( s.beforeSend && + ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) { + + // Abort if not done already and return + return jqXHR.abort(); + } + + // Aborting is no longer a cancellation + strAbort = "abort"; + + // Install callbacks on deferreds + completeDeferred.add( s.complete ); + jqXHR.done( s.success ); + jqXHR.fail( s.error ); + + // Get transport + transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); + + // If no transport, we auto-abort + if ( !transport ) { + done( -1, "No Transport" ); + } else { + jqXHR.readyState = 1; + + // Send global event + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); + } + + // If request was aborted inside ajaxSend, stop there + if ( completed ) { + return jqXHR; + } + + // Timeout + if ( s.async && s.timeout > 0 ) { + timeoutTimer = window.setTimeout( function() { + jqXHR.abort( "timeout" ); + }, s.timeout ); + } + + try { + completed = false; + transport.send( requestHeaders, done ); + } catch ( e ) { + + // Rethrow post-completion exceptions + if ( completed ) { + throw e; + } + + // Propagate others as results + done( -1, e ); + } + } + + // Callback for when everything is done + function done( status, nativeStatusText, responses, headers ) { + var isSuccess, success, error, response, modified, + statusText = nativeStatusText; + + // Ignore repeat invocations + if ( completed ) { + return; + } + + completed = true; + + // Clear timeout if it exists + if ( timeoutTimer ) { + window.clearTimeout( timeoutTimer ); + } + + // Dereference transport for early garbage collection + // (no matter how long the jqXHR object will be used) + transport = undefined; + + // Cache response headers + responseHeadersString = headers || ""; + + // Set readyState + jqXHR.readyState = status > 0 ? 4 : 0; + + // Determine if successful + isSuccess = status >= 200 && status < 300 || status === 304; + + // Get response data + if ( responses ) { + response = ajaxHandleResponses( s, jqXHR, responses ); + } + + // Use a noop converter for missing script + if ( !isSuccess && jQuery.inArray( "script", s.dataTypes ) > -1 ) { + s.converters[ "text script" ] = function() {}; + } + + // Convert no matter what (that way responseXXX fields are always set) + response = ajaxConvert( s, response, jqXHR, isSuccess ); + + // If successful, handle type chaining + if ( isSuccess ) { + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + modified = jqXHR.getResponseHeader( "Last-Modified" ); + if ( modified ) { + jQuery.lastModified[ cacheURL ] = modified; + } + modified = jqXHR.getResponseHeader( "etag" ); + if ( modified ) { + jQuery.etag[ cacheURL ] = modified; + } + } + + // if no content + if ( status === 204 || s.type === "HEAD" ) { + statusText = "nocontent"; + + // if not modified + } else if ( status === 304 ) { + statusText = "notmodified"; + + // If we have data, let's convert it + } else { + statusText = response.state; + success = response.data; + error = response.error; + isSuccess = !error; + } + } else { + + // Extract error from statusText and normalize for non-aborts + error = statusText; + if ( status || !statusText ) { + statusText = "error"; + if ( status < 0 ) { + status = 0; + } + } + } + + // Set data for the fake xhr object + jqXHR.status = status; + jqXHR.statusText = ( nativeStatusText || statusText ) + ""; + + // Success/Error + if ( isSuccess ) { + deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); + } else { + deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); + } + + // Status-dependent callbacks + jqXHR.statusCode( statusCode ); + statusCode = undefined; + + if ( fireGlobals ) { + globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", + [ jqXHR, s, isSuccess ? success : error ] ); + } + + // Complete + completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); + + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); + + // Handle the global AJAX counter + if ( !( --jQuery.active ) ) { + jQuery.event.trigger( "ajaxStop" ); + } + } + } + + return jqXHR; + }, + + getJSON: function( url, data, callback ) { + return jQuery.get( url, data, callback, "json" ); + }, + + getScript: function( url, callback ) { + return jQuery.get( url, undefined, callback, "script" ); + } +} ); + +jQuery.each( [ "get", "post" ], function( _i, method ) { + jQuery[ method ] = function( url, data, callback, type ) { + + // Shift arguments if data argument was omitted + if ( isFunction( data ) ) { + type = type || callback; + callback = data; + data = undefined; + } + + // The url can be an options object (which then must have .url) + return jQuery.ajax( jQuery.extend( { + url: url, + type: method, + dataType: type, + data: data, + success: callback + }, jQuery.isPlainObject( url ) && url ) ); + }; +} ); + +jQuery.ajaxPrefilter( function( s ) { + var i; + for ( i in s.headers ) { + if ( i.toLowerCase() === "content-type" ) { + s.contentType = s.headers[ i ] || ""; + } + } +} ); + + +jQuery._evalUrl = function( url, options, doc ) { + return jQuery.ajax( { + url: url, + + // Make this explicit, since user can override this through ajaxSetup (#11264) + type: "GET", + dataType: "script", + cache: true, + async: false, + global: false, + + // Only evaluate the response if it is successful (gh-4126) + // dataFilter is not invoked for failure responses, so using it instead + // of the default converter is kludgy but it works. + converters: { + "text script": function() {} + }, + dataFilter: function( response ) { + jQuery.globalEval( response, options, doc ); + } + } ); +}; + + +jQuery.fn.extend( { + wrapAll: function( html ) { + var wrap; + + if ( this[ 0 ] ) { + if ( isFunction( html ) ) { + html = html.call( this[ 0 ] ); + } + + // The elements to wrap the target around + wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); + + if ( this[ 0 ].parentNode ) { + wrap.insertBefore( this[ 0 ] ); + } + + wrap.map( function() { + var elem = this; + + while ( elem.firstElementChild ) { + elem = elem.firstElementChild; + } + + return elem; + } ).append( this ); + } + + return this; + }, + + wrapInner: function( html ) { + if ( isFunction( html ) ) { + return this.each( function( i ) { + jQuery( this ).wrapInner( html.call( this, i ) ); + } ); + } + + return this.each( function() { + var self = jQuery( this ), + contents = self.contents(); + + if ( contents.length ) { + contents.wrapAll( html ); + + } else { + self.append( html ); + } + } ); + }, + + wrap: function( html ) { + var htmlIsFunction = isFunction( html ); + + return this.each( function( i ) { + jQuery( this ).wrapAll( htmlIsFunction ? html.call( this, i ) : html ); + } ); + }, + + unwrap: function( selector ) { + this.parent( selector ).not( "body" ).each( function() { + jQuery( this ).replaceWith( this.childNodes ); + } ); + return this; + } +} ); + + +jQuery.expr.pseudos.hidden = function( elem ) { + return !jQuery.expr.pseudos.visible( elem ); +}; +jQuery.expr.pseudos.visible = function( elem ) { + return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); +}; + + + + +jQuery.ajaxSettings.xhr = function() { + try { + return new window.XMLHttpRequest(); + } catch ( e ) {} +}; + +var xhrSuccessStatus = { + + // File protocol always yields status code 0, assume 200 + 0: 200, + + // Support: IE <=9 only + // #1450: sometimes IE returns 1223 when it should be 204 + 1223: 204 + }, + xhrSupported = jQuery.ajaxSettings.xhr(); + +support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); +support.ajax = xhrSupported = !!xhrSupported; + +jQuery.ajaxTransport( function( options ) { + var callback, errorCallback; + + // Cross domain only allowed if supported through XMLHttpRequest + if ( support.cors || xhrSupported && !options.crossDomain ) { + return { + send: function( headers, complete ) { + var i, + xhr = options.xhr(); + + xhr.open( + options.type, + options.url, + options.async, + options.username, + options.password + ); + + // Apply custom fields if provided + if ( options.xhrFields ) { + for ( i in options.xhrFields ) { + xhr[ i ] = options.xhrFields[ i ]; + } + } + + // Override mime type if needed + if ( options.mimeType && xhr.overrideMimeType ) { + xhr.overrideMimeType( options.mimeType ); + } + + // X-Requested-With header + // For cross-domain requests, seeing as conditions for a preflight are + // akin to a jigsaw puzzle, we simply never set it to be sure. + // (it can always be set on a per-request basis or even using ajaxSetup) + // For same-domain requests, won't change header if already provided. + if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { + headers[ "X-Requested-With" ] = "XMLHttpRequest"; + } + + // Set headers + for ( i in headers ) { + xhr.setRequestHeader( i, headers[ i ] ); + } + + // Callback + callback = function( type ) { + return function() { + if ( callback ) { + callback = errorCallback = xhr.onload = + xhr.onerror = xhr.onabort = xhr.ontimeout = + xhr.onreadystatechange = null; + + if ( type === "abort" ) { + xhr.abort(); + } else if ( type === "error" ) { + + // Support: IE <=9 only + // On a manual native abort, IE9 throws + // errors on any property access that is not readyState + if ( typeof xhr.status !== "number" ) { + complete( 0, "error" ); + } else { + complete( + + // File: protocol always yields status 0; see #8605, #14207 + xhr.status, + xhr.statusText + ); + } + } else { + complete( + xhrSuccessStatus[ xhr.status ] || xhr.status, + xhr.statusText, + + // Support: IE <=9 only + // IE9 has no XHR2 but throws on binary (trac-11426) + // For XHR2 non-text, let the caller handle it (gh-2498) + ( xhr.responseType || "text" ) !== "text" || + typeof xhr.responseText !== "string" ? + { binary: xhr.response } : + { text: xhr.responseText }, + xhr.getAllResponseHeaders() + ); + } + } + }; + }; + + // Listen to events + xhr.onload = callback(); + errorCallback = xhr.onerror = xhr.ontimeout = callback( "error" ); + + // Support: IE 9 only + // Use onreadystatechange to replace onabort + // to handle uncaught aborts + if ( xhr.onabort !== undefined ) { + xhr.onabort = errorCallback; + } else { + xhr.onreadystatechange = function() { + + // Check readyState before timeout as it changes + if ( xhr.readyState === 4 ) { + + // Allow onerror to be called first, + // but that will not handle a native abort + // Also, save errorCallback to a variable + // as xhr.onerror cannot be accessed + window.setTimeout( function() { + if ( callback ) { + errorCallback(); + } + } ); + } + }; + } + + // Create the abort callback + callback = callback( "abort" ); + + try { + + // Do send the request (this may raise an exception) + xhr.send( options.hasContent && options.data || null ); + } catch ( e ) { + + // #14683: Only rethrow if this hasn't been notified as an error yet + if ( callback ) { + throw e; + } + } + }, + + abort: function() { + if ( callback ) { + callback(); + } + } + }; + } +} ); + + + + +// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) +jQuery.ajaxPrefilter( function( s ) { + if ( s.crossDomain ) { + s.contents.script = false; + } +} ); + +// Install script dataType +jQuery.ajaxSetup( { + accepts: { + script: "text/javascript, application/javascript, " + + "application/ecmascript, application/x-ecmascript" + }, + contents: { + script: /\b(?:java|ecma)script\b/ + }, + converters: { + "text script": function( text ) { + jQuery.globalEval( text ); + return text; + } + } +} ); + +// Handle cache's special case and crossDomain +jQuery.ajaxPrefilter( "script", function( s ) { + if ( s.cache === undefined ) { + s.cache = false; + } + if ( s.crossDomain ) { + s.type = "GET"; + } +} ); + +// Bind script tag hack transport +jQuery.ajaxTransport( "script", function( s ) { + + // This transport only deals with cross domain or forced-by-attrs requests + if ( s.crossDomain || s.scriptAttrs ) { + var script, callback; + return { + send: function( _, complete ) { + script = jQuery( " + + + + + + + + + + + + + + + + + +
+
+ + + ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

HADevice class

+
+
+class HADevice
+

This class represents your device that’s going to be registered in the Home Assistant devices registry. Each entity (HABinarySensor, HASensor, etc.) that you use will be owned by this device.

+
+

Public Functions

+
+
+HADevice()
+

Constructs HADevice without the unique ID.

+
+

Note

+

You will need to set the ID using HADevice::setUniqueId method. Otherwise none of the entities will work.

+
+
+ +
+
+HADevice(const char *uniqueId)
+

Constructs HADevice with the given unique ID (string). Keep the unique ID short to save the memory.

+
+
Parameters
+

uniqueId – String with the null terminator.

+
+
+
+ +
+
+HADevice(const byte *uniqueId, const uint16_t length)
+

Constructs HADevice using the given byte array as the unique ID. It works in the same way as HADevice::setUniqueId method.

+
+
Parameters
+
    +
  • uniqueId – Bytes array that’s going to be converted into the string.

  • +
  • length – Number of bytes in the array.

  • +
+
+
+
+ +
+
+~HADevice()
+

Deletes HASerializer and the availability topic if the shared availability was enabled.

+
+ +
+
+inline const char *getUniqueId() const
+

Returns pointer to the unique ID. It can be nullptr if the device has no ID assigned.

+
+ +
+
+inline const HASerializer *getSerializer() const
+

Returns the instance of the HASerializer used by the device. This method is used by all entities to serialize device’s representation.

+
+ +
+
+inline bool isSharedAvailabilityEnabled() const
+

Returns true if the shared availability is enabled for the device.

+
+ +
+
+inline const char *getAvailabilityTopic() const
+

Returns availability topic generated by the HADevice::enableSharedAvailability method. It can be nullptr if the shared availability is not enabled.

+
+ +
+
+inline bool isAvailable() const
+

Returns online/offline state of the device.

+
+ +
+
+bool setUniqueId(const byte *uniqueId, const uint16_t length)
+

Sets unique ID of the device based on the given byte array. Each byte is converted into a hex string representation, so the final length of the unique ID will be twice as given.

+
+

Note

+

The unique ID can be set only once (via constructor or using this method).

+
+
+
Parameters
+
    +
  • uniqueId – Bytes array that’s going to be converted into the string.

  • +
  • length – Number of bytes in the array.

  • +
+
+
+
+ +
+
+void setManufacturer(const char *manufacturer)
+

Sets the “manufacturer” property that’s going to be displayed in the Home Assistant.

+
+
Parameters
+

manufacturer – Any string. Keep it short to save the memory.

+
+
+
+ +
+
+void setModel(const char *model)
+

Sets the “model” property that’s going to be displayed in the Home Assistant.

+
+
Parameters
+

model – Any string. Keep it short to save the memory.

+
+
+
+ +
+
+void setName(const char *name)
+

Sets the “name” property that’s going to be displayed in the Home Assistant.

+
+
Parameters
+

name – Any string. Keep it short to save the memory.

+
+
+
+ +
+
+void setSoftwareVersion(const char *softwareVersion)
+

Sets the “software version” property that’s going to be displayed in the Home Assistant.

+
+
Parameters
+

softwareVersion – Any string. Keep it short to save the memory.

+
+
+
+ +
+
+void setAvailability(bool online)
+

Sets device’s availability and publishes MQTT message on the availability topic. If the device is not connected to an MQTT broker or the shared availability is not enabled then nothing happens.

+
+
Parameters
+

online – Set to true if the device should be displayed as available in the HA panel.

+
+
+
+ +
+
+bool enableSharedAvailability()
+

Enables the shared availability feature.

+
+ +
+
+void enableLastWill()
+

Enables MQTT LWT feature. Please note that the shared availability needs to be enabled first.

+
+ +
+
+void publishAvailability() const
+

Publishes current availability of the device on the availability topic. If the device is not connected to an MQTT broker or the shared availability is not enabled then nothing happens. This method is called by the HAMqtt when the connection to an MQTT broker is acquired.

+
+ +
+
+

Private Members

+
+
+const char *_uniqueId
+

The unique ID of the device. It can be a memory allocated by HADevice::setUniqueId method.

+
+ +
+
+bool _ownsUniqueId
+

Specifies whether HADevice class owns the _uniqueId pointer.

+
+ +
+
+HASerializer *_serializer
+

JSON serializer of the HADevice class. It’s allocated in the constructor.

+
+ +
+
+char *_availabilityTopic
+

The availability topic allocated by HADevice::enableSharedAvailability method.

+
+ +
+
+bool _sharedAvailability
+

Specifies whether the shared availability is enabled.

+
+ +
+
+bool _available
+

Specifies whether the device is available (online / offline).

+
+ +
+
+ +
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/docs/documents/api/core/ha-mqtt.html b/docs/documents/api/core/ha-mqtt.html new file mode 100644 index 0000000..4a533af --- /dev/null +++ b/docs/documents/api/core/ha-mqtt.html @@ -0,0 +1,625 @@ + + + + + + + HAMqtt class - ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

HAMqtt class

+
+
+class HAMqtt
+

This class is a wrapper for the PubSub API. It’s a central point of the library where instances of all device types are stored.

+
+

Public Functions

+
+
+explicit HAMqtt(Client &netClient, HADevice &device, const uint8_t maxDevicesTypesNb = 6)
+

Creates a new instance of the HAMqtt class. Please note that only one instance of the class can be initialized at the same time.

+
+
Parameters
+
    +
  • netClient – The EthernetClient or WiFiClient that’s going to be used for the network communication.

  • +
  • device – An instance of the HADevice class representing your device.

  • +
  • maxDevicesTypesNb – The maximum number of device types (sensors, switches, etc.) that you’re going to implement.

  • +
+
+
+
+ +
+
+~HAMqtt()
+

Removes singleton of the HAMqtt class.

+
+ +
+
+inline void setDiscoveryPrefix(const char *prefix)
+

Sets the prefix of the Home Assistant discovery topics. It needs to match the prefix set in the HA admin panel. The default prefix is “homeassistant”.

+
+
Parameters
+

prefix – The discovery topics’ prefix.

+
+
+
+ +
+
+inline const char *getDiscoveryPrefix() const
+

Returns the discovery topics’ prefix.

+
+ +
+
+inline void setDataPrefix(const char *prefix)
+

Sets prefix of the data topics. It may be useful if you want to pass MQTT traffic through a bridge. The default prefix is “aha”.

+
+
Parameters
+

prefix – The data topics’ prefix.

+
+
+
+ +
+
+inline const char *getDataPrefix() const
+

Returns the data topics’ prefix.

+
+ +
+
+inline HADevice const *getDevice() const
+

Returns instance of the device assigned to the HAMqtt class. It’s the same object (pointer) that was passed to the HAMqtt constructor.

+
+ +
+
+inline void onMessage(void (*callback)(const char *topic, const uint8_t *payload, uint16_t length))
+

Registers a new callback method that will be called when the device receives an MQTT message. Please note that the callback is also fired by internal MQTT messages used by the library. You should always verify the topic of the received message.

+
+
Parameters
+

callback – Callback method.

+
+
+
+ +
+
+inline void onConnected(void (*callback)())
+

Registers a new callback method that will be called each time a connection to the MQTT broker is acquired. The callback is also fired after reconnecting to the broker. You can use this method to register topics’ subscriptions.

+
+
Parameters
+

callback – Callback method.

+
+
+
+ +
+
+bool begin(const IPAddress serverIp, const uint16_t serverPort = 1883, const char *username = nullptr, const char *password = nullptr)
+

Sets parameters of the MQTT connection using the IP address and port. The library will try to connect to the broker in first loop cycle. Please note that the library automatically reconnects to the broker if connection is lost.

+
+
Parameters
+
    +
  • serverIp – IP address of the MQTT broker.

  • +
  • serverPort – Port of the MQTT broker.

  • +
  • username – Username for authentication. It can be nullptr if the anonymous connection needs to be performed.

  • +
  • password – Password for authentication. It can be nullptr if the anonymous connection needs to be performed.

  • +
+
+
+
+ +
+
+bool begin(const IPAddress serverIp, const char *username, const char *password)
+

Sets parameters of the MQTT connection using the IP address and the default port (1883). The library will try to connect to the broker in first loop cycle. Please note that the library automatically reconnects to the broker if connection is lost.

+
+
Parameters
+
    +
  • serverIp – IP address of the MQTT broker.

  • +
  • username – Username for authentication. It can be nullptr if the anonymous connection needs to be performed.

  • +
  • password – Password for authentication. It can be nullptr if the anonymous connection needs to be performed.

  • +
+
+
+
+ +
+
+bool begin(const char *serverHostname, const uint16_t serverPort = 1883, const char *username = nullptr, const char *password = nullptr)
+

Sets parameters of the MQTT connection using the hostname and port. The library will try to connect to the broker in first loop cycle. Please note that the library automatically reconnects to the broker if connection is lost.

+
+
Parameters
+
    +
  • serverHostname – Hostname of the MQTT broker.

  • +
  • serverPort – Port of the MQTT broker.

  • +
  • username – Username for authentication. It can be nullptr if the anonymous connection needs to be performed.

  • +
  • password – Password for authentication. It can be nullptr if the anonymous connection needs to be performed.

  • +
+
+
+
+ +
+
+bool begin(const char *serverHostname, const char *username, const char *password)
+

Sets parameters of the MQTT connection using the hostname and the default port (1883). The library will try to connect to the broker in first loop cycle. Please note that the library automatically reconnects to the broker if connection is lost.

+
+
Parameters
+
    +
  • serverHostname – Hostname of the MQTT broker.

  • +
  • username – Username for authentication. It can be nullptr if the anonymous connection needs to be performed.

  • +
  • password – Password for authentication. It can be nullptr if the anonymous connection needs to be performed.

  • +
+
+
+
+ +
+
+bool disconnect()
+

Closes the MQTT connection.

+
+ +
+
+void loop()
+

This method should be called periodically inside the main loop of the firmware. It’s safe to call this method in some interval (like 5ms).

+
+ +
+
+bool isConnected() const
+

Returns true if connection to the MQTT broker is established.

+
+ +
+
+void addDeviceType(HABaseDeviceType *deviceType)
+

Adds a new device’s type to the MQTT. Each time the connection with MQTT broker is acquired, the HAMqtt class calls “onMqttConnected” method in all devices’ types instances.

+
+

Note

+

The HAMqtt class doesn’t take ownership of the given pointer.

+
+
+
Parameters
+

deviceType – Instance of the device’s type (HASwitch, HABinarySensor, etc.).

+
+
+
+ +
+
+bool publish(const char *topic, const char *payload, bool retained = false)
+

Publishes the MQTT message with given topic and payload. Message won’t be published if the connection with the MQTT broker is not established. In this case method returns false.

+
+
Parameters
+
    +
  • topic – The topic to publish.

  • +
  • payload – The payload to publish (it may be empty const char).

  • +
  • retained – Specifies whether message should be retained.

  • +
+
+
+
+ +
+
+bool beginPublish(const char *topic, uint16_t payloadLength, bool retained = false)
+

Begins publishing of a message with the given properties. When this method returns true the payload can be written using HAMqtt::writePayload method.

+
+
Parameters
+
    +
  • topic – Topic of the published message.

  • +
  • payloadLength – Length of the payload (bytes) that’s going to be published.

  • +
  • retained – Specifies whether the published message should be retained.

  • +
+
+
+
+ +
+
+void writePayload(const char *data, const uint16_t length)
+

Writes given string to the TCP stream. Please note that before writing any data the HAMqtt::beginPublish method needs to be called.

+
+
Parameters
+
    +
  • data – The string to publish.

  • +
  • length – Length of the data (bytes).

  • +
+
+
+
+ +
+
+void writePayload(const uint8_t *data, const uint16_t length)
+

Writes given data to the TCP stream. Please note that before writing any data the HAMqtt::beginPublish method needs to be called.

+
+
Parameters
+
    +
  • data – The data to publish.

  • +
  • length – Length of the data (bytes).

  • +
+
+
+
+ +
+
+void writePayload(const __FlashStringHelper *data)
+

Writes given progmem data to the TCP stream. Please note that before writing any data the HAMqtt::beginPublish method needs to be called.

+
+
Parameters
+

data – Progmem data to publish.

+
+
+
+ +
+
+bool endPublish()
+

Finishes publishing of a message. After calling this method the message will be processed by the broker.

+
+ +
+
+bool subscribe(const char *topic)
+

Subscribes to the given topic. Whenever a new message is received the onMqttMessage callback in all devices types is called.

+

Please note that you need to subscribe topic each time the connection with the broker is acquired.

+
+
Parameters
+

topic – Topic to subscribe.

+
+
+
+ +
+
+inline void setLastWill(const char *lastWillTopic, const char *lastWillMessage, bool lastWillRetain)
+

Enables the last will message that will be produced when the device disconnects from the broker. If you want to change availability of the device in Home Assistant panel please use enableLastWill() method from the HADevice class instead.

+
+
Parameters
+
    +
  • lastWillTopic – The topic to publish.

  • +
  • lastWillMessage – The message (payload) to publish.

  • +
  • lastWillRetain – Specifies whether the published message should be retained.

  • +
+
+
+
+ +
+
+void processMessage(const char *topic, const uint8_t *payload, uint16_t length)
+

Processes MQTT message received from the broker (subscription).

+
+

Note

+

Do not use this method on your own. It’s only for the internal purpose.

+
+
+
Parameters
+
    +
  • topic – Topic of the message.

  • +
  • payload – Content of the message.

  • +
  • length – Length of the message.

  • +
+
+
+
+ +
+
+

Public Static Functions

+
+
+static inline HAMqtt *instance()
+

Returns existing instance (singleton) of the HAMqtt class. It may be a null pointer if the HAMqtt object was never constructed or it was destroyed.

+
+ +
+
+

Private Functions

+
+
+void connectToServer()
+

Attempts to connect to the MQTT broker. The method uses properties passed to the “begin” method.

+
+ +
+
+void onConnectedLogic()
+

This method is called each time the connection with MQTT broker is acquired.

+
+ +
+
+

Private Members

+
+
+PubSubClient *_mqtt
+

Instance of the PubSubClient class. It’s initialized in the constructor.

+
+ +
+
+const HADevice &_device
+

Instance of the HADevice passed to the constructor.

+
+ +
+
+void (*_messageCallback)(const char *topic, const uint8_t *payload, uint16_t length)
+

The callback method that will be called when an MQTT message is received.

+
+ +
+
+void (*_connectedCallback)()
+

The callback method that will be called when the MQTT connection is acquired.

+
+ +
+
+bool _initialized
+

Specifies whether the HAMqtt::begin method was ever called.

+
+ +
+
+const char *_discoveryPrefix
+

Teh discovery prefix that’s used for the configuration messages.

+
+ +
+
+const char *_dataPrefix
+

The data prefix that’s used for publishing data messages.

+
+ +
+
+const char *_username
+

The username used for the authentication. It’s set in the HAMqtt::begin method.

+
+ +
+
+const char *_password
+

The password used for the authentication. It’s set in the HAMqtt::begin method.

+
+ +
+
+uint32_t _lastConnectionAttemptAt
+

Time of the last connection attemps (milliseconds since boot).

+
+ +
+
+uint8_t _devicesTypesNb
+

The amount of registered devices types.

+
+ +
+
+uint8_t _maxDevicesTypesNb
+

The maximum amount of devices types that can be registered.

+
+ +
+
+HABaseDeviceType **_devicesTypes
+

Pointers of all registered devices types (array of pointers).

+
+ +
+
+const char *_lastWillTopic
+

The last will topic set by HAMqtt::setLastWill.

+
+ +
+
+const char *_lastWillMessage
+

The last will message set by HAMqtt::setLastWill.

+
+ +
+
+bool _lastWillRetain
+

The last will retain set by HAMqtt::setLastWill.

+
+ +
+
+

Private Static Attributes

+
+
+static const uint16_t ReconnectInterval = 5000
+

Interval between MQTT reconnects (milliseconds).

+
+ +
+
+static HAMqtt *_instance
+

Living instance of the HAMqtt class. It can be nullptr.

+
+ +
+
+ +
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/docs/documents/api/core/index.html b/docs/documents/api/core/index.html new file mode 100644 index 0000000..38d64fd --- /dev/null +++ b/docs/documents/api/core/index.html @@ -0,0 +1,183 @@ + + + + + + + Core API - ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

Core API

+ +
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/docs/documents/api/device-types/ha-base-device-type.html b/docs/documents/api/device-types/ha-base-device-type.html new file mode 100644 index 0000000..bf9ba38 --- /dev/null +++ b/docs/documents/api/device-types/ha-base-device-type.html @@ -0,0 +1,473 @@ + + + + + + + HABaseDeviceType class - ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

HABaseDeviceType class

+
+
+class HABaseDeviceType
+

Subclassed by HABinarySensor, HAButton, HACamera, HACover, HADeviceTracker, HADeviceTrigger, HAFan, HAHVAC, HALight, HALock, HANumber, HAScene, HASelect, HASensor, HASwitch, HATagScanner

+
+

Public Types

+
+
+enum NumberPrecision
+

Values:

+
+
+enumerator PrecisionP0
+

No digits after the decimal point.

+
+ +
+
+enumerator PrecisionP1
+

One digit after the decimal point.

+
+ +
+
+enumerator PrecisionP2
+

Two digits after the decimal point.

+
+ +
+
+enumerator PrecisionP3
+

Three digits after the decimal point.

+
+ +
+ +
+
+

Public Functions

+
+
+HABaseDeviceType(const __FlashStringHelper *componentName, const char *uniqueId)
+

Creates a new device type instance and registers it in the HAMqtt class.

+
+
Parameters
+
    +
  • componentName – The name of the Home Assistant component (e.g. binary_sensor). You can find all available component names in the Home Assistant documentation. The component name needs to be stored in the flash memory.

  • +
  • uniqueId – The unique ID of the device type. It needs to be unique in a scope of the HADevice.

  • +
+
+
+
+ +
+
+inline const char *uniqueId() const
+

Returns unique ID of the device type.

+
+ +
+
+inline const __FlashStringHelper *componentName() const
+

Returns component name defined by the device type. It’s used for the MQTT discovery topic.

+
+ +
+
+inline bool isAvailabilityConfigured() const
+

Returns true if the availability was configured for this device type.

+
+ +
+
+inline bool isOnline() const
+

Returns online state of the device type.

+
+ +
+
+inline void setName(const char *name)
+

Sets name of the device type that will be used as a label in the HA panel. Keep the name short to save the resources.

+
+
Parameters
+

name – The device type name.

+
+
+
+ +
+
+inline const char *getName() const
+

Returns name of the deviced type that was assigned via setName method. It can be nullptr if there is no name assigned.

+
+ +
+
+virtual void setAvailability(bool online)
+

Sets availability of the device type. Setting the initial availability enables availability reporting for this device type. Please note that not all device types support this feature. Follow HA documentation of a specific device type to get more information.

+
+
Parameters
+

online – Specifies whether the device type is online.

+
+
+
+ +
+
+

Protected Functions

+
+
+inline virtual void buildSerializer()
+

This method should build serializer that will be used for publishing the configuration. The serializer is built each time the MQTT connection is acquired. Follow implementation of the existing device types to get better understanding of the logic.

+
+ +
+
+virtual void onMqttConnected() = 0
+

This method is called each time the MQTT connection is acquired. Each device type should publish its configuration and availability. It can be also used for subscribing to MQTT topics.

+
+ +
+
+virtual void onMqttMessage(const char *topic, const uint8_t *payload, const uint16_t length)
+

This method is called each time the device receives a MQTT message. It can be any MQTT message so the method should always verify the topic.

+
+
Parameters
+
    +
  • topic – The topic on which the message was produced.

  • +
  • payload – The payload of the message. It can be nullptr.

  • +
  • length – The length of the payload.

  • +
+
+
+
+ +
+
+void destroySerializer()
+

Destroys the existing serializer.

+
+ +
+
+void publishConfig()
+

Publishes configuration of this device type on the HA discovery topic.

+
+ +
+
+void publishAvailability()
+

Publishes current availability of the device type. The message is only produced if the availability is configured for this device type.

+
+ +
+
+bool publishOnDataTopic(const __FlashStringHelper *topic, const __FlashStringHelper *payload, bool retained = false)
+

Publishes the given flash string on the data topic.

+
+
Parameters
+
    +
  • topic – The topic to publish on (progmem string).

  • +
  • payload – The message’s payload (progmem string).

  • +
  • retained – Specifies whether the message should be retained.

  • +
+
+
+
+ +
+
+bool publishOnDataTopic(const __FlashStringHelper *topic, const char *payload, bool retained = false)
+

Publishes the given string on the data topic.

+
+
Parameters
+
    +
  • topic – The topic to publish on (progmem string).

  • +
  • payload – The message’s payload.

  • +
  • retained – Specifies whether the message should be retained.

  • +
+
+
+
+ +
+
+bool publishOnDataTopic(const __FlashStringHelper *topic, const uint8_t *payload, const uint16_t length, bool retained = false, bool isProgmemData = false)
+

Publishes the given data on the data topic.

+
+
Parameters
+
    +
  • topic – The topic to publish on (progmem string).

  • +
  • payload – The message’s payload.

  • +
  • length – The length of the payload.

  • +
  • retained – Specifies whether the message should be retained.

  • +
  • isProgmemData – Specifies whether the given data is stored in the flash memory.

  • +
+
+
+
+ +
+
+

Protected Attributes

+
+
+const __FlashStringHelper *const _componentName
+

The component name that was assigned via the constructor.

+
+ +
+
+const char *_uniqueId
+

The unique ID that was assigned via the constructor.

+
+ +
+
+const char *_name
+

The name that was set using setName method. It can be nullptr.

+
+ +
+
+HASerializer *_serializer
+

HASerializer that belongs to this device type. It can be nullptr.

+
+ +
+
+

Protected Static Functions

+
+
+static HAMqtt *mqtt()
+

Returns instance of the HAMqtt class.

+
+ +
+
+static void subscribeTopic(const char *uniqueId, const __FlashStringHelper *topic)
+

Subscribes to the given data topic.

+
+
Parameters
+
    +
  • uniqueId – THe unique ID of the device type assigned via the constructor.

  • +
  • topic – Topic to subscribe (progmem string).

  • +
+
+
+
+ +
+
+

Private Types

+
+
+enum Availability
+

Values:

+
+
+enumerator AvailabilityDefault
+
+ +
+
+enumerator AvailabilityOnline
+
+ +
+
+enumerator AvailabilityOffline
+
+ +
+ +
+
+

Private Members

+
+
+Availability _availability
+

The current availability of this device type. AvailabilityDefault means that the initial availability was never set.

+
+ +
+
+

Friends

+
+
+friend class HAMqtt
+
+ +
+
+ +
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/docs/documents/api/device-types/ha-binary-sensor.html b/docs/documents/api/device-types/ha-binary-sensor.html new file mode 100644 index 0000000..10f6756 --- /dev/null +++ b/docs/documents/api/device-types/ha-binary-sensor.html @@ -0,0 +1,309 @@ + + + + + + + HABinarySensor class - ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

HABinarySensor class

+
+
+class HABinarySensor : public HABaseDeviceType
+

HABinarySensor represents a binary sensor that allows publishing on/off state to the Home Assistant panel.

+
+

Note

+

You can find more information about this entity in the Home Assistant documentation: https://www.home-assistant.io/integrations/binary_sensor.mqtt/

+
+
+

Public Functions

+
+
+HABinarySensor(const char *uniqueId)
+
+
Parameters
+

uniqueId – The unique ID of the button. It needs to be unique in a scope of your device.

+
+
+
+ +
+
+bool setState(const bool state, const bool force = false)
+

Changes state of the sensor and publish MQTT message. Please note that if a new value is the same as the previous one the MQTT message won’t be published.

+
+
Parameters
+
    +
  • state – New state of the sensor (true - on, false - off).

  • +
  • force – Forces to update the state without comparing it to a previous known state.

  • +
+
+
Returns
+

Returns true if the MQTT message has been published successfully.

+
+
+
+ +
+
+inline void setCurrentState(const bool state)
+

Sets the current state of the sensor without publishing it to Home Assistant. This method may be useful if you want to change the state before the connection with the MQTT broker is acquired.

+
+
Parameters
+

state – New state of the sensor.

+
+
+
+ +
+
+inline bool getCurrentState() const
+

Returns the last known state of the sensor.

+
+ +
+
+inline void setDeviceClass(const char *deviceClass)
+

Sets class of the device. You can find list of available values here: https://www.home-assistant.io/integrations/binary_sensor/#device-class

+
+
Parameters
+

deviceClass – The class name.

+
+
+
+ +
+
+inline void setIcon(const char *icon)
+

Sets icon of the sensor. Any icon from MaterialDesignIcons.com (for example: mdi:home).

+
+
Parameters
+

icon – The icon name.

+
+
+
+ +
+
+

Protected Functions

+
+
+virtual void buildSerializer() override
+
+ +
+
+virtual void onMqttConnected() override
+
+ +
+
+

Private Functions

+
+
+bool publishState(bool state)
+

Publishes the MQTT message with the given state.

+
+
Parameters
+

state – The state to publish.

+
+
Returns
+

Returns true if the MQTT message has been published successfully.

+
+
+
+ +
+
+

Private Members

+
+
+const char *_class
+

The device class. It can be nullptr.

+
+ +
+
+const char *_icon
+

The icon of the sensor. It can be nullptr.

+
+ +
+
+bool _currentState
+

Current state of the sensor. By default it’s false.

+
+ +
+
+ +
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/docs/documents/api/device-types/ha-button.html b/docs/documents/api/device-types/ha-button.html new file mode 100644 index 0000000..b040a5d --- /dev/null +++ b/docs/documents/api/device-types/ha-button.html @@ -0,0 +1,291 @@ + + + + + + + HAButton class - ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

HAButton class

+
+
+class HAButton : public HABaseDeviceType
+

HAButton represents a button that’s displayed in the Home Assistant panel and triggers some logic on your Arduino/ESP device once clicked.

+
+

Note

+

You can find more information about this entity in the Home Assistant documentation: https://www.home-assistant.io/integrations/button.mqtt/

+
+
+

Public Functions

+
+
+HAButton(const char *uniqueId)
+
+
Parameters
+

uniqueId – The unique ID of the button. It needs to be unique in a scope of your device.

+
+
+
+ +
+
+inline void setDeviceClass(const char *deviceClass)
+

Sets class of the device. You can find list of available values here: https://www.home-assistant.io/integrations/button/#device-class

+
+
Parameters
+

deviceClass – The class name.

+
+
+
+ +
+
+inline void setIcon(const char *icon)
+

Sets icon of the button. Any icon from MaterialDesignIcons.com (for example: mdi:home).

+
+
Parameters
+

icon – The icon name.

+
+
+
+ +
+
+inline void setRetain(const bool retain)
+

Sets retain flag for the button’s command. If set to true the command produced by Home Assistant will be retained.

+
+
Parameters
+

retain –

+
+
+
+ +
+
+inline void onCommand(void (*callback)(HAButton *sender))
+

Registers callback that will be called each time the press command from HA is received. Please note that it’s not possible to register multiple callbacks for the same button.

+
+
Parameters
+

callback –

+
+
+
+ +
+
+

Protected Functions

+
+
+virtual void buildSerializer() override
+
+ +
+
+virtual void onMqttConnected() override
+
+ +
+
+virtual void onMqttMessage(const char *topic, const uint8_t *payload, const uint16_t length) override
+
+ +
+
+

Private Members

+
+
+const char *_class
+

The device class. It can be nullptr.

+
+ +
+
+const char *_icon
+

The icon of the button. It can be nullptr.

+
+ +
+
+bool _retain
+

The retain flag for the HA commands.

+
+ +
+
+void (*_commandCallback)(HAButton *sender)
+

The command callback that will be called once clicking the button in HA panel.

+
+ +
+
+ +
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/docs/documents/api/device-types/ha-camera.html b/docs/documents/api/device-types/ha-camera.html new file mode 100644 index 0000000..75b6253 --- /dev/null +++ b/docs/documents/api/device-types/ha-camera.html @@ -0,0 +1,297 @@ + + + + + + + HACamera class - ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

HACamera class

+
+
+class HACamera : public HABaseDeviceType
+

HACamera allows to display an image in the Home Assistant panel. It can be used for publishing an image from the ESP32-Cam module or any other module that’s equipped with a camera.

+
+

Note

+

You can find more information about this entity in the Home Assistant documentation: https://www.home-assistant.io/integrations/camera.mqtt/

+
+
+

Public Types

+
+
+enum ImageEncoding
+

Values:

+
+
+enumerator EncodingBinary
+
+ +
+
+enumerator EncodingBase64
+
+ +
+ +
+
+

Public Functions

+
+
+HACamera(const char *uniqueId)
+
+
Parameters
+

uniqueId – The unique ID of the camera. It needs to be unique in a scope of your device.

+
+
+
+ +
+
+bool publishImage(const uint8_t *data, const uint16_t length)
+

Publishes MQTT message with the given image data as a message content. It updates image displayed in the Home Assistant panel.

+
+
Parameters
+
    +
  • data – Image data (raw binary data or base64)

  • +
  • length – The length of the data.

  • +
+
+
Returns
+

Returns true if MQTT message has been published successfully.

+
+
+
+ +
+
+inline void setEncoding(const ImageEncoding encoding)
+

Sets encoding of the image content. Bu default Home Assistant expects raw binary data (e.g. JPEG binary data).

+
+
Parameters
+

encoding – The image’s data encoding.

+
+
+
+ +
+
+inline void setIcon(const char *icon)
+

Sets icon of the camera. Any icon from MaterialDesignIcons.com (for example: mdi:home).

+
+
Parameters
+

icon – The icon name.

+
+
+
+ +
+
+

Protected Functions

+
+
+virtual void buildSerializer() override
+
+ +
+
+virtual void onMqttConnected() override
+
+ +
+
+

Private Functions

+
+
+const __FlashStringHelper *getEncodingProperty() const
+

Returns progmem string representing the encoding property.

+
+ +
+
+

Private Members

+
+
+ImageEncoding _encoding
+

The encoding of the image’s data. By default it’s HACamera::EncodingBinary.

+
+ +
+
+const char *_icon
+

The icon of the camera. It can be nullptr.

+
+ +
+
+ +
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/docs/documents/api/device-types/ha-cover.html b/docs/documents/api/device-types/ha-cover.html new file mode 100644 index 0000000..64c5e6d --- /dev/null +++ b/docs/documents/api/device-types/ha-cover.html @@ -0,0 +1,526 @@ + + + + + + + HACover class - ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

HACover class

+
+
+class HACover : public HABaseDeviceType
+

HACover allows to control a cover (such as blinds, a roller shutter or a garage door).

+
+

Note

+

You can find more information about this entity in the Home Assistant documentation: https://www.home-assistant.io/integrations/cover.mqtt/

+
+
+

Public Types

+
+
+enum CoverState
+

Values:

+
+
+enumerator StateUnknown
+
+ +
+
+enumerator StateClosed
+
+ +
+
+enumerator StateClosing
+
+ +
+
+enumerator StateOpen
+
+ +
+
+enumerator StateOpening
+
+ +
+
+enumerator StateStopped
+
+ +
+ +
+
+enum CoverCommand
+

Values:

+
+
+enumerator CommandOpen
+
+ +
+
+enumerator CommandClose
+
+ +
+
+enumerator CommandStop
+
+ +
+ +
+
+enum Features
+

Values:

+
+
+enumerator DefaultFeatures
+
+ +
+
+enumerator PositionFeature
+
+ +
+ +
+
+

Public Functions

+
+
+HACover(const char *uniqueId, const Features features = DefaultFeatures)
+
+
Parameters
+
    +
  • uniqueId – The unique ID of the cover. It needs to be unique in a scope of your device.

  • +
  • features – Features that should be enabled for the fan.

  • +
+
+
+
+ +
+
+bool setState(const CoverState state, const bool force = false)
+

Changes state of the cover and publishes MQTT message. Please note that if a new value is the same as previous one, the MQTT message won’t be published.

+
+
Parameters
+
    +
  • state – New state of the cover.

  • +
  • force – Forces to update state without comparing it to previous known state.

  • +
+
+
Returns
+

Returns true if MQTT message has been published successfully.

+
+
+
+ +
+
+bool setPosition(const int16_t position, const bool force = false)
+

Changes the position of the cover and publishes MQTT message. Please note that if a new value is the same as previous one, the MQTT message won’t be published.

+
+
Parameters
+
    +
  • position – The new position of the cover (0-100).

  • +
  • force – Forces to update the state without comparing it to a previous known state.

  • +
+
+
Returns
+

Returns true if MQTT message has been published successfully.

+
+
+
+ +
+
+inline void setCurrentState(const CoverState state)
+

Sets the current state of the cover without publishing it to Home Assistant. This method may be useful if you want to change the state before the connection with the MQTT broker is acquired.

+
+
Parameters
+

state – The new state of the cover.

+
+
+
+ +
+
+inline CoverState getCurrentState() const
+

Returns last known state of the cover. By default the state is set to CoverState::StateUnknown

+
+ +
+
+inline void setCurrentPosition(const int16_t position)
+

Sets the current position of the cover without pushing the value to Home Assistant. This method may be useful if you want to change the position before the connection with the MQTT broker is acquired.

+
+
Parameters
+

position – The new position of the cover (0-100).

+
+
+
+ +
+
+inline int16_t getCurrentPosition() const
+

Returns the last known position of the cover. By default position is set to HACover::DefaultPosition

+
+ +
+
+inline void setDeviceClass(const char *deviceClass)
+

Sets class of the device. You can find list of available values here: https://www.home-assistant.io/integrations/cover/

+
+
Parameters
+

deviceClass – The class name.

+
+
+
+ +
+
+inline void setIcon(const char *icon)
+

Sets icon of the cover. Any icon from MaterialDesignIcons.com (for example: mdi:home).

+
+
Parameters
+

icon – The icon name.

+
+
+
+ +
+
+inline void setRetain(const bool retain)
+

Sets retain flag for the cover’s command. If set to true the command produced by Home Assistant will be retained.

+
+
Parameters
+

retain –

+
+
+
+ +
+
+inline void setOptimistic(const bool optimistic)
+

Sets optimistic flag for the cover state. In this mode the cover state doesn’t need to be reported back to the HA panel when a command is received. By default the optimistic mode is disabled.

+
+
Parameters
+

optimistic – The optimistic mode (true - enabled, false - disabled).

+
+
+
+ +
+
+inline void onCommand(void (*callback)(CoverCommand cmd, HACover *sender))
+

Registers callback that will be called each time the command from HA is received. Please note that it’s not possible to register multiple callbacks for the same cover.

+
+
Parameters
+

callback –

+
+
+
+ +
+
+

Public Static Attributes

+
+
+static const int16_t DefaultPosition = -32768
+
+ +
+
+

Protected Functions

+
+
+virtual void buildSerializer() override
+
+ +
+
+virtual void onMqttConnected() override
+
+ +
+
+virtual void onMqttMessage(const char *topic, const uint8_t *payload, const uint16_t length) override
+
+ +
+
+

Private Functions

+
+
+bool publishState(const CoverState state)
+

Publishes the MQTT message with the given state.

+
+
Parameters
+

state – The state to publish.

+
+
Returns
+

Returns true if the MQTT message has been published successfully.

+
+
+
+ +
+
+bool publishPosition(const int16_t position)
+

Publishes the MQTT message with the given position.

+
+
Parameters
+

position – The position to publish.

+
+
Returns
+

Returns true if the MQTT message has been published successfully.

+
+
+
+ +
+
+void handleCommand(const uint8_t *cmd, const uint16_t length)
+

Parses the given command and executes the cover’s callback with proper enum’s property.

+
+
Parameters
+
    +
  • cmd – The data of the command.

  • +
  • length – Length of the command.

  • +
+
+
+
+ +
+
+

Private Members

+
+
+const uint8_t _features
+

Features enabled for the cover.

+
+ +
+
+CoverState _currentState
+

The current state of the cover. By default it’s HACover::StateUnknown.

+
+ +
+
+int16_t _currentPosition
+

The current position of the cover. By default it’s HACover::DefaultPosition.

+
+ +
+
+const char *_class
+

The device class. It can be nullptr.

+
+ +
+
+const char *_icon
+

The icon of the button. It can be nullptr.

+
+ +
+
+bool _retain
+

The retain flag for the HA commands.

+
+ +
+
+bool _optimistic
+

The optimistic mode of the cover (true - enabled, false - disabled).

+
+ +
+
+void (*_commandCallback)(CoverCommand cmd, HACover *sender)
+

The command callback that will be called when clicking the cover’s button in the HA panel.

+
+ +
+
+ +
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/docs/documents/api/device-types/ha-device-tracker.html b/docs/documents/api/device-types/ha-device-tracker.html new file mode 100644 index 0000000..806803f --- /dev/null +++ b/docs/documents/api/device-types/ha-device-tracker.html @@ -0,0 +1,377 @@ + + + + + + + HADeviceTracker class - ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

HADeviceTracker class

+
+
+class HADeviceTracker : public HABaseDeviceType
+

HADeviceTracker allows to implement a custom device’s tracker.

+
+

Note

+

You can find more information about this entity in the Home Assistant documentation: https://www.home-assistant.io/integrations/device_tracker.mqtt/

+
+
+

Public Types

+
+
+enum SourceType
+

Available source types of the tracker.

+

Values:

+
+
+enumerator SourceTypeUnknown
+
+ +
+
+enumerator SourceTypeGPS
+
+ +
+
+enumerator SourceTypeRouter
+
+ +
+
+enumerator SourceTypeBluetooth
+
+ +
+
+enumerator SourceTypeBluetoothLE
+
+ +
+ +
+
+enum TrackerState
+

Available states that can be reported to the HA panel.

+

Values:

+
+
+enumerator StateUnknown
+
+ +
+
+enumerator StateHome
+
+ +
+
+enumerator StateNotHome
+
+ +
+
+enumerator StateNotAvailable
+
+ +
+ +
+
+

Public Functions

+
+
+HADeviceTracker(const char *uniqueId)
+
+
Parameters
+

uniqueId – The unique ID of the tracker. It needs to be unique in a scope of your device.

+
+
+
+ +
+
+bool setState(const TrackerState state, const bool force = false)
+

Changes the state of the tracker and publishes MQTT message. Please note that if a new value is the same as previous one, the MQTT message won’t be published.

+
+
Parameters
+
    +
  • state – The new state of the tracker.

  • +
  • force – Forces to update the state without comparing it to a previous known state.

  • +
+
+
Returns
+

Returns true if MQTT message has been published successfully.

+
+
+
+ +
+
+inline void setCurrentState(const TrackerState state)
+

Sets the current state of the tracker without publishing it to Home Assistant. This method may be useful if you want to change the state before connection with MQTT broker is acquired.

+
+
Parameters
+

state – The new state of the tracker.

+
+
+
+ +
+
+inline TrackerState getState() const
+

Returns the last known state of the tracker. If setState method wasn’t called the initial value will be returned.

+
+ +
+
+inline void setIcon(const char *icon)
+

Sets icon of the tracker. Any icon from MaterialDesignIcons.com (for example: mdi:home).

+
+
Parameters
+

icon – The icon name.

+
+
+
+ +
+
+inline void setSourceType(const SourceType type)
+

Sets the source type of the tracker.

+
+
Parameters
+

type – The source type (gps, router, bluetooth, bluetooth LE).

+
+
+
+ +
+
+

Protected Functions

+
+
+virtual void buildSerializer() override
+
+ +
+
+virtual void onMqttConnected() override
+
+ +
+
+

Private Functions

+
+
+bool publishState(TrackerState state)
+

Publishes the MQTT message with the given state.

+
+
Parameters
+

state – The state to publish.

+
+
Returns
+

Returns true if the MQTT message has been published successfully.

+
+
+
+ +
+
+const __FlashStringHelper *getSourceTypeProperty() const
+

Returns progmem string representing source type of the tracker.

+
+ +
+
+

Private Members

+
+
+const char *_icon
+

The icon of the tracker. It can be nullptr.

+
+ +
+
+SourceType _sourceType
+

The source type of the tracker. By default it’s HADeviceTracker::SourceTypeUnknown.

+
+ +
+
+TrackerState _currentState
+

The current state of the device’s tracker. By default its HADeviceTracker::StateUnknown.

+
+ +
+
+ +
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/docs/documents/api/device-types/ha-device-trigger.html b/docs/documents/api/device-types/ha-device-trigger.html new file mode 100644 index 0000000..6a15937 --- /dev/null +++ b/docs/documents/api/device-types/ha-device-trigger.html @@ -0,0 +1,479 @@ + + + + + + + HADeviceTrigger class - ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

HADeviceTrigger class

+
+
+class HADeviceTrigger : public HABaseDeviceType
+

HADeviceTrigger allows to a custom trigger that can be used in the Home Assistant automation. For example, it can be a wall switch that produces press and long_press actions.

+
+

Note

+

You can find more information about this entity in the Home Assistant documentation: https://www.home-assistant.io/integrations/device_trigger.mqtt/

+
+
+

Public Types

+
+
+enum TriggerType
+

Built-in types of the trigger.

+

Values:

+
+
+enumerator ButtonShortPressType
+
+ +
+
+enumerator ButtonShortReleaseType
+
+ +
+
+enumerator ButtonLongPressType
+
+ +
+
+enumerator ButtonLongReleaseType
+
+ +
+
+enumerator ButtonDoublePressType
+
+ +
+
+enumerator ButtonTriplePressType
+
+ +
+
+enumerator ButtonQuadruplePressType
+
+ +
+
+enumerator ButtonQuintuplePressType
+
+ +
+ +
+
+enum TriggerSubtype
+

Built-in subtypes of the trigger.

+

Values:

+
+
+enumerator TurnOnSubtype
+
+ +
+
+enumerator TurnOffSubtype
+
+ +
+
+enumerator Button1Subtype
+
+ +
+
+enumerator Button2Subtype
+
+ +
+
+enumerator Button3Subtype
+
+ +
+
+enumerator Button4Subtype
+
+ +
+
+enumerator Button5Subtype
+
+ +
+
+enumerator Button6Subtype
+
+ +
+ +
+
+

Public Functions

+
+
+HADeviceTrigger(const char *type, const char *subtype)
+

Creates the device trigger with a custom type and subtype. For example, it can be click as the type and btn0 as the subtype. Please note that combination of the type and subtype needs to be unique in a scope of your device.

+
+
Parameters
+
    +
  • type – String representation of the type.

  • +
  • subtype – String representation of the subtype.

  • +
+
+
+
+ +
+
+HADeviceTrigger(TriggerType type, const char *subtype)
+

Creates the device trigger with a built-in type and a custom subtype. For example, it can be HADeviceTrigger::ButtonShortPressType as the type and btn0 as the subtype. Please note that combination of the type and subtype needs to be unique in a scope of your device.

+
+
Parameters
+
    +
  • type – Built-in type of the trigger.

  • +
  • subtype – String representation of the subtype.

  • +
+
+
+
+ +
+
+HADeviceTrigger(const char *type, TriggerSubtype subtype)
+

Creates the device trigger with a custom type and a built-in subtype. For example, it can be click as the type and HADeviceTrigger::Button1Subtype as the subtype. Please note that combination of the type and subtype needs to be unique in a scope of your device.

+
+
Parameters
+
    +
  • type – String representation of the subtype.

  • +
  • subtype – Built-in subtype of the trigger.

  • +
+
+
+
+ +
+
+HADeviceTrigger(TriggerType type, TriggerSubtype subtype)
+

Creates the device trigger with a built-in type and built-in subtype. For example, it can be HADeviceTrigger::ButtonShortPressType as the type and HADeviceTrigger::Button1Subtype as the subtype. Please note that combination of the type and subtype needs to be unique in a scope of your device.

+
+
Parameters
+
    +
  • type – Built-in type of the trigger.

  • +
  • subtype – Built-in subtype of the trigger.

  • +
+
+
+
+ +
+
+~HADeviceTrigger()
+

Frees memory allocated by the class.

+
+ +
+
+bool trigger()
+

Publishes MQTT message with the trigger event. The published message is not retained.

+
+
Returns
+

Returns true if MQTT message has been published successfully.

+
+
+
+ +
+
+inline const char *getType() const
+

Returns the type of the trigger. If the built-in type is used the returned value points to the flash memory. Use HADeviceTrigger::isProgmemType to verify if the returned value is the progmem pointer.

+
+
Returns
+

Pointer to the type.

+
+
+
+ +
+
+inline bool isProgmemType() const
+

Returns true if the built-in type was assigned to the trigger.

+
+ +
+
+inline const char *getSubtype() const
+

Returns the subtype of the trigger. If the built-in subtype is used the returned value points to the flash memory. Use HADeviceTrigger::isProgmemSubtype to verify if the returned value is the progmem pointer.

+
+
Returns
+

Pointer to the subtype.

+
+
+
+ +
+
+inline bool isProgmemSubtype() const
+

Returns true if the built-in subtype was assigned to the trigger.

+
+ +
+
+

Protected Functions

+
+
+virtual void buildSerializer() override
+
+ +
+
+virtual void onMqttConnected() override
+
+ +
+
+

Private Functions

+
+
+uint16_t calculateIdSize() const
+

Calculates desired size of the unique ID based on the type and subtype that were passed to the constructor.

+
+ +
+
+void buildUniqueId()
+

Builds the unique ID of the device’s type based on the type and subtype that were passed to the constructor.

+
+ +
+
+const char *determineProgmemType(TriggerType type) const
+

Returns pointer to the flash memory that represents the given type.

+
+
Parameters
+

subtype – Built-in type enum’s value.

+
+
Returns
+

Pointer to the flash memory if the given type is supported. For the unsupported type the nullptr is returned.

+
+
+
+ +
+
+const char *determineProgmemSubtype(TriggerSubtype subtype) const
+

Returns pointer to the flash memory that represents the given subtype.

+
+
Parameters
+

subtype – Built-in subtype enum’s value.

+
+
Returns
+

Pointer to the flash memory if the given subtype is supported. For the unsupported subtype the nullptr is returned.

+
+
+
+ +
+
+

Private Members

+
+
+const char *_type
+

Pointer to the trigger’s type. It can be pointer to the flash memory.

+
+ +
+
+const char *_subtype
+

Pointer to the trigger’s subtype. It can be pointer to the flash memory.

+
+ +
+
+bool _isProgmemType
+

Specifies whether the type points to the flash memory.

+
+ +
+
+bool _isProgmemSubtype
+

Specifies whether the subtype points to the flash memory.

+
+ +
+
+ +
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/docs/documents/api/device-types/ha-fan.html b/docs/documents/api/device-types/ha-fan.html new file mode 100644 index 0000000..f43e999 --- /dev/null +++ b/docs/documents/api/device-types/ha-fan.html @@ -0,0 +1,529 @@ + + + + + + + HAFan class - ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

HAFan class

+
+
+class HAFan : public HABaseDeviceType
+

HAFan allows adding a controllable fan in the Home Assistant panel. The library supports only the state and speed of the fan. If you want more features please open a new GitHub issue.

+
+

Note

+

You can find more information about this entity in the Home Assistant documentation: https://www.home-assistant.io/integrations/fan.mqtt/

+
+
+

Public Types

+
+
+enum Features
+

Values:

+
+
+enumerator DefaultFeatures
+
+ +
+
+enumerator SpeedsFeature
+
+ +
+ +
+
+

Public Functions

+
+
+HAFan(const char *uniqueId, const uint8_t features = DefaultFeatures)
+
+
Parameters
+
    +
  • uniqueId – The unique ID of the fan. It needs to be unique in a scope of your device.

  • +
  • features – Features that should be enabled for the fan.

  • +
+
+
+
+ +
+
+bool setState(const bool state, const bool force = false)
+

Changes state of the fan and publishes MQTT message. Please note that if a new value is the same as previous one, the MQTT message won’t be published.

+
+
Parameters
+
    +
  • state – New state of the fan.

  • +
  • force – Forces to update state without comparing it to previous known state.

  • +
+
+
Returns
+

Returns true if MQTT message has been published successfully.

+
+
+
+ +
+
+bool setSpeed(const uint16_t speed, const bool force = false)
+

Changes the speed of the fan and publishes MQTT message. Please note that if a new value is the same as previous one, the MQTT message won’t be published.

+
+
Parameters
+
    +
  • speed – The new speed of the fan. It should be in range of min and max value.

  • +
  • force – Forces to update the value without comparing it to a previous known value.

  • +
+
+
Returns
+

Returns true if MQTT message has been published successfully.

+
+
+
+ +
+
+inline bool turnOn()
+

Alias for setState(true).

+
+ +
+
+inline bool turnOff()
+

Alias for setState(false).

+
+ +
+
+inline void setCurrentState(const bool state)
+

Sets current state of the fan without publishing it to Home Assistant. This method may be useful if you want to change state before connection with MQTT broker is acquired.

+
+
Parameters
+

state – New state of the fan.

+
+
+
+ +
+
+inline bool getCurrentState() const
+

Returns last known state of the fan. By default it’s false.

+
+ +
+
+inline void setCurrentSpeed(const uint16_t speed)
+

Sets the current speed of the fan without pushing the value to Home Assistant. This method may be useful if you want to change the speed before the connection with the MQTT broker is acquired.

+
+
Parameters
+

speed – The new speed of the fan. It should be in range of min and max value.

+
+
+
+ +
+
+inline uint16_t getCurrentSpeed() const
+

Returns the last known speed of the fan. By default speed is set to 0.

+
+ +
+
+inline void setIcon(const char *icon)
+

Sets icon of the fan. Any icon from MaterialDesignIcons.com (for example: mdi:home).

+
+
Parameters
+

icon – The icon name.

+
+
+
+ +
+
+inline void setRetain(const bool retain)
+

Sets retain flag for the fan’s command. If set to true the command produced by Home Assistant will be retained.

+
+
Parameters
+

retain –

+
+
+
+ +
+
+inline void setOptimistic(const bool optimistic)
+

Sets optimistic flag for the fan state. In this mode the fan state doesn’t need to be reported back to the HA panel when a command is received. By default the optimistic mode is disabled.

+
+
Parameters
+

optimistic – The optimistic mode (true - enabled, false - disabled).

+
+
+
+ +
+
+inline void setSpeedRangeMax(const uint16_t max)
+

Sets the maximum of numeric output range (representing 100%). The number of speeds within the speed_range / 100 will determine the percentage step. By default the maximum range is 100.

+
+
Parameters
+

max – The maximum of numeric output range.

+
+
+
+ +
+
+inline void setSpeedRangeMin(const uint16_t min)
+

Sets the minimum of numeric output range (off is not included, so speed_range_min - 1 represents 0 %). The number of speeds within the speed_range / 100 will determine the percentage step. By default the minimum range is 1.

+
+
Parameters
+

min – The minimum of numeric output range.

+
+
+
+ +
+
+inline void onStateCommand(void (*callback)(bool state, HAFan *sender))
+

Registers callback that will be called each time the state command from HA is received. Please note that it’s not possible to register multiple callbacks for the same fan.

+
+

Note

+

In non-optimistic mode, the state must be reported back to HA using the HAFan::setState method.

+
+
+
Parameters
+

callback –

+
+
+
+ +
+
+inline void onSpeedCommand(void (*callback)(uint16_t speed, HAFan *sender))
+

Registers callback that will be called each time the speed command from HA is received. Please note that it’s not possible to register multiple callbacks for the same fan.

+
+

Note

+

In non-optimistic mode, the speed must be reported back to HA using the HAFan::setSpeed method.

+
+
+
Parameters
+

callback –

+
+
+
+ +
+
+

Protected Functions

+
+
+virtual void buildSerializer() override
+
+ +
+
+virtual void onMqttConnected() override
+
+ +
+
+virtual void onMqttMessage(const char *topic, const uint8_t *payload, const uint16_t length) override
+
+ +
+
+

Private Functions

+
+
+bool publishState(const bool state)
+

Publishes the MQTT message with the given state.

+
+
Parameters
+

state – The state to publish.

+
+
Returns
+

Returns true if the MQTT message has been published successfully.

+
+
+
+ +
+
+bool publishSpeed(const uint16_t speed)
+

Publishes the MQTT message with the given speed.

+
+
Parameters
+

speed – The speed to publish. It should be in range of min and max value.

+
+
Returns
+

Returns true if the MQTT message has been published successfully.

+
+
+
+ +
+
+void handleStateCommand(const uint8_t *cmd, const uint16_t length)
+

Parses the given state command and executes the callback with proper value.

+
+
Parameters
+
    +
  • cmd – The data of the command.

  • +
  • length – Length of the command.

  • +
+
+
+
+ +
+
+void handleSpeedCommand(const uint8_t *cmd, const uint16_t length)
+

Parses the given speed command and executes the callback with proper value.

+
+
Parameters
+
    +
  • cmd – The data of the command.

  • +
  • length – Length of the command.

  • +
+
+
+
+ +
+
+

Private Members

+
+
+const uint8_t _features
+

Features enabled for the fan.

+
+ +
+
+const char *_icon
+

The icon of the button. It can be nullptr.

+
+ +
+
+bool _retain
+

The retain flag for the HA commands.

+
+ +
+
+bool _optimistic
+

The optimistic mode of the fan (true - enabled, false - disabled).

+
+ +
+
+HANumeric _speedRangeMax
+

The maximum of numeric output range.

+
+ +
+
+HANumeric _speedRangeMin
+

The minimum of numeric output range.

+
+ +
+
+bool _currentState
+

The current state of the fan. By default it’s false.

+
+ +
+
+uint16_t _currentSpeed
+

The current speed of the fan. By default it’s 0.

+
+ +
+
+void (*_stateCallback)(bool state, HAFan *sender)
+

The callback that will be called when the state command is received from the HA.

+
+ +
+
+void (*_speedCallback)(uint16_t speed, HAFan *sender)
+

The callback that will be called when the speed command is received from the HA.

+
+ +
+
+ +
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/docs/documents/api/device-types/ha-hvac.html b/docs/documents/api/device-types/ha-hvac.html new file mode 100644 index 0000000..acec067 --- /dev/null +++ b/docs/documents/api/device-types/ha-hvac.html @@ -0,0 +1,1405 @@ + + + + + + + HAHVAC class - ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

HAHVAC class

+
+
+class HAHVAC : public HABaseDeviceType
+

HAHVAC lets you control your HVAC devices.

+
+

Note

+

You can find more information about this entity in the Home Assistant documentation: https://www.home-assistant.io/integrations/climate.mqtt/

+
+
+

Public Types

+
+
+enum Features
+

The list of features available in the HVAC. They’re used in the constructor.

+

Values:

+
+
+enumerator DefaultFeatures
+
+ +
+
+enumerator ActionFeature
+
+ +
+
+enumerator AuxHeatingFeature
+
+ +
+
+enumerator PowerFeature
+
+ +
+
+enumerator FanFeature
+
+ +
+
+enumerator SwingFeature
+
+ +
+
+enumerator ModesFeature
+
+ +
+
+enumerator TargetTemperatureFeature
+
+ +
+ +
+
+enum Action
+

The list of available actions of the HVAC.

+

Values:

+
+
+enumerator UnknownAction
+
+ +
+
+enumerator OffAction
+
+ +
+
+enumerator HeatingAction
+
+ +
+
+enumerator CoolingAction
+
+ +
+
+enumerator DryingAction
+
+ +
+
+enumerator IdleAction
+
+ +
+
+enumerator FanAction
+
+ +
+ +
+
+enum FanMode
+

The list of available fan modes.

+

Values:

+
+
+enumerator UnknownFanMode
+
+ +
+
+enumerator AutoFanMode
+
+ +
+
+enumerator LowFanMode
+
+ +
+
+enumerator MediumFanMode
+
+ +
+
+enumerator HighFanMode
+
+ +
+ +
+
+enum SwingMode
+

The list of available swing modes.

+

Values:

+
+
+enumerator UnknownSwingMode
+
+ +
+
+enumerator OnSwingMode
+
+ +
+
+enumerator OffSwingMode
+
+ +
+ +
+
+enum Mode
+

The list of available HVAC’s modes.

+

Values:

+
+
+enumerator UnknownMode
+
+ +
+
+enumerator AutoMode
+
+ +
+
+enumerator OffMode
+
+ +
+
+enumerator CoolMode
+
+ +
+
+enumerator HeatMode
+
+ +
+
+enumerator DryMode
+
+ +
+
+enumerator FanOnlyMode
+
+ +
+ +
+
+enum TemperatureUnit
+

Temperature units available in the HVAC.

+

Values:

+
+
+enumerator DefaultUnit
+
+ +
+
+enumerator CelsiusUnit
+
+ +
+
+enumerator FahrenheitUnit
+
+ +
+ +
+
+

Public Functions

+
+
+HAHVAC(const char *uniqueId, const uint16_t features = DefaultFeatures, const NumberPrecision precision = PrecisionP1)
+
+
Parameters
+
    +
  • uniqueId – The unique ID of the HVAC. It needs to be unique in a scope of your device.

  • +
  • features – Features that should be enabled for the HVAC.

  • +
  • precision – The precision of temperatures reported by the HVAC.

  • +
+
+
+
+ +
+
+~HAHVAC()
+

Frees memory allocated for the arrays serialization.

+
+ +
+
+bool setCurrentTemperature(const HANumeric &temperature, const bool force = false)
+

Changes current temperature of the HVAC and publishes MQTT message. Please note that if a new value is the same as previous one, the MQTT message won’t be published.

+
+
Parameters
+
    +
  • temperature – New current temperature.

  • +
  • force – Forces to update the temperature without comparing it to a previous known value.

  • +
+
+
Returns
+

Returns true if MQTT message has been published successfully.

+
+
+
+ +
+
+inline bool setCurrentTemperature(const int8_t temperature, const bool force = false)
+

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

+
+ +
+
+inline bool setCurrentTemperature(const int16_t temperature, const bool force = false)
+

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

+
+ +
+
+inline bool setCurrentTemperature(const int32_t temperature, const bool force = false)
+

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

+
+ +
+
+inline bool setCurrentTemperature(const uint8_t temperature, const bool force = false)
+

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

+
+ +
+
+inline bool setCurrentTemperature(const uint16_t temperature, const bool force = false)
+

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

+
+ +
+
+inline bool setCurrentTemperature(const uint32_t temperature, const bool force = false)
+

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

+
+ +
+
+inline bool setCurrentTemperature(const float temperature, const bool force = false)
+

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

+
+ +
+
+bool setAction(const Action action, const bool force = false)
+

Changes action of the HVAC and publishes MQTT message. Please note that if a new value is the same as previous one, the MQTT message won’t be published.

+
+
Parameters
+
    +
  • action – New action.

  • +
  • force – Forces to update the action without comparing it to a previous known value.

  • +
+
+
Returns
+

Returns true if MQTT message has been published successfully.

+
+
+
+ +
+
+bool setAuxState(const bool state, const bool force = false)
+

Changes state of the aux heating and publishes MQTT message. Please note that if a new value is the same as previous one, the MQTT message won’t be published.

+
+
Parameters
+
    +
  • state – The new state.

  • +
  • force – Forces to update the state without comparing it to a previous known value.

  • +
+
+
Returns
+

Returns true if MQTT message has been published successfully.

+
+
+
+ +
+
+bool setFanMode(const FanMode mode, const bool force = false)
+

Changes mode of the fan of the HVAC and publishes MQTT message. Please note that if a new value is the same as previous one, the MQTT message won’t be published.

+
+
Parameters
+
    +
  • mode – New fan’s mode.

  • +
  • force – Forces to update the mode without comparing it to a previous known value.

  • +
+
+
Returns
+

Returns true if MQTT message has been published successfully.

+
+
+
+ +
+
+bool setSwingMode(const SwingMode mode, const bool force = false)
+

Changes swing mode of the HVAC and publishes MQTT message. Please note that if a new value is the same as previous one, the MQTT message won’t be published.

+
+
Parameters
+
    +
  • mode – New swing mode.

  • +
  • force – Forces to update the mode without comparing it to a previous known value.

  • +
+
+
Returns
+

Returns true if MQTT message has been published successfully.

+
+
+
+ +
+
+bool setMode(const Mode mode, const bool force = false)
+

Changes mode of the HVAC and publishes MQTT message. Please note that if a new value is the same as previous one, the MQTT message won’t be published.

+
+
Parameters
+
    +
  • mode – New HVAC’s mode.

  • +
  • force – Forces to update the mode without comparing it to a previous known value.

  • +
+
+
Returns
+

Returns true if MQTT message has been published successfully.

+
+
+
+ +
+
+bool setTargetTemperature(const HANumeric &temperature, const bool force = false)
+

Changes target temperature of the HVAC and publishes MQTT message. Please note that if a new value is the same as previous one, the MQTT message won’t be published.

+
+
Parameters
+
    +
  • temperature – Target temperature to set.

  • +
  • force – Forces to update the mode without comparing it to a previous known value.

  • +
+
+
Returns
+

Returns true if MQTT message has been published successfully.

+
+
+
+ +
+
+inline bool setTargetTemperature(const int8_t temperature, const bool force = false)
+

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

+
+ +
+
+inline bool setTargetTemperature(const int16_t temperature, const bool force = false)
+

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

+
+ +
+
+inline bool setTargetTemperature(const int32_t temperature, const bool force = false)
+

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

+
+ +
+
+inline bool setTargetTemperature(const uint8_t temperature, const bool force = false)
+

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

+
+ +
+
+inline bool setTargetTemperature(const uint16_t temperature, const bool force = false)
+

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

+
+ +
+
+inline bool setTargetTemperature(const uint32_t temperature, const bool force = false)
+

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

+
+ +
+
+inline bool setTargetTemperature(const float temperature, const bool force = false)
+

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

+
+ +
+
+inline void setCurrentCurrentTemperature(const HANumeric &temperature)
+

Sets current temperature of the HVAC without publishing it to Home Assistant. This method may be useful if you want to change temperature before connection with MQTT broker is acquired.

+
+
Parameters
+

temperature – New current temperature.

+
+
+
+ +
+
+inline void setCurrentCurrentTemperature(const int8_t temperature)
+

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

+
+ +
+
+inline void setCurrentCurrentTemperature(const int16_t temperature)
+

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

+
+ +
+
+inline void setCurrentCurrentTemperature(const int32_t temperature)
+

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

+
+ +
+
+inline void setCurrentCurrentTemperature(const uint8_t temperature)
+

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

+
+ +
+
+inline void setCurrentCurrentTemperature(const uint16_t temperature)
+

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

+
+ +
+
+inline void setCurrentCurrentTemperature(const uint32_t temperature)
+

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

+
+ +
+
+inline void setCurrentCurrentTemperature(const float temperature)
+

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

+
+ +
+
+inline const HANumeric &getCurrentTemperature() const
+

Returns last known current temperature of the HVAC. If setCurrentTemperature method wasn’t called the initial value will be returned.

+
+ +
+
+inline void setCurrentAction(const Action action)
+

Sets action of the HVAC without publishing it to Home Assistant. This method may be useful if you want to change the action before connection with MQTT broker is acquired.

+
+
Parameters
+

action – New action.

+
+
+
+ +
+
+inline Action getCurrentAction() const
+

Returns last known action of the HVAC. If setAction method wasn’t called the initial value will be returned.

+
+ +
+
+inline void setCurrentAuxState(const bool state)
+

Sets aux heating state without publishing it to Home Assistant. This method may be useful if you want to change the state before connection with MQTT broker is acquired.

+
+
Parameters
+

state – The new state.

+
+
+
+ +
+
+inline bool getCurrentAuxState() const
+

Returns last known state of the aux heating. If setAuxState method wasn’t called the initial value will be returned.

+
+ +
+
+inline void setCurrentFanMode(const FanMode mode)
+

Sets fan’s mode of the HVAC without publishing it to Home Assistant. This method may be useful if you want to change the mode before connection with MQTT broker is acquired.

+
+
Parameters
+

mode – New fan’s mode.

+
+
+
+ +
+
+inline FanMode getCurrentFanMode() const
+

Returns last known fan’s mode of the HVAC. If setFanMode method wasn’t called the initial value will be returned.

+
+ +
+
+inline void setFanModes(const uint8_t modes)
+

Sets available fan modes.

+
+
Parameters
+

modes – The modes to set (for example: HAHVAC::AutoFanMode | HAHVAC::HighFanMode).

+
+
+
+ +
+
+inline void setCurrentSwingMode(const SwingMode mode)
+

Sets swing mode of the HVAC without publishing it to Home Assistant. This method may be useful if you want to change the mode before connection with MQTT broker is acquired.

+
+
Parameters
+

mode – New swing mode.

+
+
+
+ +
+
+inline SwingMode getCurrentSwingMode() const
+

Returns last known swing mode of the HVAC. If setSwingMode method wasn’t called the initial value will be returned.

+
+ +
+
+inline void setSwingModes(const uint8_t modes)
+

Sets available swing modes.

+
+
Parameters
+

modes – The modes to set (for example: HAHVAC::OnSwingMode).

+
+
+
+ +
+
+inline void setCurrentMode(const Mode mode)
+

Sets mode of the HVAC without publishing it to Home Assistant. This method may be useful if you want to change the mode before connection with MQTT broker is acquired.

+
+
Parameters
+

mode – New HVAC’s mode.

+
+
+
+ +
+
+inline Mode getCurrentMode() const
+

Returns last known mode of the HVAC. If setMode method wasn’t called the initial value will be returned.

+
+ +
+
+inline void setModes(const uint8_t modes)
+

Sets available HVAC’s modes.

+
+
Parameters
+

modes – The modes to set (for example: HAHVAC::CoolMode | HAHVAC::HeatMode).

+
+
+
+ +
+
+inline void setCurrentTargetTemperature(const HANumeric &temperature)
+

Sets target temperature of the HVAC without publishing it to Home Assistant. This method may be useful if you want to change the target before connection with MQTT broker is acquired.

+
+
Parameters
+

temperature – Target temperature to set.

+
+
+
+ +
+
+inline void setCurrentTargetTemperature(const int8_t temperature)
+

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

+
+ +
+
+inline void setCurrentTargetTemperature(const int16_t temperature)
+

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

+
+ +
+
+inline void setCurrentTargetTemperature(const int32_t temperature)
+

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

+
+ +
+
+inline void setCurrentTargetTemperature(const uint8_t temperature)
+

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

+
+ +
+
+inline void setCurrentTargetTemperature(const uint16_t temperature)
+

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

+
+ +
+
+inline void setCurrentTargetTemperature(const uint32_t temperature)
+

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

+
+ +
+
+inline void setCurrentTargetTemperature(const float temperature)
+

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

+
+ +
+
+inline const HANumeric &getCurrentTargetTemperature() const
+

Returns last known target temperature of the HVAC. If setTargetTemperature method wasn’t called the initial value will be returned.

+
+ +
+
+inline void setIcon(const char *icon)
+

Sets icon of the HVAC. Any icon from MaterialDesignIcons.com (for example: mdi:home).

+
+
Parameters
+

icon – The icon name.

+
+
+
+ +
+
+inline void setRetain(const bool retain)
+

Sets retain flag for the HVAC’s command. If set to true the command produced by Home Assistant will be retained.

+
+
Parameters
+

retain –

+
+
+
+ +
+
+inline void setTemperatureUnit(TemperatureUnit unit)
+

Changes the temperature unit.

+
+
Parameters
+

unit – See the TemperatureUnit enum above.

+
+
+
+ +
+
+inline void setMinTemp(const float min)
+

Sets the minimum temperature that can be set from the Home Assistant panel.

+
+
Parameters
+

min – The minimum value.

+
+
+
+ +
+
+inline void setMaxTemp(const float max)
+

Sets the maximum temperature that can be set from the Home Assistant panel.

+
+
Parameters
+

min – The maximum value.

+
+
+
+ +
+
+inline void setTempStep(const float step)
+

Sets the step of the temperature that can be set from the Home Assistant panel.

+
+
Parameters
+

step – The setp value. By default it’s 1.

+
+
+
+ +
+
+inline void onAuxStateCommand(void (*callback)(bool state, HAHVAC *sender))
+

Registers callback that will be called each time the aux state command from HA is received. Please note that it’s not possible to register multiple callbacks for the same HVAC.

+
+

Note

+

The aux state must be reported back to HA using the HAHVAC::setAuxState method.

+
+
+
Parameters
+

callback –

+
+
+
+ +
+
+inline void onPowerCommand(void (*callback)(bool state, HAHVAC *sender))
+

Registers callback that will be called each time the power command from HA is received. Please note that it’s not possible to register multiple callbacks for the same HVAC.

+
+
Parameters
+

callback –

+
+
+
+ +
+
+inline void onFanModeCommand(void (*callback)(FanMode mode, HAHVAC *sender))
+

Registers callback that will be called each time the fan mode command from HA is received. Please note that it’s not possible to register multiple callbacks for the same HVAC.

+
+

Note

+

The fan mode must be reported back to HA using the HAHVAC::setFanMode method.

+
+
+
Parameters
+

callback –

+
+
+
+ +
+
+inline void onSwingModeCommand(void (*callback)(SwingMode mode, HAHVAC *sender))
+

Registers callback that will be called each time the swing mode command from HA is received. Please note that it’s not possible to register multiple callbacks for the same HVAC.

+
+

Note

+

The swing mode must be reported back to HA using the HAHVAC::setSwingMode method.

+
+
+
Parameters
+

callback –

+
+
+
+ +
+
+inline void onModeCommand(void (*callback)(Mode mode, HAHVAC *sender))
+

Registers callback that will be called each time the HVAC mode command from HA is received. Please note that it’s not possible to register multiple callbacks for the same HVAC.

+
+

Note

+

The mode must be reported back to HA using the HAHVAC::setMode method.

+
+
+
Parameters
+

callback –

+
+
+
+ +
+
+inline void onTargetTemperatureCommand(void (*callback)(HANumeric temperature, HAHVAC *sender))
+

Registers callback that will be called each time the target temperature is set via HA panel. Please note that it’s not possible to register multiple callbacks for the same HVAC.

+
+

Note

+

The target temperature must be reported back to HA using the HAHVAC::setTargetTemperature method.

+
+
+
Parameters
+

callback –

+
+
+
+ +
+
+

Public Static Attributes

+
+
+static const uint8_t DefaultFanModes
+
+ +
+
+static const uint8_t DefaultSwingModes
+
+ +
+
+static const uint8_t DefaultModes
+
+ +
+
+

Protected Functions

+
+
+virtual void buildSerializer() override
+
+ +
+
+virtual void onMqttConnected() override
+
+ +
+
+virtual void onMqttMessage(const char *topic, const uint8_t *payload, const uint16_t length) override
+
+ +
+
+

Private Functions

+
+
+bool publishCurrentTemperature(const HANumeric &temperature)
+

Publishes the MQTT message with the given current temperature.

+
+
Parameters
+

temperature – The temperature to publish.

+
+
Returns
+

Returns true if the MQTT message has been published successfully.

+
+
+
+ +
+
+bool publishAction(const Action action)
+

Publishes the MQTT message with the given action.

+
+
Parameters
+

action – The action to publish.

+
+
Returns
+

Returns true if the MQTT message has been published successfully.

+
+
+
+ +
+
+bool publishAuxState(const bool state)
+

Publishes the MQTT message with the given aux heating state.

+
+
Parameters
+

state – The state to publish.

+
+
Returns
+

Returns true if the MQTT message has been published successfully.

+
+
+
+ +
+
+bool publishFanMode(const FanMode mode)
+

Publishes the MQTT message with the given fan mode.

+
+
Parameters
+

mode – The mode to publish.

+
+
Returns
+

Returns true if the MQTT message has been published successfully.

+
+
+
+ +
+
+bool publishSwingMode(const SwingMode mode)
+

Publishes the MQTT message with the given swing mode.

+
+
Parameters
+

mode – The mode to publish.

+
+
Returns
+

Returns true if the MQTT message has been published successfully.

+
+
+
+ +
+
+bool publishMode(const Mode mode)
+

Publishes the MQTT message with the given mode.

+
+
Parameters
+

mode – The mode to publish.

+
+
Returns
+

Returns true if the MQTT message has been published successfully.

+
+
+
+ +
+
+bool publishTargetTemperature(const HANumeric &temperature)
+

Publishes the MQTT message with the given target temperature.

+
+
Parameters
+

temperature – The temperature to publish.

+
+
Returns
+

Returns true if the MQTT message has been published successfully.

+
+
+
+ +
+
+void handleAuxStateCommand(const uint8_t *cmd, const uint16_t length)
+

Parses the given aux state command and executes the callback with proper value.

+
+
Parameters
+
    +
  • cmd – The data of the command.

  • +
  • length – Length of the command.

  • +
+
+
+
+ +
+
+void handlePowerCommand(const uint8_t *cmd, const uint16_t length)
+

Parses the given power command and executes the callback with proper value.

+
+
Parameters
+
    +
  • cmd – The data of the command.

  • +
  • length – Length of the command.

  • +
+
+
+
+ +
+
+void handleFanModeCommand(const uint8_t *cmd, const uint16_t length)
+

Parses the given fan mode command and executes the callback with proper value.

+
+
Parameters
+
    +
  • cmd – The data of the command.

  • +
  • length – Length of the command.

  • +
+
+
+
+ +
+
+void handleSwingModeCommand(const uint8_t *cmd, const uint16_t length)
+

Parses the given swing mode command and executes the callback with proper value.

+
+
Parameters
+
    +
  • cmd – The data of the command.

  • +
  • length – Length of the command.

  • +
+
+
+
+ +
+
+void handleModeCommand(const uint8_t *cmd, const uint16_t length)
+

Parses the given HVAC’s mode command and executes the callback with proper value.

+
+
Parameters
+
    +
  • cmd – The data of the command.

  • +
  • length – Length of the command.

  • +
+
+
+
+ +
+
+void handleTargetTemperatureCommand(const uint8_t *cmd, const uint16_t length)
+

Parses the given HVAC’s target temperature command and executes the callback with proper value.

+
+
Parameters
+
    +
  • cmd – The data of the command.

  • +
  • length – Length of the command.

  • +
+
+
+
+ +
+
+const __FlashStringHelper *getCommandWithFloatTemplate()
+

Returns progmem string representing value template for the command that contains floating point numbers.

+
+ +
+
+

Private Members

+
+
+const uint16_t _features
+

Features enabled for the HVAC.

+
+ +
+
+const NumberPrecision _precision
+

The precision of temperatures. By default it’s HANumber::PrecisionP1.

+
+ +
+
+const char *_icon
+

The icon of the button. It can be nullptr.

+
+ +
+
+bool _retain
+

The retain flag for the HA commands.

+
+ +
+
+HANumeric _currentTemperature
+

The current temperature of the HVAC. By default it’s not set.

+
+ +
+
+Action _action
+

The current action of the HVAC. By default it’s HAHVAC::UnknownAction.

+
+ +
+
+TemperatureUnit _temperatureUnit
+

The temperature unit for the HVAC. By default it’s HAHVAC::DefaultUnit.

+
+ +
+
+HANumeric _minTemp
+

The minimum temperature that can be set.

+
+ +
+
+HANumeric _maxTemp
+

The maximum temperature that can be set.

+
+ +
+
+HANumeric _tempStep
+

The step of the temperature that can be set.

+
+ +
+
+void (*_auxCallback)(bool state, HAHVAC *sender)
+

Callback that will be called when the aux state command is received from the HA.

+
+ +
+
+bool _auxState
+

The state of the aux heating. By default it’s false.

+
+ +
+
+void (*_powerCallback)(bool state, HAHVAC *sender)
+

Callback that will be called when the power command is received from the HA.

+
+ +
+
+FanMode _fanMode
+

The current mode of the fan. By default it’s HAHVAC::UnknownFanMode.

+
+ +
+
+uint8_t _fanModes
+

The supported fan modes. By default it’s HAHVAC::DefaultFanModes.

+
+ +
+
+HASerializerArray *_fanModesSerializer
+

The serializer for the fan modes. It’s nullptr if the fan feature is disabled.

+
+ +
+
+void (*_fanModeCallback)(FanMode mode, HAHVAC *sender)
+

Callback that will be called when the fan mode command is received from the HA.

+
+ +
+
+SwingMode _swingMode
+

The current swing mode. By default it’s HAHVAC::UnknownSwingMode.

+
+ +
+
+uint8_t _swingModes
+

The supported swing modes. By default it’s HAHVAC::DefaultSwingModes.

+
+ +
+
+HASerializerArray *_swingModesSerializer
+

The serializer for the swing modes. It’s nullptr if the swing feature is disabled.

+
+ +
+
+void (*_swingModeCallback)(SwingMode mode, HAHVAC *sender)
+

Callback that will be called when the swing mode command is received from the HA.

+
+ +
+
+Mode _mode
+

The current mode. By default it’s HAHVAC::UnknownMode.

+
+ +
+
+uint8_t _modes
+

The supported modes. By default it’s HAHVAC::DefaultModes.

+
+ +
+
+HASerializerArray *_modesSerializer
+

The serializer for the modes. It’s nullptr if the modes feature is disabled.

+
+ +
+
+void (*_modeCallback)(Mode mode, HAHVAC *sender)
+

Callback that will be called when the mode command is received from the HA.

+
+ +
+
+HANumeric _targetTemperature
+

The target temperature of the HVAC. By default it’s not set.

+
+ +
+
+void (*_targetTemperatureCallback)(HANumeric temperature, HAHVAC *sender)
+

Callback that will be called when the target temperature is changed via the HA panel.

+
+ +
+
+ +
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/docs/documents/api/device-types/ha-light.html b/docs/documents/api/device-types/ha-light.html new file mode 100644 index 0000000..e39c0f3 --- /dev/null +++ b/docs/documents/api/device-types/ha-light.html @@ -0,0 +1,803 @@ + + + + + + + HALight class - ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

HALight class

+
+
+class HALight : public HABaseDeviceType
+

HALight allows adding a controllable light in the Home Assistant panel. The library supports only the state, brightness, color temperature and RGB color. If you need more features please open a new GitHub issue.

+
+

Note

+

You can find more information about this entity in the Home Assistant documentation: https://www.home-assistant.io/integrations/light.mqtt/

+
+
+

Public Types

+
+
+enum Features
+

Values:

+
+
+enumerator DefaultFeatures
+
+ +
+
+enumerator BrightnessFeature
+
+ +
+
+enumerator ColorTemperatureFeature
+
+ +
+
+enumerator RGBFeature
+
+ +
+ +
+
+

Public Functions

+
+
+HALight(const char *uniqueId, const uint8_t features = DefaultFeatures)
+
+
Parameters
+
    +
  • uniqueId – The unique ID of the light. It needs to be unique in a scope of your device.

  • +
  • features – Features that should be enabled for the light. You can enable multiple features by using OR bitwise operator, for example: HALight::BrightnessFeature | HALight::ColorTemperatureFeature

  • +
+
+
+
+ +
+
+bool setState(const bool state, const bool force = false)
+

Changes state of the light and publishes MQTT message. Please note that if a new value is the same as previous one, the MQTT message won’t be published.

+
+
Parameters
+
    +
  • state – New state of the light.

  • +
  • force – Forces to update state without comparing it to previous known state.

  • +
+
+
Returns
+

Returns true if MQTT message has been published successfully.

+
+
+
+ +
+
+bool setBrightness(const uint8_t brightness, const bool force = false)
+

Changes the brightness of the light and publishes MQTT message. Please note that if a new value is the same as previous one, the MQTT message won’t be published.

+
+
Parameters
+
    +
  • brightness – The new brightness of the light.

  • +
  • force – Forces to update the value without comparing it to a previous known value.

  • +
+
+
Returns
+

Returns true if MQTT message has been published successfully.

+
+
+
+ +
+
+bool setColorTemperature(const uint16_t temperature, const bool force = false)
+

Changes the color temperature of the light and publishes MQTT message. Please note that if a new value is the same as previous one, the MQTT message won’t be published.

+
+
Parameters
+
    +
  • temperature – The new color temperature of the light.

  • +
  • force – Forces to update the value without comparing it to a previous known value.

  • +
+
+
Returns
+

Returns true if MQTT message has been published successfully.

+
+
+
+ +
+
+bool setRGBColor(const RGBColor &color, const bool force = false)
+

Changes the RGB color of the light and publishes MQTT message. Please note that if a new color is the same as previous one, the MQTT message won’t be published.

+
+
Parameters
+
    +
  • color – The new RGB color of the light.

  • +
  • force – Forces to update the value without comparing it to a previous known value.

  • +
+
+
Returns
+

Returns true if MQTT message has been published successfully.

+
+
+
+ +
+
+inline bool turnOn()
+

Alias for setState(true).

+
+ +
+
+inline bool turnOff()
+

Alias for setState(false).

+
+ +
+
+inline void setCurrentState(const bool state)
+

Sets current state of the light without publishing it to Home Assistant. This method may be useful if you want to change state before connection with MQTT broker is acquired.

+
+
Parameters
+

state – New state of the light.

+
+
+
+ +
+
+inline bool getCurrentState() const
+

Returns last known state of the light. By default it’s false.

+
+ +
+
+inline void setCurrentBrightness(const uint8_t brightness)
+

Sets the current brightness of the light without pushing the value to Home Assistant. This method may be useful if you want to change the brightness before the connection with the MQTT broker is acquired.

+
+
Parameters
+

brightness – The new brightness of the light.

+
+
+
+ +
+
+inline uint8_t getCurrentBrightness() const
+

Returns the last known brightness of the light. By default brightness is set to 0.

+
+ +
+
+inline void setCurrentColorTemperature(const uint16_t temperature)
+

Sets the current color temperature of the light without pushing the value to Home Assistant. This method may be useful if you want to change the color temperature before the connection with the MQTT broker is acquired.

+
+
Parameters
+

colorTemp – The new color temperature (mireds).

+
+
+
+ +
+
+inline uint16_t getCurrentColorTemperature() const
+

Returns the last known color temperature of the light. By default temperature is set to 0.

+
+ +
+
+inline void setCurrentRGBColor(const RGBColor &color)
+

Sets the current RGB color of the light without pushing the value to Home Assistant. This method may be useful if you want to change the color before the connection with the MQTT broker is acquired.

+
+
Parameters
+

color – The new RGB color.

+
+
+
+ +
+
+inline const RGBColor &getCurrentRGBColor() const
+

Returns the last known RGB color of the light. By default the RGB color is set to 0,0,0.

+
+ +
+
+inline void setIcon(const char *icon)
+

Sets icon of the light. Any icon from MaterialDesignIcons.com (for example: mdi:home).

+
+
Parameters
+

icon – The icon name.

+
+
+
+ +
+
+inline void setRetain(const bool retain)
+

Sets retain flag for the light’s command. If set to true the command produced by Home Assistant will be retained.

+
+
Parameters
+

retain –

+
+
+
+ +
+
+inline void setOptimistic(const bool optimistic)
+

Sets optimistic flag for the light state. In this mode the light state doesn’t need to be reported back to the HA panel when a command is received. By default the optimistic mode is disabled.

+
+
Parameters
+

optimistic – The optimistic mode (true - enabled, false - disabled).

+
+
+
+ +
+
+inline void setBrightnessScale(const uint8_t scale)
+

Sets the maximum brightness value that can be set via HA panel. By default it’s 255.

+
+
Parameters
+

scale – The maximum value of the brightness.

+
+
+
+ +
+
+inline void setMinMireds(const uint16_t mireds)
+

Sets the minimum color temperature (mireds) value that can be set via HA panel. By default it’s 153.

+
+
Parameters
+

mireds – The minimum value of the brightness.

+
+
+
+ +
+
+inline void setMaxMireds(const uint16_t mireds)
+

Sets the maximum color temperature (mireds) value that can be set via HA panel. By default it’s 500.

+
+
Parameters
+

mireds – The maximum value of the brightness.

+
+
+
+ +
+
+inline void onStateCommand(void (*callback)(bool state, HALight *sender))
+

Registers callback that will be called each time the state command from HA is received. Please note that it’s not possible to register multiple callbacks for the same light.

+
+

Note

+

In non-optimistic mode, the state must be reported back to HA using the HALight::setState method.

+
+
+
Parameters
+

callback –

+
+
+
+ +
+
+inline void onBrightnessCommand(void (*callback)(uint8_t brightness, HALight *sender))
+

Registers callback that will be called each time the brightness command from HA is received. Please note that it’s not possible to register multiple callbacks for the same light.

+
+

Note

+

In non-optimistic mode, the brightness must be reported back to HA using the HALight::setBrightness method.

+
+
+
Parameters
+

callback –

+
+
+
+ +
+
+inline void onColorTemperatureCommand(void (*callback)(uint16_t temperature, HALight *sender))
+

Registers callback that will be called each time the color temperature command from HA is received. Please note that it’s not possible to register multiple callbacks for the same light.

+
+

Note

+

In non-optimistic mode, the color temperature must be reported back to HA using the HALight::setColorTemperature method.

+
+
+
Parameters
+

callback –

+
+
+
+ +
+
+inline void onRGBColorCommand(void (*callback)(HALight::RGBColor color, HALight *sender))
+

Registers callback that will be called each time the RGB color command from HA is received. Please note that it’s not possible to register multiple callbacks for the same light.

+
+

Note

+

In non-optimistic mode, the color must be reported back to HA using the HALight::setRGBColor method.

+
+
+
Parameters
+

callback –

+
+
+
+ +
+
+

Public Static Attributes

+
+
+static const uint8_t RGBStringMaxLength
+
+ +
+
+

Protected Functions

+
+
+virtual void buildSerializer() override
+
+ +
+
+virtual void onMqttConnected() override
+
+ +
+
+virtual void onMqttMessage(const char *topic, const uint8_t *payload, const uint16_t length) override
+
+ +
+
+

Private Functions

+
+
+bool publishState(const bool state)
+

Publishes the MQTT message with the given state.

+
+
Parameters
+

state – The state to publish.

+
+
Returns
+

Returns true if the MQTT message has been published successfully.

+
+
+
+ +
+
+bool publishBrightness(const uint8_t brightness)
+

Publishes the MQTT message with the given brightness.

+
+
Parameters
+

brightness – The brightness to publish.

+
+
Returns
+

Returns true if the MQTT message has been published successfully.

+
+
+
+ +
+
+bool publishColorTemperature(const uint16_t temperature)
+

Publishes the MQTT message with the given color temperature (mireds).

+
+
Parameters
+

temperature – The color temperature to publish.

+
+
Returns
+

Returns true if the MQTT message has been published successfully.

+
+
+
+ +
+
+bool publishRGBColor(const RGBColor &color)
+

Publishes the MQTT message with the given RGB color.

+
+
Parameters
+

color – The color to publish.

+
+
Returns
+

Returns true if the MQTT message has been published successfully.

+
+
+
+ +
+
+void handleStateCommand(const uint8_t *cmd, const uint16_t length)
+

Parses the given state command and executes the callback with proper value.

+
+
Parameters
+
    +
  • cmd – The data of the command.

  • +
  • length – Length of the command.

  • +
+
+
+
+ +
+
+void handleBrightnessCommand(const uint8_t *cmd, const uint16_t length)
+

Parses the given brightness command and executes the callback with proper value.

+
+
Parameters
+
    +
  • cmd – The data of the command.

  • +
  • length – Length of the command.

  • +
+
+
+
+ +
+
+void handleColorTemperatureCommand(const uint8_t *cmd, const uint16_t length)
+

Parses the given color temperature command and executes the callback with proper value.

+
+
Parameters
+
    +
  • cmd – The data of the command.

  • +
  • length – Length of the command.

  • +
+
+
+
+ +
+
+void handleRGBCommand(const uint8_t *cmd, const uint16_t length)
+

Parses the given RGB color command and executes the callback with proper value.

+
+
Parameters
+
    +
  • cmd – The data of the command.

  • +
  • length – Length of the command.

  • +
+
+
+
+ +
+
+

Private Members

+
+
+const uint8_t _features
+

Features enabled for the light.

+
+ +
+
+const char *_icon
+

The icon of the button. It can be nullptr.

+
+ +
+
+bool _retain
+

The retain flag for the HA commands.

+
+ +
+
+bool _optimistic
+

The optimistic mode of the light (true - enabled, false - disabled).

+
+ +
+
+HANumeric _brightnessScale
+

The maximum value of the brightness. By default it’s 255.

+
+ +
+
+bool _currentState
+

The current state of the light. By default it’s false.

+
+ +
+
+uint8_t _currentBrightness
+

The current brightness of the light. By default it’s 0.

+
+ +
+
+HANumeric _minMireds
+

The minimum color temperature (mireds). By default the value is not set.

+
+ +
+
+HANumeric _maxMireds
+

The maximum color temperature (mireds). By default the value is not set.

+
+ +
+
+uint16_t _currentColorTemperature
+

The current color temperature (mireds). By default the value is not set.

+
+ +
+
+RGBColor _currentRGBColor
+

The current RBB color. By default the value is not set.

+
+ +
+
+void (*_stateCallback)(bool state, HALight *sender)
+

The callback that will be called when the state command is received from the HA.

+
+ +
+
+void (*_brightnessCallback)(uint8_t brightness, HALight *sender)
+

The callback that will be called when the brightness command is received from the HA.

+
+ +
+
+void (*_colorTemperatureCallback)(uint16_t temperature, HALight *sender)
+

The callback that will be called when the color temperature command is received from the HA.

+
+ +
+
+void (*_rgbColorCallback)(HALight::RGBColor color, HALight *sender)
+

The callback that will be called when the RGB command is received from the HA.

+
+ +
+
+
+struct RGBColor
+
+

Public Functions

+
+
+inline RGBColor()
+
+ +
+
+inline RGBColor(uint8_t r, uint8_t g, uint8_t b)
+
+ +
+
+inline void operator=(const RGBColor &a)
+
+ +
+
+inline bool operator==(const RGBColor &a) const
+
+ +
+
+inline bool operator!=(const RGBColor &a) const
+
+ +
+
+void fromBuffer(const uint8_t *data, const uint16_t length)
+
+ +
+
+

Public Members

+
+
+uint8_t red
+
+ +
+
+uint8_t green
+
+ +
+
+uint8_t blue
+
+ +
+
+bool isSet
+
+ +
+
+ +
+ +
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/docs/documents/api/device-types/ha-lock.html b/docs/documents/api/device-types/ha-lock.html new file mode 100644 index 0000000..2a09154 --- /dev/null +++ b/docs/documents/api/device-types/ha-lock.html @@ -0,0 +1,409 @@ + + + + + + + HALock class - ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

HALock class

+
+
+class HALock : public HABaseDeviceType
+

HALock allows to implement a custom lock (for example: door lock) that can be controlled from the Home Assistant panel.

+
+

Note

+

You can find more information about this entity in the Home Assistant documentation: https://www.home-assistant.io/integrations/lock.mqtt/

+
+
+

Public Types

+
+
+enum LockState
+

Available states of the lock that can be reported to the HA panel.

+

Values:

+
+
+enumerator StateUnknown
+
+ +
+
+enumerator StateLocked
+
+ +
+
+enumerator StateUnlocked
+
+ +
+ +
+
+enum LockCommand
+

Commands that will be produced by the HA panel.

+

Values:

+
+
+enumerator CommandLock
+
+ +
+
+enumerator CommandUnlock
+
+ +
+
+enumerator CommandOpen
+
+ +
+ +
+
+

Public Functions

+
+
+HALock(const char *uniqueId)
+
+
Parameters
+

uniqueId – The unique ID of the lock. It needs to be unique in a scope of your device.

+
+
+
+ +
+
+bool setState(const LockState state, const bool force = false)
+

Changes state of the lock and publishes MQTT message. Please note that if a new value is the same as previous one, the MQTT message won’t be published.

+
+
Parameters
+
    +
  • state – New state of the lock.

  • +
  • force – Forces to update state without comparing it to a previous known state.

  • +
+
+
Returns
+

Returns true if MQTT message has been published successfully.

+
+
+
+ +
+
+inline void setCurrentState(const LockState state)
+

Sets current state of the lock without publishing it to Home Assistant. This method may be useful if you want to change state before connection with MQTT broker is acquired.

+
+
Parameters
+

state – New state of the lock.

+
+
+
+ +
+
+inline LockState getCurrentState() const
+

Returns last known state of the lock. If setState method wasn’t called the initial value will be returned.

+
+ +
+
+inline void setIcon(const char *icon)
+

Sets icon of the lock. Any icon from MaterialDesignIcons.com (for example: mdi:home).

+
+
Parameters
+

icon – The icon name.

+
+
+
+ +
+
+inline void setRetain(const bool retain)
+

Sets retain flag for the lock’s command. If set to true the command produced by Home Assistant will be retained.

+
+
Parameters
+

retain –

+
+
+
+ +
+
+inline void setOptimistic(const bool optimistic)
+

Sets optimistic flag for the lock state. In this mode the lock state doesn’t need to be reported back to the HA panel when a command is received. By default the optimistic mode is disabled.

+
+
Parameters
+

optimistic – The optimistic mode (true - enabled, false - disabled).

+
+
+
+ +
+
+inline void onCommand(void (*callback)(LockCommand command, HALock *sender))
+

Registers callback that will be called each time the lock/unlock/open command from the HA is received. Please note that it’s not possible to register multiple callbacks for the same lock.

+
+
Parameters
+

callback –

+
+
+
+ +
+
+

Protected Functions

+
+
+virtual void buildSerializer() override
+
+ +
+
+virtual void onMqttConnected() override
+
+ +
+
+virtual void onMqttMessage(const char *topic, const uint8_t *payload, const uint16_t length) override
+
+ +
+
+

Private Functions

+
+
+bool publishState(const LockState state)
+

Publishes the MQTT message with the given state.

+
+
Parameters
+

state – The state to publish.

+
+
Returns
+

Returns true if the MQTT message has been published successfully.

+
+
+
+ +
+
+void handleCommand(const uint8_t *cmd, const uint16_t length)
+

Parses the given command and executes the lock’s callback with proper enum’s property.

+
+
Parameters
+
    +
  • cmd – The data of the command.

  • +
  • length – Length of the command.

  • +
+
+
+
+ +
+
+

Private Members

+
+
+const char *_icon
+

The icon of the lock. It can be nullptr.

+
+ +
+
+bool _retain
+

The retain flag for the HA commands.

+
+ +
+
+bool _optimistic
+

The optimistic mode of the lock (true - enabled, false - disabled).

+
+ +
+
+LockState _currentState
+

The current state of the lock. By default it’s HALock::StateUnknown.

+
+ +
+
+void (*_commandCallback)(LockCommand command, HALock *sender)
+

The callback that will be called when lock/unlock/open command is received from the HA.

+
+ +
+
+ +
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/docs/documents/api/device-types/ha-number.html b/docs/documents/api/device-types/ha-number.html new file mode 100644 index 0000000..c261afc --- /dev/null +++ b/docs/documents/api/device-types/ha-number.html @@ -0,0 +1,599 @@ + + + + + + + HANumber class - ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

HANumber class

+
+
+class HANumber : public HABaseDeviceType
+

HANumber adds a slider or a box in the Home Assistant panel that controls the numeric value stored on your device.

+
+

Note

+

You can find more information about this entity in the Home Assistant documentation: https://www.home-assistant.io/integrations/number.mqtt/

+
+
+

Public Types

+
+
+enum Mode
+

Represents mode of the number.

+

Values:

+
+
+enumerator ModeAuto
+
+ +
+
+enumerator ModeBox
+
+ +
+
+enumerator ModeSlider
+
+ +
+ +
+
+

Public Functions

+
+
+HANumber(const char *uniqueId, const NumberPrecision precision = PrecisionP0)
+

Creates instance of the HANumber entity with the given numbers precision. The given precision applies to the state, min, max and step values.

+
+
Parameters
+
    +
  • uniqueId – The unique ID of the number. It needs to be unique in a scope of your device.

  • +
  • precision – Precision of the floating point number that will be displayed in the HA panel.

  • +
+
+
+
+ +
+
+bool setState(const HANumeric &state, const bool force = false)
+

Changes state of the number and publishes MQTT message. Please note that if a new value is the same as previous one, the MQTT message won’t be published.

+
+
Parameters
+
    +
  • state – New state of the number.

  • +
  • force – Forces to update state without comparing it to a previous known state.

  • +
+
+
Returns
+

Returns true if MQTT message has been published successfully.

+
+
+
+ +
+
+inline bool setState(const int8_t state, const bool force = false)
+

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

+
+ +
+
+inline bool setState(const int16_t state, const bool force = false)
+

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

+
+ +
+
+inline bool setState(const int32_t state, const bool force = false)
+

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

+
+ +
+
+inline bool setState(const uint8_t state, const bool force = false)
+

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

+
+ +
+
+inline bool setState(const uint16_t state, const bool force = false)
+

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

+
+ +
+
+inline bool setState(const uint32_t state, const bool force = false)
+

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

+
+ +
+
+inline bool setState(const float state, const bool force = false)
+

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

+
+ +
+
+inline void setCurrentState(const HANumeric &state)
+

Sets current state of the number without publishing it to Home Assistant. This method may be useful if you want to change state before connection with MQTT broker is acquired.

+
+
Parameters
+

state – New state of the number.

+
+
+
+ +
+
+inline void setCurrentState(const int8_t state)
+

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

+
+ +
+
+inline void setCurrentState(const int16_t state)
+

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

+
+ +
+
+inline void setCurrentState(const int32_t state)
+

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

+
+ +
+
+inline void setCurrentState(const uint8_t state)
+

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

+
+ +
+
+inline void setCurrentState(const uint16_t state)
+

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

+
+ +
+
+inline void setCurrentState(const uint32_t state)
+

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

+
+ +
+
+inline void setCurrentState(const float state)
+

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

+
+ +
+
+inline const HANumeric &getCurrentState() const
+

Returns last known state of the number. If setState method wasn’t called the initial value will be returned.

+
+ +
+
+inline void setDeviceClass(const char *deviceClass)
+

Sets class of the device. You can find list of available values here: https://www.home-assistant.io/integrations/number/#device-class

+
+
Parameters
+

deviceClass – The class name.

+
+
+
+ +
+
+inline void setIcon(const char *icon)
+

Sets icon of the number. Any icon from MaterialDesignIcons.com (for example: mdi:home).

+
+
Parameters
+

icon – The icon name.

+
+
+
+ +
+
+inline void setRetain(const bool retain)
+

Sets retain flag for the number’s command. If set to true the command produced by Home Assistant will be retained.

+
+
Parameters
+

retain –

+
+
+
+ +
+
+inline void setOptimistic(const bool optimistic)
+

Sets optimistic flag for the number state. In this mode the number state doesn’t need to be reported back to the HA panel when a command is received. By default the optimistic mode is disabled.

+
+
Parameters
+

optimistic – The optimistic mode (true - enabled, false - disabled).

+
+
+
+ +
+
+inline void setMode(const Mode mode)
+

Sets mode of the number. It controls how the number should be displayed in the UI. By default it’s HANumber::ModeAuto.

+
+
Parameters
+

mode – Mode to set.

+
+
+
+ +
+
+inline void setUnitOfMeasurement(const char *unitOfMeasurement)
+

Defines the units of measurement of the number, if any.

+
+
Parameters
+

units – For example: °C, %

+
+
+
+ +
+
+inline void setMin(const float min)
+

Sets the minimum value that can be set from the Home Assistant panel.

+
+
Parameters
+

min – The minimal value. By default the value is not set.

+
+
+
+ +
+
+inline void setMax(const float max)
+

Sets the maximum value that can be set from the Home Assistant panel.

+
+
Parameters
+

min – The maximum value. By default the value is not set.

+
+
+
+ +
+
+inline void setStep(const float step)
+

Sets step of the slider’s movement in the Home Assistant panel.

+
+
Parameters
+

step – The step value. Smallest value 0.001. By default the value is not set.

+
+
+
+ +
+
+inline void onCommand(void (*callback)(HANumeric number, HANumber *sender))
+

Registers callback that will be called each time the number is changed in the HA panel. Please note that it’s not possible to register multiple callbacks for the same number.

+
+

Note

+

In non-optimistic mode, the number must be reported back to HA using the HANumber::setState method.

+
+
+
Parameters
+

callback –

+
+
+
+ +
+
+

Protected Functions

+
+
+virtual void buildSerializer() override
+
+ +
+
+virtual void onMqttConnected() override
+
+ +
+
+virtual void onMqttMessage(const char *topic, const uint8_t *payload, const uint16_t length) override
+
+ +
+
+

Private Functions

+
+
+bool publishState(const HANumeric &state)
+

Publishes the MQTT message with the given state.

+
+
Parameters
+

state – The state to publish.

+
+
Returns
+

Returns true if the MQTT message has been published successfully.

+
+
+
+ +
+
+void handleCommand(const uint8_t *cmd, const uint16_t length)
+

Parses the given command and executes the number’s callback with proper value.

+
+
Parameters
+
    +
  • cmd – The data of the command.

  • +
  • length – Length of the command.

  • +
+
+
+
+ +
+
+const __FlashStringHelper *getModeProperty() const
+

Returns progmem string representing mode of the number

+
+ +
+
+const __FlashStringHelper *getCommandTemplate()
+

Returns progmem string representing value template for the command.

+
+ +
+
+

Private Members

+
+
+const NumberPrecision _precision
+

The precision of the number. By default it’s HANumber::PrecisionP0.

+
+ +
+
+const char *_class
+

The device class. It can be nullptr.

+
+ +
+
+const char *_icon
+

The icon of the number. It can be nullptr.

+
+ +
+
+bool _retain
+

The retain flag for the HA commands.

+
+ +
+
+bool _optimistic
+

The optimistic mode of the number (true - enabled, false - disabled).

+
+ +
+
+Mode _mode
+

Controls how the number should be displayed in the UI. By default it’s HANumber::ModeAuto.

+
+ +
+
+const char *_unitOfMeasurement
+

The unit of measurement for the sensor. It can be nullptr.

+
+ +
+
+HANumeric _minValue
+

The minimal value that can be set from the HA panel.

+
+ +
+
+HANumeric _maxValue
+

The maximum value that can be set from the HA panel.

+
+ +
+
+HANumeric _step
+

The step of the slider’s movement.

+
+ +
+
+HANumeric _currentState
+

The current state of the number. By default the value is not set.

+
+ +
+
+void (*_commandCallback)(HANumeric number, HANumber *sender)
+

The callback that will be called when the command is received from the HA.

+
+ +
+
+ +
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/docs/documents/api/device-types/ha-scene.html b/docs/documents/api/device-types/ha-scene.html new file mode 100644 index 0000000..8c807fc --- /dev/null +++ b/docs/documents/api/device-types/ha-scene.html @@ -0,0 +1,274 @@ + + + + + + + HAScene class - ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

HAScene class

+
+
+class HAScene : public HABaseDeviceType
+

HAScene adds a new scene to the Home Assistant that triggers your callback once activated.

+
+

Note

+

You can find more information about this entity in the Home Assistant documentation: https://www.home-assistant.io/integrations/scene.mqtt/

+
+
+

Public Functions

+
+
+HAScene(const char *uniqueId)
+
+
Parameters
+

uniqueId – The unique ID of the scene. It needs to be unique in a scope of your device.

+
+
+
+ +
+
+inline void setIcon(const char *icon)
+

Sets icon of the scene. Any icon from MaterialDesignIcons.com (for example: mdi:home).

+
+
Parameters
+

icon – The icon name.

+
+
+
+ +
+
+inline void setRetain(const bool retain)
+

Sets retain flag for the scene’s command. If set to true the command produced by Home Assistant will be retained.

+
+
Parameters
+

retain –

+
+
+
+ +
+
+inline void onCommand(void (*callback)(HAScene *sender))
+

Registers callback that will be called when the scene is activated in the HA panel. Please note that it’s not possible to register multiple callbacks for the same scene.

+
+
Parameters
+

callback –

+
+
+
+ +
+
+

Protected Functions

+
+
+virtual void buildSerializer() override
+
+ +
+
+virtual void onMqttConnected() override
+
+ +
+
+virtual void onMqttMessage(const char *topic, const uint8_t *payload, const uint16_t length) override
+
+ +
+
+

Private Members

+
+
+const char *_icon
+

The icon of the scene. It can be nullptr.

+
+ +
+
+bool _retain
+

The retain flag for the HA commands.

+
+ +
+
+void (*_commandCallback)(HAScene *sender)
+

The command callback that will be called when scene is activated from the HA panel.

+
+ +
+
+ +
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/docs/documents/api/device-types/ha-select.html b/docs/documents/api/device-types/ha-select.html new file mode 100644 index 0000000..6c27bdb --- /dev/null +++ b/docs/documents/api/device-types/ha-select.html @@ -0,0 +1,384 @@ + + + + + + + HASelect class - ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

HASelect class

+
+
+class HASelect : public HABaseDeviceType
+

HASelect adds a dropdown with options in the Home Assistant panel.

+
+

Note

+

You can find more information about this entity in the Home Assistant documentation: https://www.home-assistant.io/integrations/button.mqtt/

+
+
+

Public Functions

+
+
+HASelect(const char *uniqueId)
+
+
Parameters
+

uniqueId – The unique ID of the select. It needs to be unique in a scope of your device.

+
+
+
+ +
+
+~HASelect()
+
+ +
+
+void setOptions(const char *options)
+

Sets the list of available options that will be listed in the dropdown. The input string should contain options separated using semicolons. For example: `setOptions(“Option A;Option B;Option C”);

+
+

Note

+

The options list can be set only once.

+
+
+
Parameters
+

options – The list of options that are separated by semicolons.

+
+
+
+ +
+
+bool setState(const int8_t state, const bool force = false)
+

Changes state of the select and publishes MQTT message. State represents the index of the option that was set using the setOptions method. Please note that if a new value is the same as previous one, the MQTT message won’t be published.

+
+
Parameters
+
    +
  • state – New state of the select.

  • +
  • force – Forces to update state without comparing it to previous known state.

  • +
+
+
Returns
+

Returns true if MQTT message has been published successfully.

+
+
+
+ +
+
+inline void setCurrentState(const int8_t state)
+

Sets the current state of the select without publishing it to Home Assistant. State represents the index of the option that was set using the setOptions method. This method may be useful if you want to change the state before the connection with the MQTT broker is acquired.

+
+
Parameters
+

state – The new state of the cover.

+
+
+
+ +
+
+inline int8_t getCurrentState() const
+

Returns last known state of the select. State represents the index of the option that was set using the setOptions method. By default the state is set to -1.

+
+ +
+
+inline void setIcon(const char *icon)
+

Sets icon of the select. Any icon from MaterialDesignIcons.com (for example: mdi:home).

+
+
Parameters
+

icon – The icon name.

+
+
+
+ +
+
+inline void setRetain(const bool retain)
+

Sets retain flag for the select’s command. If set to true the command produced by Home Assistant will be retained.

+
+
Parameters
+

retain –

+
+
+
+ +
+
+inline void setOptimistic(const bool optimistic)
+

Sets optimistic flag for the select state. In this mode the select state doesn’t need to be reported back to the HA panel when a command is received. By default the optimistic mode is disabled.

+
+
Parameters
+

optimistic – The optimistic mode (true - enabled, false - disabled).

+
+
+
+ +
+
+inline void onCommand(void (*callback)(int8_t index, HASelect *sender))
+

Registers callback that will be called each time the option is changed from the HA panel. Please note that it’s not possible to register multiple callbacks for the same select.

+
+

Note

+

In non-optimistic mode, the selected option must be reported back to HA using the HASelect::setState method.

+
+
+
Parameters
+

callback –

+
+
+
+ +
+
+

Protected Functions

+
+
+virtual void buildSerializer() override
+
+ +
+
+virtual void onMqttConnected() override
+
+ +
+
+virtual void onMqttMessage(const char *topic, const uint8_t *payload, const uint16_t length) override
+
+ +
+
+

Private Functions

+
+
+bool publishState(const int8_t state)
+

Publishes the MQTT message with the given state.

+
+
Parameters
+

state – The state to publish.

+
+
Returns
+

Returns true if the MQTT message has been published successfully.

+
+
+
+ +
+
+uint8_t countOptionsInString(const char *options) const
+

Counts the amount of options in the given string.

+
+ +
+
+

Private Members

+
+
+HASerializerArray *_options
+

Array of options for the serializer.

+
+ +
+
+int8_t _currentState
+

Stores the current state (the current option’s index). By default it’s -1.

+
+ +
+
+const char *_icon
+

The icon of the select. It can be nullptr.

+
+ +
+
+bool _retain
+

The retain flag for the HA commands.

+
+ +
+
+bool _optimistic
+

The optimistic mode of the select (true - enabled, false - disabled).

+
+ +
+
+void (*_commandCallback)(int8_t index, HASelect *sender)
+

The command callback that will be called when option is changed via the HA panel.

+
+ +
+
+ +
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/docs/documents/api/device-types/ha-sensor-number.html b/docs/documents/api/device-types/ha-sensor-number.html new file mode 100644 index 0000000..b0b8382 --- /dev/null +++ b/docs/documents/api/device-types/ha-sensor-number.html @@ -0,0 +1,363 @@ + + + + + + + HASensorNumber class - ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

HASensorNumber class

+
+
+class HASensorNumber : public HASensor
+

HASensorInteger allows to publish numeric values of a sensor that will be displayed in the HA panel.

+
+

Note

+

You can find more information about this class in HASensor documentation.

+
+
+

Public Functions

+
+
+HASensorNumber(const char *uniqueId, const NumberPrecision precision = PrecisionP0)
+
+
Parameters
+
    +
  • uniqueId – The unique ID of the sensor. It needs to be unique in a scope of your device.

  • +
  • precision – Precision of the floating point number that will be displayed in the HA panel.

  • +
+
+
+
+ +
+
+bool setValue(const HANumeric &value, const bool force = false)
+

Changes value of the sensor and publish MQTT message. Please note that if a new value is the same as the previous one the MQTT message won’t be published.

+
+
Parameters
+
    +
  • value – New value of the sensor. THe precision of the value needs to match precision of the sensor.

  • +
  • force – Forces to update the value without comparing it to a previous known value.

  • +
+
+
Returns
+

Returns true if the MQTT message has been published successfully.

+
+
+
+ +
+
+inline bool setValue(const int8_t value, const bool force = false)
+

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

+
+ +
+
+inline bool setValue(const int16_t value, const bool force = false)
+

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

+
+ +
+
+inline bool setValue(const int32_t value, const bool force = false)
+

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

+
+ +
+
+inline bool setValue(const uint8_t value, const bool force = false)
+

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

+
+ +
+
+inline bool setValue(const uint16_t value, const bool force = false)
+

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

+
+ +
+
+inline bool setValue(const uint32_t value, const bool force = false)
+

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

+
+ +
+
+inline bool setValue(const float value, const bool force = false)
+

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

+
+ +
+
+inline void setCurrentValue(const HANumeric &value)
+

Sets the current value of the sensor without publishing it to Home Assistant. This method may be useful if you want to change the value before the connection with the MQTT broker is acquired.

+
+
Parameters
+

value – New value of the sensor.

+
+
+
+ +
+
+inline void setCurrentValue(const int8_t value)
+

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

+
+ +
+
+inline void setCurrentValue(const int16_t value)
+

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

+
+ +
+
+inline void setCurrentValue(const int32_t value)
+

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

+
+ +
+
+inline void setCurrentValue(const uint8_t value)
+

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

+
+ +
+
+inline void setCurrentValue(const uint16_t value)
+

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

+
+ +
+
+inline void setCurrentValue(const uint32_t value)
+

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

+
+ +
+
+inline void setCurrentValue(const float value)
+

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

+
+ +
+
+inline const HANumeric &getCurrentValue() const
+

Returns the last known value of the sensor. By default the value is not set.

+
+ +
+
+

Protected Functions

+
+
+virtual void onMqttConnected() override
+
+ +
+
+

Private Functions

+
+
+bool publishValue(const HANumeric &value)
+

Publishes the MQTT message with the given value.

+
+
Parameters
+

state – The value to publish.

+
+
Returns
+

Returns true if the MQTT message has been published successfully.

+
+
+
+ +
+
+

Private Members

+
+
+const NumberPrecision _precision
+

The precision of the sensor. By default it’s HASensorNumber::PrecisionP0.

+
+ +
+
+HANumeric _currentValue
+

The current value of the sensor. By default the value is not set.

+
+ +
+
+ +
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/docs/documents/api/device-types/ha-sensor.html b/docs/documents/api/device-types/ha-sensor.html new file mode 100644 index 0000000..aa38aac --- /dev/null +++ b/docs/documents/api/device-types/ha-sensor.html @@ -0,0 +1,305 @@ + + + + + + + HASensor class - ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

HASensor class

+
+
+class HASensor : public HABaseDeviceType
+

HASensor allows to publish textual sensor values that will be displayed in the HA panel. If you need to publish numbers then HASensorNumber is what you’re looking for.

+
+

Note

+

It’s not possible to define a sensor that publishes mixed values (e.g. string + integer values).

+
+
+

Note

+

You can find more information about this entity in the Home Assistant documentation: https://www.home-assistant.io/integrations/sensor.mqtt/

+
+

Subclassed by HASensorNumber

+
+

Public Functions

+
+
+HASensor(const char *uniqueId)
+
+
Parameters
+

uniqueId – The unique ID of the sensor. It needs to be unique in a scope of your device.

+
+
+
+ +
+
+bool setValue(const char *value)
+

Publishes the MQTT message with the given value. Unlike the other device types, the HASensor doesn’t store the previous value that was set. It means that the MQTT message is produced each time the setValue method is called.

+
+
Parameters
+

value – String representation of the sensor’s value.

+
+
Returns
+

Returns true if MQTT message has been published successfully.

+
+
+
+ +
+
+inline void setDeviceClass(const char *deviceClass)
+

Sets class of the device. You can find list of available values here: https://www.home-assistant.io/integrations/sensor/#device-class

+
+
Parameters
+

deviceClass – The class name.

+
+
+
+ +
+
+inline void setForceUpdate(bool forceUpdate)
+

Forces HA panel to process each incoming value (MQTT message). It’s useful if you want to have meaningful value graphs in history.

+
+
Parameters
+

forceUpdate –

+
+
+
+ +
+
+inline void setIcon(const char *icon)
+

Sets icon of the sensor. Any icon from MaterialDesignIcons.com (for example: mdi:home).

+
+
Parameters
+

class – The icon name.

+
+
+
+ +
+
+inline void setUnitOfMeasurement(const char *unitOfMeasurement)
+

Defines the units of measurement of the sensor, if any.

+
+
Parameters
+

units – For example: °C, %

+
+
+
+ +
+
+

Protected Functions

+
+
+virtual void buildSerializer() final override
+
+ +
+
+virtual void onMqttConnected() override
+
+ +
+
+

Private Members

+
+
+const char *_deviceClass
+

The device class. It can be nullptr.

+
+ +
+
+bool _forceUpdate
+

The force update flag for the HA panel.

+
+ +
+
+const char *_icon
+

The icon of the sensor. It can be nullptr.

+
+ +
+
+const char *_unitOfMeasurement
+

The unit of measurement for the sensor. It can be nullptr.

+
+ +
+
+ +
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/docs/documents/api/device-types/ha-switch.html b/docs/documents/api/device-types/ha-switch.html new file mode 100644 index 0000000..6fa9057 --- /dev/null +++ b/docs/documents/api/device-types/ha-switch.html @@ -0,0 +1,381 @@ + + + + + + + HASwitch class - ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

HASwitch class

+
+
+class HASwitch : public HABaseDeviceType
+

HASwitch allows to display on/off switch in the HA panel and receive commands on your device.

+
+

Note

+

You can find more information about this entity in the Home Assistant documentation: https://www.home-assistant.io/integrations/switch.mqtt/

+
+
+

Public Functions

+
+
+HASwitch(const char *uniqueId)
+
+
Parameters
+

uniqueId – The unique ID of the sensor. It needs to be unique in a scope of your device.

+
+
+
+ +
+
+bool setState(const bool state, const bool force = false)
+

Changes state of the switch and publishes MQTT message. Please note that if a new value is the same as previous one, the MQTT message won’t be published.

+
+
Parameters
+
    +
  • state – New state of the switch.

  • +
  • force – Forces to update state without comparing it to previous known state.

  • +
+
+
Returns
+

Returns true if MQTT message has been published successfully.

+
+
+
+ +
+
+inline bool turnOn()
+

Alias for setState(true).

+
+ +
+
+inline bool turnOff()
+

Alias for setState(false).

+
+ +
+
+inline void setCurrentState(const bool state)
+

Sets current state of the switch without publishing it to Home Assistant. This method may be useful if you want to change state before connection with MQTT broker is acquired.

+
+
Parameters
+

state – New state of the switch.

+
+
+
+ +
+
+inline bool getCurrentState() const
+

Returns last known state of the switch. By default it’s false.

+
+ +
+
+inline void setDeviceClass(const char *deviceClass)
+

Sets class of the device. You can find list of available values here: https://www.home-assistant.io/integrations/switch/#device-class

+
+
Parameters
+

deviceClass – The class name.

+
+
+
+ +
+
+inline void setIcon(const char *icon)
+

Sets icon of the sensor. Any icon from MaterialDesignIcons.com (for example: mdi:home).

+
+
Parameters
+

icon – The icon name.

+
+
+
+ +
+
+inline void setRetain(const bool retain)
+

Sets retain flag for the switch command. If set to true the command produced by Home Assistant will be retained.

+
+
Parameters
+

retain –

+
+
+
+ +
+
+inline void setOptimistic(const bool optimistic)
+

Sets optimistic flag for the switch state. In this mode the switch state doesn’t need to be reported back to the HA panel when a command is received. By default the optimistic mode is disabled.

+
+
Parameters
+

optimistic – The optimistic mode (true - enabled, false - disabled).

+
+
+
+ +
+
+inline void onCommand(void (*callback)(bool state, HASwitch *sender))
+

Registers callback that will be called each time the on/off command from HA is received. Please note that it’s not possible to register multiple callbacks for the same switch.

+
+

Note

+

In non-optimistic mode, the state must be reported back to HA using the HASwitch::setState method.

+
+
+
Parameters
+

callback –

+
+
+
+ +
+
+

Protected Functions

+
+
+virtual void buildSerializer() override
+
+ +
+
+virtual void onMqttConnected() override
+
+ +
+
+virtual void onMqttMessage(const char *topic, const uint8_t *payload, const uint16_t length) override
+
+ +
+
+

Private Functions

+
+
+bool publishState(const bool state)
+

Publishes the MQTT message with the given state.

+
+
Parameters
+

state – The state to publish.

+
+
Returns
+

Returns true if the MQTT message has been published successfully.

+
+
+
+ +
+
+

Private Members

+
+
+const char *_class
+

The device class. It can be nullptr.

+
+ +
+
+const char *_icon
+

The icon of the button. It can be nullptr.

+
+ +
+
+bool _retain
+

The retain flag for the HA commands.

+
+ +
+
+bool _optimistic
+

The optimistic mode of the switch (true - enabled, false - disabled).

+
+ +
+
+bool _currentState
+

The current state of the switch. By default it’s false.

+
+ +
+
+void (*_commandCallback)(bool state, HASwitch *sender)
+

The callback that will be called when switch command is received from the HA.

+
+ +
+
+ +
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/docs/documents/api/device-types/ha-tag-scanner.html b/docs/documents/api/device-types/ha-tag-scanner.html new file mode 100644 index 0000000..18be2f5 --- /dev/null +++ b/docs/documents/api/device-types/ha-tag-scanner.html @@ -0,0 +1,229 @@ + + + + + + + HATagScanner class - ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

HATagScanner class

+
+
+class HATagScanner : public HABaseDeviceType
+

HATagScanner allow to produce scan events that can be used in the HA automation.

+
+

Note

+

You can find more information about this entity in the Home Assistant documentation: https://www.home-assistant.io/integrations/tag.mqtt/

+
+
+

Public Functions

+
+
+HATagScanner(const char *uniqueId)
+
+
Parameters
+

uniqueId – The unique ID of the scanner. It needs to be unique in a scope of your device.

+
+
+
+ +
+
+bool tagScanned(const char *tag)
+

Sends “tag scanned” event to the MQTT (Home Assistant). Based on this event HA may perform user-defined automation.

+
+
Parameters
+

tag – Value of the scanned tag.

+
+
Returns
+

Returns true if MQTT message has been published successfully.

+
+
+
+ +
+
+

Protected Functions

+
+
+virtual void buildSerializer() override
+
+ +
+
+virtual void onMqttConnected() override
+
+ +
+
+ +
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/docs/documents/api/device-types/index.html b/docs/documents/api/device-types/index.html new file mode 100644 index 0000000..9dacf0c --- /dev/null +++ b/docs/documents/api/device-types/index.html @@ -0,0 +1,199 @@ + + + + + + + Device types API - ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/documents/api/index.html b/docs/documents/api/index.html new file mode 100644 index 0000000..e5c3010 --- /dev/null +++ b/docs/documents/api/index.html @@ -0,0 +1,212 @@ + + + + + + + API reference - ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/documents/api/utils/ha-numeric.html b/docs/documents/api/utils/ha-numeric.html new file mode 100644 index 0000000..cb2480f --- /dev/null +++ b/docs/documents/api/utils/ha-numeric.html @@ -0,0 +1,503 @@ + + + + + + + HANumeric class - ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

HANumeric class

+
+
+class HANumeric
+

This class represents a numeric value that simplifies use of different types of numbers across the library.

+
+

Public Functions

+
+
+HANumeric()
+

Creates an empty number representation.

+
+ +
+
+HANumeric(const float value, const uint8_t precision)
+

Converts the given float into number representation of the given precision. If the precision is set to zero the given float will be converted into integer.

+
+
Parameters
+
    +
  • value – The value that should be used as a base.

  • +
  • precision – The number of digits in the decimal part.

  • +
+
+
+
+ +
+
+HANumeric(const int8_t value, const uint8_t precision)
+

Converts the given int8_t into number representation of the given precision. If the precision is greater than zero the given value will be converted to float.

+
+
Parameters
+
    +
  • value – The value that should be used as a base.

  • +
  • precision – The number of digits in the decimal part.

  • +
+
+
+
+ +
+
+HANumeric(const int16_t value, const uint8_t precision)
+

Converts the given int16_t into number representation of the given precision. If the precision is greater than zero the given value will be converted to float.

+
+
Parameters
+
    +
  • value – The value that should be used as a base.

  • +
  • precision – The number of digits in the decimal part.

  • +
+
+
+
+ +
+
+HANumeric(const int32_t value, const uint8_t precision)
+

Converts the given int32_t into number representation of the given precision. If the precision is greater than zero the given value will be converted to float.

+
+
Parameters
+
    +
  • value – The value that should be used as a base.

  • +
  • precision – The number of digits in the decimal part.

  • +
+
+
+
+ +
+
+HANumeric(const uint8_t value, const uint8_t precision)
+

Converts the given uint8_t into number representation of the given precision. If the precision is greater than zero the given value will be converted to float.

+
+
Parameters
+
    +
  • value – The value that should be used as a base.

  • +
  • precision – The number of digits in the decimal part.

  • +
+
+
+
+ +
+
+HANumeric(const uint16_t value, const uint8_t precision)
+

Converts the given uint16_t into number representation of the given precision. If the precision is greater than zero the given value will be converted to float.

+
+
Parameters
+
    +
  • value – The value that should be used as a base.

  • +
  • precision – The number of digits in the decimal part.

  • +
+
+
+
+ +
+
+HANumeric(const uint32_t value, const uint8_t precision)
+

Converts the given uint32_t into number representation of the given precision. If the precision is greater than zero the given value will be converted to float.

+
+
Parameters
+
    +
  • value – The value that should be used as a base.

  • +
  • precision – The number of digits in the decimal part.

  • +
+
+
+
+ +
+
+inline void operator=(const HANumeric &a)
+
+ +
+
+inline bool operator==(const HANumeric &a) const
+
+ +
+
+uint32_t getPrecisionBase() const
+

Returns multiplier that used to generate base value based on the precision. The multiplier is generated using the formula: pow(precision, 10).

+
+ +
+
+uint8_t calculateSize() const
+

Returns size of the number

+
+ +
+
+uint16_t toStr(char *dst) const
+

Converts the number to the string.

+
+

Note

+

The dst size should be calculated using HANumeric::calculateSize() method plus 1 extra byte for the null terminator.

+
+
+
Parameters
+

dst – Destination where the number will be saved. The null terminator is not added at the end.

+
+
Returns
+

The number of written characters.

+
+
+
+ +
+
+inline bool isSet() const
+

Returns true if the base value is set.

+
+ +
+
+inline void setBaseValue(int64_t value)
+

Sets the base value without converting it to the proper precision.

+
+ +
+
+inline int64_t getBaseValue() const
+

Returns the base value of the number.

+
+ +
+
+inline void setPrecision(const uint8_t precision)
+

Sets the precision of the number (number of digits in the decimal part).

+
+
Parameters
+

precision – The precision to use.

+
+
+
+ +
+
+inline uint8_t getPrecision() const
+

Returns the precision of the number.

+
+ +
+
+inline void reset()
+

Resets the number to the defaults.

+
+ +
+
+inline bool isUInt8() const
+
+ +
+
+inline bool isUInt16() const
+
+ +
+
+inline bool isUInt32() const
+
+ +
+
+inline bool isInt8() const
+
+ +
+
+inline bool isInt16() const
+
+ +
+
+inline bool isInt32() const
+
+ +
+
+inline bool isFloat() const
+
+ +
+
+inline uint8_t toUInt8() const
+
+ +
+
+inline uint16_t toUInt16() const
+
+ +
+
+inline uint32_t toUInt32() const
+
+ +
+
+inline int8_t toInt8() const
+
+ +
+
+inline int16_t toInt16() const
+
+ +
+
+inline int32_t toInt32() const
+
+ +
+
+inline float toFloat() const
+
+ +
+
+

Public Static Functions

+
+
+static HANumeric fromStr(const uint8_t *buffer, const uint16_t length)
+

Deserializes number from the given buffer. Please note that the class expected buffer to contain the base number. For example, deserializing 1234 number and setting precision to 1 results in representation of 123.4 float.

+
+
Parameters
+
    +
  • buffer – The buffer that contains the number.

  • +
  • length – The length of the buffer.

  • +
+
+
+
+ +
+
+

Public Static Attributes

+
+
+static const uint8_t MaxDigitsNb
+

The maximum number of digits that the base value can have (int64_t).

+
+ +
+
+

Private Functions

+
+
+explicit HANumeric(const int64_t value)
+
+ +
+
+

Private Members

+
+
+bool _isSet
+
+ +
+
+int64_t _value
+
+ +
+
+uint8_t _precision
+
+ +
+
+

Friends

+
+
+friend class HANumeric
+
+ +
+
+ +
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/docs/documents/api/utils/ha-serializer-array.html b/docs/documents/api/utils/ha-serializer-array.html new file mode 100644 index 0000000..028da4f --- /dev/null +++ b/docs/documents/api/utils/ha-serializer-array.html @@ -0,0 +1,286 @@ + + + + + + + HASerializerArray class - ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

HASerializerArray class

+
+
+class HASerializerArray
+

HASerializerArray represents array of items that can be used as a HASerializer property.

+
+

Public Types

+
+
+typedef const char *ItemType
+
+ +
+
+

Public Functions

+
+
+HASerializerArray(const uint8_t size, const bool progmemItems = true)
+

Constructs HASerializerArray with the static size (number of elements). The array is allocated dynamically in the memory based on the given size.

+
+
Parameters
+
    +
  • size – The desired number of elements that will be stored in the array.

  • +
  • progmemItems – Specifies whether items are going to be stored in the flash memory.

  • +
+
+
+
+ +
+
+~HASerializerArray()
+
+ +
+
+inline uint8_t getItemsNb() const
+

Returns the number of elements that were added to the array. It can be lower than size of the array.

+
+ +
+
+inline ItemType *getItems() const
+

Returns pointer to the array.

+
+ +
+
+bool add(ItemType item)
+

Adds a new element to the array.

+
+
Parameters
+

itemP – Item to add (string).

+
+
Returns
+

Returns true if item has been added to the array successfully.

+
+
+
+ +
+
+uint16_t calculateSize() const
+

Calculates the size of the serialized array (JSON representation).

+
+ +
+
+bool serialize(char *output) const
+

Serializes array as JSON to the given output.

+
+ +
+
+void clear()
+

Clears the array.

+
+ +
+
+

Private Members

+
+
+const bool _progmemItems
+

Specifies whether items are stored in the flash memory.

+
+ +
+
+const uint8_t _size
+

The maximum size of the array.

+
+ +
+
+uint8_t _itemsNb
+

The number of items that were added to the array.

+
+ +
+
+ItemType *_items
+

Pointer to the array elements.

+
+ +
+
+ +
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/docs/documents/api/utils/ha-serializer.html b/docs/documents/api/utils/ha-serializer.html new file mode 100644 index 0000000..f714ca5 --- /dev/null +++ b/docs/documents/api/utils/ha-serializer.html @@ -0,0 +1,560 @@ + + + + + + + HASerializer class - ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

HASerializer class

+
+
+class HASerializer
+

This class allows to create JSON objects easily. Its main purpose is to handle configuration of a device type that’s going to be published to the MQTT broker.

+
+

Public Types

+
+
+enum EntryType
+

Type of the object’s entry.

+

Values:

+
+
+enumerator UnknownEntryType
+
+ +
+
+enumerator PropertyEntryType
+
+ +
+
+enumerator TopicEntryType
+
+ +
+
+enumerator FlagEntryType
+
+ +
+ +
+
+enum FlagType
+

The type of a flag for a FlagEntryType.

+

Values:

+
+
+enumerator WithDevice
+
+ +
+
+enumerator WithAvailability
+
+ +
+ +
+
+enum PropertyValueType
+

Available data types of entries.

+

Values:

+
+
+enumerator UnknownPropertyValueType
+
+ +
+
+enumerator ConstCharPropertyValue
+
+ +
+
+enumerator ProgmemPropertyValue
+
+ +
+
+enumerator BoolPropertyType
+
+ +
+
+enumerator NumberPropertyType
+
+ +
+
+enumerator ArrayPropertyType
+
+ +
+ +
+
+

Public Functions

+
+
+HASerializer(HABaseDeviceType *deviceType, const uint8_t maxEntriesNb)
+

Creates instance of the serializer for the given device type. Please note that the number JSON object’s entries needs to be known upfront. This approach reduces number of memory allocations.

+
+
Parameters
+
    +
  • deviceType – The device type that owns the serializer.

  • +
  • maxEntriesNb – Maximum number of the output object entries.

  • +
+
+
+
+ +
+
+~HASerializer()
+

Frees the dynamic memory allocated by the class.

+
+ +
+
+inline uint8_t getEntriesNb() const
+

Returns the number of items that were added to the serializer.

+
+ +
+
+inline SerializerEntry *getEntries() const
+

Returns pointer to the serializer’s entries.

+
+ +
+
+void set(const __FlashStringHelper *property, const void *value, PropertyValueType valueType = ConstCharPropertyValue)
+

Adds a new entry to the serialized with a type of PropertyEntryType.

+
+
Parameters
+
    +
  • property – Pointer to the name of the property (progmem string).

  • +
  • value – Pointer to the value that’s being set.

  • +
  • valueType – The type of the value that’s passed to the method.

  • +
+
+
+
+ +
+
+void set(const FlagType flag)
+

Adds a new entry to the serializer with a type of FlagEntryType.

+
+
Parameters
+

flag – Flag to add.

+
+
+
+ +
+
+void topic(const __FlashStringHelper *topic)
+

Adds a new entry to the serialize with a type of TopicEntryType.

+
+
Parameters
+

topic – The topic name to add (progmem string).

+
+
+
+ +
+
+uint16_t calculateSize() const
+

Calculates the output size of the serialized JSON object.

+
+ +
+
+bool flush() const
+

Flushes the JSON object to the MQTT stream. Please note that this method only writes the MQTT payload. The MQTT session needs to be opened before.

+
+ +
+
+

Public Static Functions

+
+
+static uint16_t calculateConfigTopicLength(const __FlashStringHelper *component, const char *objectId)
+

Calculates the size of a configuration topic for the given component and object ID. The configuration topic has structure as follows: [discovery prefix]/[component]/[device ID]_[objectId]/config

+
+
Parameters
+
    +
  • component – The name of the HA component (e.g. binary_sensor).

  • +
  • objectId – The unique ID of a device type that’s going to publish the config.

  • +
+
+
+
+ +
+
+static bool generateConfigTopic(char *output, const __FlashStringHelper *component, const char *objectId)
+

Generates the configuration topic for the given component and object ID. The topic will be stored in the output variable.

+
+
Parameters
+
    +
  • output – Buffer where the topic will be written.

  • +
  • component – The name of the HA component (e.g. binary_sensor).

  • +
  • objectId – The unique ID of a device type that’s going to publish the config.

  • +
+
+
+
+ +
+
+static uint16_t calculateDataTopicLength(const char *objectId, const __FlashStringHelper *topic)
+

Calculates the size of the given data topic for the given objectId. The data topic has structure as follows: [data prefix]/[device ID]_[objectId]/[topic]

+
+
Parameters
+
    +
  • objectId – The unique ID of a device type that’s going to publish the data.

  • +
  • topic – The topic name (progmem string).

  • +
+
+
+
+ +
+
+static bool generateDataTopic(char *output, const char *objectId, const __FlashStringHelper *topic)
+

Generates the data topic for the given object ID. The topic will be stored in the output variable.

+
+
Parameters
+
    +
  • output – Buffer where the topic will be written.

  • +
  • objectId – The unique ID of a device type that’s going to publish the data.

  • +
  • topic – The topic name (progmem string).

  • +
+
+
+
+ +
+
+static bool compareDataTopics(const char *actualTopic, const char *objectId, const __FlashStringHelper *topic)
+

Checks whether the given topic matches the data topic that can be generated using the given objectId and topicP. This method can be used to check if the received message matches some data topic.

+
+
Parameters
+
    +
  • actualTopic – The actual topic to compare.

  • +
  • objectId – The unique ID of a device type that may be the owner of the topic.

  • +
  • topic – The topic name (progmem string).

  • +
+
+
+
+ +
+
+

Private Functions

+
+
+SerializerEntry *addEntry()
+

Creates a new entry in the serializer’s memory. If the limit of entries is hit, the nullptr is returned.

+
+ +
+
+uint16_t calculateEntrySize(const SerializerEntry *entry) const
+

Calculates the serialized size of the given entry. Internally, this method recognizes the type of the entry and calls a proper calculate method listed below.

+
+ +
+
+uint16_t calculateTopicEntrySize(const SerializerEntry *entry) const
+

Calculates the size of the entry of type TopicEntryType.

+
+ +
+
+uint16_t calculateFlagSize(const FlagType flag) const
+

Calculates the size of the entry of type FlagEntryType.

+
+ +
+
+uint16_t calculatePropertyValueSize(const SerializerEntry *entry) const
+

Calculates the size of the entry’s value if the entry is PropertyEntryType.

+
+ +
+
+uint16_t calculateArraySize(const HASerializerArray *array) const
+

Calculates the size of the array if the property’s value is a type of ArrayPropertyType.

+
+ +
+
+bool flushEntry(const SerializerEntry *entry) const
+

Flushes the given entry to the MQTT. Internally this method recognizes the type of the entry and calls a proper flush method listed below.

+
+ +
+
+bool flushEntryValue(const SerializerEntry *entry) const
+

Flushes the value of the PropertyEntryType entry.

+
+ +
+
+bool flushTopic(const SerializerEntry *entry) const
+

Flushes the entry of type TopicEntryType to the MQTT.

+
+ +
+
+bool flushFlag(const SerializerEntry *entry) const
+

Flushes the entry of type FlagEntryType to the MQTT.

+
+ +
+
+

Private Members

+
+
+HABaseDeviceType *_deviceType
+

Pointer to the device type that owns the serializer.

+
+ +
+
+uint8_t _entriesNb
+

The number of entries added to the serializer.

+
+ +
+
+uint8_t _maxEntriesNb
+

Maximum number of entries that can be added to the serializer.

+
+ +
+
+SerializerEntry *_entries
+

Pointer to the serializer entries.

+
+ +
+
+
+struct SerializerEntry
+

Representation of a single entry in the object.

+
+

Public Functions

+
+
+inline SerializerEntry()
+
+ +
+
+

Public Members

+
+
+EntryType type
+

Type of the entry.

+
+ +
+
+uint8_t subtype
+

Subtype of the entry. It can be FlagType, PropertyValueType or TopicType.

+
+ +
+
+const __FlashStringHelper *property
+

Pointer to the property name (progmem string).

+
+ +
+
+const void *value
+

Pointer to the property value. The value type is determined by subtype.

+
+ +
+
+ +
+ +
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/docs/documents/api/utils/ha-utils.html b/docs/documents/api/utils/ha-utils.html new file mode 100644 index 0000000..108af1d --- /dev/null +++ b/docs/documents/api/utils/ha-utils.html @@ -0,0 +1,228 @@ + + + + + + + HAUtils class - ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

HAUtils class

+
+
+class HAUtils
+

This class provides some useful methods to make life easier.

+
+

Public Static Functions

+
+
+static bool endsWith(const char *str, const char *suffix)
+

Checks whether the given str ends with the given suffix.

+
+
Parameters
+
    +
  • str – Input string to check.

  • +
  • suffix – Suffix to find

  • +
+
+
Returns
+

True if the given suffix is present at the end of the given string.

+
+
+
+ +
+
+static void byteArrayToStr(char *dst, const byte *src, const uint16_t length)
+

Converts the given byte array into hex string. Each byte will be represented by two bytes, so the output size will be length * 2

+
+
Parameters
+
    +
  • dst – Destination where the string will be saved.

  • +
  • src – Bytes array to convert.

  • +
  • length – Length of the bytes array.

  • +
+
+
+
+ +
+
+static char *byteArrayToStr(const byte *src, const uint16_t length)
+

Converts the given byte array into hex string. This method allocates a new memory.

+
+
Parameters
+
    +
  • src – Bytes array to convert.

  • +
  • length – Length of the bytes array.

  • +
+
+
Returns
+

Newly allocated string containing the hex representation.

+
+
+
+ +
+
+ +
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/docs/documents/api/utils/index.html b/docs/documents/api/utils/index.html new file mode 100644 index 0000000..84a8f28 --- /dev/null +++ b/docs/documents/api/utils/index.html @@ -0,0 +1,185 @@ + + + + + + + Utils API - ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+
+ + + + \ No newline at end of file diff --git a/docs/documents/getting-started/compatible-hardware.html b/docs/documents/getting-started/compatible-hardware.html new file mode 100644 index 0000000..abff820 --- /dev/null +++ b/docs/documents/getting-started/compatible-hardware.html @@ -0,0 +1,200 @@ + + + + + + + Compatible Hardware - ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

Compatible Hardware

+

The library uses the Arduino Ethernet Client API for interacting with the network hardware. +It should work fine as long as the Client class is available.

+

Here is the list of devices on which the library was tested:

+
    +
  • Arduino Uno

  • +
  • Arduino Mega

  • +
  • Arduino Nano

  • +
  • Arduino Pro Mini

  • +
  • Arduino Nano 33 IoT

  • +
  • NodeMCU

  • +
  • Controllino Mega (Pure)

  • +
  • Controllino Maxi (Pure)

  • +
  • ESP-01

  • +
  • ESP32-CAM

  • +
  • Sonoff Dual R2

  • +
  • Sonoff Dual R3

  • +
  • Sonoff Basic

  • +
  • Sonoff Mini

  • +
  • Tuya Wi-Fi switch module

  • +
  • Tuya Wi-Fi curtain module

  • +
+

Please note that it’s not the complete list of supported devices. +You may try to use the library on any device that uses Arduino core.

+
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/docs/documents/getting-started/examples.html b/docs/documents/getting-started/examples.html new file mode 100644 index 0000000..d99b990 --- /dev/null +++ b/docs/documents/getting-started/examples.html @@ -0,0 +1,265 @@ + + + + + + + Examples - ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

Examples

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Example

Description

Binary sensor

Using the binary sensor as a door contact sensor.

Button

Adding simple buttons to the Home Assistant panel.

Camera

Publishing the preview from the ESP32-CAM module.

Cover

Controlling a window cover (open / close / stop).

Device trigger

Implementation of a simple wall switch that reports press and hold states.

Fan

Controlling a simple fan (state + speed).

HVAC

HVAC controller with multiple modes, power control and target temperature.

Lock

A simple door lock that’s controlled by the Home Assistant.

Light

A simple light that allows changing brightness, color temperature and RGB color.

Number

Adding an interactive numeric slider in the Home Assistant panel.

Scene

Adding a custom scene in the Home Assistant panel.

Select

A dropdown selector that’s displayed in the Home Assistant panel.

Sensor

A simple sensor that reports a state in a string representation (open / opening / close).

Analog sensor

Reporting the analog pin’s voltage to the Home Assistant.

Integer sensor

Reporting the device’s uptime to the Home Assistant.

Switch

The LED that’s controlled by the Home Assistant.

Multi-switch

Multiple switches controlled by the Home Assistant.

Tag scanner

Scanning RFID tags using the MFRC522 module.

Availability

Reporting entities’ availability (online / offline) to the Home Assistant.

Advanced availability

Advanced availability reporting with MQTT LWT (Last Will and Testament).

MQTT advanced

Subscribing to custom topics and publishing custom messages.

MQTT with credentials

Establishing connection with a MQTT broker using the credentials.

NodeMCU (ESP8266)

Basic example for ESP8266 devices.

Arduino Nano 33 IoT

Basic example for Arduino Nano 33 IoT (SAMD family).

mDNS discovery

Make your ESP8266 discoverable via the mDNS.

+
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/docs/documents/getting-started/index.html b/docs/documents/getting-started/index.html new file mode 100644 index 0000000..a2f3a6f --- /dev/null +++ b/docs/documents/getting-started/index.html @@ -0,0 +1,191 @@ + + + + + + + Getting started - ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

Getting started

+

Welcome to the ArduinoHA library! +This documentation is a step-by-step guide that presents all features of the library. +If you feel that there is anything unclear don’t hesitate to open a new GitHub discussion.

+

Have fun!

+ +
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/docs/documents/getting-started/installation.html b/docs/documents/getting-started/installation.html new file mode 100644 index 0000000..c06fd63 --- /dev/null +++ b/docs/documents/getting-started/installation.html @@ -0,0 +1,204 @@ + + + + + + + Installation - ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

Installation

+

There are two ways to install the library depending on your project. +If you’re using Arduino IDE to compile your project you only need to install the library into the IDE.

+

The second method is meant for more advanced users that use makeEspArduino for building the project for ESP32/ESP8266 devices.

+
+

Arduino IDE

+

To install the library into your Arduino IDE you can use Library Manager (available from IDE version 1.6.2). +Open the IDE and click to the “Sketch” menu and then Include Library > Manage Libraries.

+../../_images/manage-libraries.png +

Type “home-assistant-integration” in the search field, select the latest version of the library from the dropdown and then click Install.

+../../_images/library-search.png +

For other installation methods please refer to Arduino documentation.

+
+
+

makeEspArduino

+

The library can be installed in an environment managed by makeEspArduino. +The best approach is to add the library and its dependency as submodules in the project as follows:

+
git submodule add https://github.com/dawidchyrzynski/arduino-home-assistant.git arduino-home-assistant
+cd arduino-home-assistant && git checkout tags/2.0.0 && cd ..
+git submodule add https://github.com/knolleary/pubsubclient.git pubsubclient
+cd pubsubclient && git checkout tags/v2.8
+
+
+

Then you just need to add one extra line in your Makefile:

+
LIBS := $(ROOT)/arduino-home-assistant $(ROOT)/pubsubclient
+
+
+
+
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/docs/documents/getting-started/prerequisites.html b/docs/documents/getting-started/prerequisites.html new file mode 100644 index 0000000..c7fd47a --- /dev/null +++ b/docs/documents/getting-started/prerequisites.html @@ -0,0 +1,181 @@ + + + + + + + Prerequisites - ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

Prerequisites

+

ArduinoHA uses MQTT protocol over TCP to communicate with your Home Assistant instance. +The MQTT broker is not installed by default so you will need to install an extra HA addon in order to get the integration working.

+

The recommended setup method is to use the Mosquitto Brokker addon. +After installing the addon your HA instance acts as a broker for all devices you’re going to integrate with it.

+
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/docs/documents/library/availability-reporting.html b/docs/documents/library/availability-reporting.html new file mode 100644 index 0000000..bef39e2 --- /dev/null +++ b/docs/documents/library/availability-reporting.html @@ -0,0 +1,265 @@ + + + + + + + Availability reporting - ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

Availability reporting

+

Home Assistant allows to track online/offline states of devices and device types. +In this way controls available in the panel will be displayed as disabled if a device is offline.

+

The library allows to expose state of the entire device (i.e. shared availability) or specific type (sensor, switch, light, etc.). +By default this feature is not enabled to save resources (RAM and flash) but you can easily turn it on as shown below.

+
+

Shared availability

+

I highly recommend to use shared availability feature as it allows to utilize MQTT LWT. +Basically, shared availability allows to control availability of all types related to a specific device. +For example: if your device has 5 switches and 2 buttons you can control their availability in the HA panel using a single method call.

+

See example below showing how to enable shared availability of the device. +By default, the device is considered online but you can control its state manually using HADevice::setAvailability(bool online) method. +In most cases you won’t need to control availability manually as the library takes care of availability as long as the device is powered on.

+
#include <ArduinoHA.h>
+
+HADevice device("myUniqueID");
+
+void setup() {
+    device.enableSharedAvailability();
+    // device.setAvailability(false); // changes default state to offline
+
+    // ...
+}
+
+void loop() {
+    // ...
+
+    // device.setAvailability(true); // you can control availability manually if you want
+}
+
+
+
+
+

MQTT LWT

+

The shared availability feature is considered a complete solution only if it’s used with MQTT LWT feature. +Without LWT if the device is powered off then Home Assistant displays it as online. +That’s because availability tracking relies on MQTT messages and if you cut off power of your device then its not capable of publishing the offline message.

+

When LWT feature is enabled the device becomes offline in the HA panel even if you cut off power supply. +This solution is implemented by MQTT broker that automatically publishes the message when the TCP connection to the device is lost.

+
#include <ArduinoHA.h>
+
+HADevice device("myUniqueID");
+
+void setup() {
+    device.enableSharedAvailability();
+    device.enableLastWill();
+
+    // ...
+}
+
+void loop() {
+    // ...
+}
+
+
+
+
+

Device type’s availability

+

There also a way to control availability of specific device types. +Each type can be controlled separately as shown below. +Please note that this solution requires shared availability to be disabled and it’s not supported by LWT.

+
#include <Ethernet.h>
+#include <ArduinoHA.h>
+
+byte mac[] = {0x00, 0x10, 0xFA, 0x6E, 0x38, 0x4A};
+EthernetClient client;
+HADevice device(mac, sizeof(mac));
+HAMqtt mqtt(client, device);
+HASwitch mySwitch("mySwitchId");
+
+void setup() {
+    Ethernet.begin(mac);
+
+    // this line enables availability for your switch
+    mySwitch.setAvailability(true); // you can also set it to false
+
+    // ...
+}
+
+void loop() {
+    // ...
+
+    // you can control availability at runtime as follows:
+    mySwitch.setAvailability(true); // online
+    mySwitch.setAvailability(false); // offline
+}
+
+
+
+
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/docs/documents/library/compiler-macros.html b/docs/documents/library/compiler-macros.html new file mode 100644 index 0000000..920ad8d --- /dev/null +++ b/docs/documents/library/compiler-macros.html @@ -0,0 +1,208 @@ + + + + + + + Compiler macros - ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

Compiler macros

+

The library supports couple of macros that are defined in the ArduinoHADefines.h file. +You can uncomment them in this specific file or provide flags directly to compiler (for example: via Makefile).

+
+

Debug mode

+

Debug mode unlocks logging feature in the library. +Logs may be useful for debugging the communication with the Home Assistant.

+

To enable debug mode you need to defined ARDUINOHA_DEBUG macro.

+
+
+

Code optimization

+

Defining one of the macros listed below results in truncating the corresponding device type. +It may be useful if you want to save some flash memory occupied by virtual tables of those classes.

+
    +
  • EX_ARDUINOHA_BINARY_SENSOR

  • +
  • EX_ARDUINOHA_BUTTON

  • +
  • EX_ARDUINOHA_CAMERA

  • +
  • EX_ARDUINOHA_COVER

  • +
  • EX_ARDUINOHA_DEVICE_TRACKER

  • +
  • EX_ARDUINOHA_DEVICE_TRIGGER

  • +
  • EX_ARDUINOHA_FAN

  • +
  • EX_ARDUINOHA_HVAC

  • +
  • EX_ARDUINOHA_LIGHT

  • +
  • EX_ARDUINOHA_LOCK

  • +
  • EX_ARDUINOHA_NUMBER

  • +
  • EX_ARDUINOHA_SCENE

  • +
  • EX_ARDUINOHA_SELECT

  • +
  • EX_ARDUINOHA_SENSOR

  • +
  • EX_ARDUINOHA_SWITCH

  • +
  • EX_ARDUINOHA_TAG_SCANNER

  • +
+
+
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/docs/documents/library/connection-params.html b/docs/documents/library/connection-params.html new file mode 100644 index 0000000..96804f2 --- /dev/null +++ b/docs/documents/library/connection-params.html @@ -0,0 +1,219 @@ + + + + + + + Connection parameters - ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

Connection parameters

+

HAMqtt class exposes a few variants of the begin method that allows specifying the MQTT connection parameters. +This method should be called only once and at the end of the setup logic. +The example below presents all possible variants. Pick one that meets your requirements.

+
+

Note

+

Connection to the MQTT broker is established asynchronously. +The HAMqtt::begin method just sets the parameters of the connection. +The connection attempt is made during the loop cycle.

+
+
#include <Ethernet.h>
+#include <ArduinoHA.h>
+
+byte mac[] = {0x00, 0x10, 0xFA, 0x6E, 0x38, 0x4A};
+EthernetClient client;
+HADevice device(mac, sizeof(mac));
+HAMqtt mqtt(client, device);
+
+void setup() {
+    Ethernet.begin(mac);
+
+    // anoymous connection on default port 1883
+    mqtt.begin("192.168.1.50");
+
+    // anoymous connection on port 8888
+    mqtt.begin("192.168.1.50", 8888);
+
+    // connection with credentials on default port 1883
+    mqtt.begin("192.168.1.50", "username", "password");
+
+    // connection with credentials on port 8888
+    mqtt.begin("192.168.1.50", 8888, "username", "password");
+
+    // you can also use hostname in all variants
+    mqtt.begin("mybroker.local");
+}
+
+void loop() {
+    Ethernet.maintain();
+    mqtt.loop();
+}
+
+
+
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/docs/documents/library/device-configuration.html b/docs/documents/library/device-configuration.html new file mode 100644 index 0000000..ed7e91d --- /dev/null +++ b/docs/documents/library/device-configuration.html @@ -0,0 +1,275 @@ + + + + + + + Device configuration - ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

Device configuration

+

HADevice represents the physical device where the library is installed. +Logically it’s a group of types like sensors, switches, lights and so on. +In the Home Assistant, it’s listed with properties that may be configured using the library’s API.

+

Each property except the unique ID is optional. +Setting optional properties increases flash and RAM usage so it’s not recommended to set them on lower-spec MCUs.

+

The supported properties are:

+
    +
  • unique ID*

  • +
  • name

  • +
  • software version

  • +
  • manufacturer

  • +
  • model

  • +
+
+

Unique ID

+

The ID of a device needs to be unique in a scope of a Home Assistant instance. +The safest solution is to use the MAC address of an Ethernet or Wi-Fi chip but you can also implement your own solution.

+

There are three different ways to set the ID of the device. +You can pick one depending on your needs.

+
+

1) Providing string (const char*) to the HADevice constructor

+

Try to keep the ID simple (alphanumeric characters) and short.

+
#include <ArduinoHA.h>
+
+HADevice device("myUniqueID");
+
+void setup() {
+    // ...
+}
+
+void loop() {
+    // ...
+}
+
+
+
+
+

2) Providing byte array to the HADevice constructor

+
#include <ArduinoHA.h>
+
+// use your own unique bytes sequence
+byte mac[] = {0x00, 0x10, 0xFA, 0x6E, 0x38, 0x4A};
+HADevice device(mac, sizeof(mac));
+
+void setup() {
+    // ...
+}
+
+void loop() {
+    // ...
+}
+
+
+
+
+

3) Using HADevice::setUniqueId method during the setup

+
#include <ArduinoHA.h>
+
+HADevice device;
+
+void setup() {
+    // any length is acceptable
+    byte myId[] = {0x05, 0xb4, 0xc6, 0x9f, 0xbe, 0xce, 0x8c, 0x1f, 0xc7};
+    device.setUniqueId(myId, sizeof(myId)); // the input array is cloned internally
+
+    // ...
+}
+
+void loop() {
+    // ...
+}
+
+
+
+
+
+

Device properties

+

Each property has its corresponding setter method in the HADevice class. +Please note that all these methods accept const char pointer whose content is not copied.

+
#include <ArduinoHA.h>
+
+HADevice device("myUniqueId");
+
+void setup() {
+    device.setName("Bedroom Light Controller");
+    device.setSoftwareVersion("1.0.0");
+    device.setManufacturer("Developer Corp.");
+    device.setModel("ABC-123");
+
+    // ...
+}
+
+void loop() {
+    // ...
+}
+
+
+
+
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/docs/documents/library/device-types.html b/docs/documents/library/device-types.html new file mode 100644 index 0000000..1f8150e --- /dev/null +++ b/docs/documents/library/device-types.html @@ -0,0 +1,312 @@ + + + + + + + Device types - ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

Device types

+

Device type represents a single entity in the Home Assistant panel. +It can be a sensor, lock, camera or anything that’s listed in the table below.

+

Your physical device (for example ESP-01 board) can have multiple device types assigned. +They will be displayed as child entities in the HA panel.

+
+

Limitations

+

Registering a new device type requires some flash and RAM memory to be utilized. +On less powerful units like Arduino Uno, you may quickly hit the limit of resources, so keeping the device simple is recommended. +Hitting the resource limit will result in random reboots of the device.

+

By default, the maximum number of device types is 6. +You can increase the limit using the HAMqtt class constructor as follows:

+
#include <Ethernet.h>
+#include <ArduinoHA.h>
+
+byte mac[] = {0x00, 0x10, 0xFA, 0x6E, 0x38, 0x4A};
+EthernetClient client;
+HADevice device(mac, sizeof(mac));
+HAMqtt mqtt(client, device, 12); // <------------ 12 is a new limit of device types
+
+void setup() {
+    Ethernet.begin(mac);
+
+    // your setup logic goes here
+}
+
+void loop() {
+    Ethernet.maintain();
+    mqtt.loop();
+
+    // your loop logic goes here
+}
+
+
+

Please note that this limit cannot be changed at runtime.

+
+
+

Supported device types

+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Device type

Supported

Documentation

Binary sensor

✅

HABinarySensor

Button

✅

HAButton

Camera

✅

HACamera

Cover

✅

HACover

Device tracker

✅

HADeviceTracker

Device trigger

✅

HADeviceTrigger

Fan

✅

HAFan

Humidifier

❌

–

HVAC

✅

HAHVAC

Light

✅

HALight

Lock

✅

HALock

Number

✅

HANumber

Scene

✅

HAScene

Select

✅

HASelect

+
Sensor (text)
+
+

✅

HASensor

+
Sensor (number)
+
+

✅

HASensorNumber

Switch

✅

HASwitch

Tag scanner

✅

HATagScanner

Vacuum

❌

–

+
+
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/docs/documents/library/discovery.html b/docs/documents/library/discovery.html new file mode 100644 index 0000000..93dacab --- /dev/null +++ b/docs/documents/library/discovery.html @@ -0,0 +1,215 @@ + + + + + + + Discovery - ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

Discovery

+

The library automatically maintains connection to the MQTT broker and takes care of the discovery process. +Each device type that you create (sensor, switch, light, fan, etc.) is automatically registered in MQTT manager. +Whenever connection with the MQTT broker is acquired the configuration of all device types is pushed to the Home Assistant.

+

There is one basic rule that you need to follow: device types need to be constructed after HAMqtt class. +That’s because device types are relying on HAMqtt instance internally.

+
+

Topics prefix

+

In some cases you may need to change prefix of MQTT topics. +There are two types of topics utilized by the library:

+
    +
  • discovery topic - used for publishing device types’ configuration (default: homeassistant)

  • +
  • data topic - used for publishing states, data, etc. (default: aha)

  • +
+

The discovery topic’s prefix can be changed using HAMqtt::setDiscoveryPrefix(const char* prefix) method. +The data topic’s prefix can be changed using HAMqtt::setDataPrefix(const char* prefix) method

+
#include <Ethernet.h>
+#include <ArduinoHA.h>
+
+byte mac[] = {0x00, 0x10, 0xFA, 0x6E, 0x38, 0x4A};
+EthernetClient client;
+HADevice device(mac, sizeof(mac));
+HAMqtt mqtt(client, device);
+
+// register your device types here
+
+void setup() {
+    mqtt.setDiscoveryPrefix("myCustomPrefix");
+    mqtt.setDataPrefix("myDataPrefix");
+
+    // ...
+}
+
+void loop() {
+    // ...
+}
+
+
+
+
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/docs/documents/library/index.html b/docs/documents/library/index.html new file mode 100644 index 0000000..b97d10b --- /dev/null +++ b/docs/documents/library/index.html @@ -0,0 +1,222 @@ + + + + + + + Library - ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+
+ + + + \ No newline at end of file diff --git a/docs/documents/library/introduction.html b/docs/documents/library/introduction.html new file mode 100644 index 0000000..2870fdf --- /dev/null +++ b/docs/documents/library/introduction.html @@ -0,0 +1,251 @@ + + + + + + + Introduction - ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

Introduction

+

Before implementing the business logic of your application you will need to +add a few necessary pieces of code to your project. +Basically, everything comes up to a few basic rules:

+
    +
  1. HADevice and HAMqtt instances need to be initialized once globally or as a part of another global object.

  2. +
  3. HAMqtt::begin needs to be called at the end of setup logic. It provides MQTT broker credentials that will be used for a connection.

  4. +
  5. HAMqtt::loop method needs to be called periodically (it doesn’t need to be called on each tick).

  6. +
  7. Device types need to be initialized after HAMqtt class (it will be described later in the documentation).

  8. +
+

Here are the minimal boilerplates that you can start with. +Don’t worry if you have no idea what’s going on here. +Everything will be covered in the following chapters.

+
+

Arduino Boilerplate

+
#include <Ethernet.h>
+#include <ArduinoHA.h>
+
+byte mac[] = {0x00, 0x10, 0xFA, 0x6E, 0x38, 0x4A};
+EthernetClient client;
+HADevice device(mac, sizeof(mac));
+HAMqtt mqtt(client, device);
+
+void setup() {
+    Ethernet.begin(mac);
+
+    // your setup logic goes here
+
+    // MQTT broker connection (use your data here)
+    mqtt.begin("192.168.1.50", "username", "password");
+}
+
+void loop() {
+    Ethernet.maintain();
+    mqtt.loop();
+
+    // your loop logic goes here
+}
+
+
+
+
+

ESP32/ESP8266 Boilerplate

+
#include <ESP8266WiFi.h>
+#include <ArduinoHA.h>
+
+WiFiClient client;
+HADevice device;
+HAMqtt mqtt(client, device);
+
+void setup() {
+    byte mac[WL_MAC_ADDR_LENGTH];
+    WiFi.macAddress(mac);
+    device.setUniqueId(mac, sizeof(mac));
+
+    // you can skip this part if you're already maintaining the connection logic
+    WiFi.begin("MyNetworkSSID", "MyPassword");
+    while (WiFi.status() != WL_CONNECTED) {
+        delay(500); // waiting for the connection
+    }
+
+    // your setup logic goes here
+
+    // MQTT broker connection (use your data here)
+    mqtt.begin("192.168.1.50", "username", "password");
+}
+
+void loop() {
+    mqtt.loop();
+
+    // your loop logic goes here
+}
+
+
+
+
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/docs/documents/library/mqtt-advanced.html b/docs/documents/library/mqtt-advanced.html new file mode 100644 index 0000000..a750d61 --- /dev/null +++ b/docs/documents/library/mqtt-advanced.html @@ -0,0 +1,279 @@ + + + + + + + MQTT advanced features - ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

MQTT advanced features

+
+

Callbacks

+

HAMqtt class exposes some useful callbacks that you can bind to. +Please take a look at the example below.

+
#include <Ethernet.h>
+#include <ArduinoHA.h>
+
+byte mac[] = {0x00, 0x10, 0xFA, 0x6E, 0x38, 0x4A};
+EthernetClient client;
+HADevice device(mac, sizeof(mac));
+HAMqtt mqtt(client, device);
+
+void onMessage(const char* topic, const uint8_t* payload, uint16_t length) {
+    // this method will be called each time the device receives an MQTT message
+}
+
+void onConnected() {
+    // this method will be called when connection to MQTT broker is established
+}
+
+void setup() {
+    Ethernet.begin(mac);
+
+    mqtt.onMessage(onMessage);
+    mqtt.onConnected(onConnected);
+    mqtt.begin("192.168.1.50", "username", "password");
+}
+
+void loop() {
+    Ethernet.maintain();
+    mqtt.loop();
+}
+
+
+
+
+

Subscriptions

+

You can also subscribe to a custom topic using HAMqtt::subscribe(const char* topic) method. +The subscription needs to be made each time a connection to the MQTT broker is established.

+
#include <Ethernet.h>
+#include <ArduinoHA.h>
+
+byte mac[] = {0x00, 0x10, 0xFA, 0x6E, 0x38, 0x4A};
+EthernetClient client;
+HADevice device(mac, sizeof(mac));
+HAMqtt mqtt(client, device);
+
+void onMessage(const char* topic, const uint8_t* payload, uint16_t length) {
+    if (strcmp(topic, "myTopic") == 0) {
+        // message on "myTopic" received
+    }
+}
+
+void onConnected() {
+    mqtt.subscribe("myTopic");
+}
+
+void setup() {
+    Ethernet.begin(mac);
+
+    mqtt.onMessage(onMessage);
+    mqtt.onConnected(onConnected);
+    mqtt.begin("192.168.1.50", "username", "password");
+}
+
+void loop() {
+    Ethernet.maintain();
+    mqtt.loop();
+}
+
+
+
+
+

Publishing a message

+

HAMqtt class also exposes the method that allows to publish custom messages.

+
#include <Ethernet.h>
+#include <ArduinoHA.h>
+
+byte mac[] = {0x00, 0x10, 0xFA, 0x6E, 0x38, 0x4A};
+EthernetClient client;
+HADevice device(mac, sizeof(mac));
+HAMqtt mqtt(client, device);
+
+void setup() {
+    Ethernet.begin(mac);
+
+    mqtt.begin("192.168.1.50", "username", "password");
+}
+
+void loop() {
+    Ethernet.maintain();
+    mqtt.loop();
+
+    // Publishing the non-retained message:
+    // mqtt.publish("customTopic", "customPayload");
+
+    // Publishing the retained message:
+    // mqtt.publish("customTopic", "customPayload", true);
+}
+
+
+
+
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/docs/documents/library/mqtt-security.html b/docs/documents/library/mqtt-security.html new file mode 100644 index 0000000..2d59859 --- /dev/null +++ b/docs/documents/library/mqtt-security.html @@ -0,0 +1,211 @@ + + + + + + + MQTT security - ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

MQTT security

+

The library allows you to use credentials for acquiring a TCP connection with the MQTT broker. +By default you can use the same credentials you use for login in the Home Assistant panel but you can also configure custom credentials in the Mosquitto broker.

+
+

Danger

+

This solution is not 100% secure because communication between Arduino and Home Assistant is not encrypted. +Username and password can be easily discovered by analyzing your local network traffic. +However, that’s fine as long as your local network is secured against unattended access. +On more powerful devices (like ESP), you should consider using TLS/SSL connection.

+
+
#include <Ethernet.h>
+#include <ArduinoHA.h>
+
+byte mac[] = {0x00, 0x10, 0xFA, 0x6E, 0x38, 0x4A};
+EthernetClient client;
+HADevice device(mac, sizeof(mac));
+HAMqtt mqtt(client, device);
+
+void setup() {
+    // ...
+
+    // replace username and password with your credentials
+    mqtt.begin("192.168.1.50", "username", "password");
+}
+
+void loop() {
+    // ...
+}
+
+
+
+

SSL connection

+

On ESP32/ESP8266 you can use WiFiClientSecure client to establish encrypted connection between your device and Home Assistant. +Please take a look at this example.

+
+
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/docs/genindex.html b/docs/genindex.html new file mode 100644 index 0000000..db8c56c --- /dev/null +++ b/docs/genindex.html @@ -0,0 +1,1599 @@ + + + + + + + Index - ArduinoHA + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +

Index

+ +
+ H + +
+

H

+ + + +
+ + + +
+ +
+
+ + + + \ No newline at end of file diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 0000000..99ebc68 --- /dev/null +++ b/docs/index.html @@ -0,0 +1,279 @@ + + + + + + + ArduinoHA documentation + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

ArduinoHA documentation

+

ArduinoHA allows to integrate an Arduino/ESP based device with Home Assistant using MQTT. +The library is designed to use as low resources (RAM/flash) as possible. +Initially, it was optimized to work on Arduino Uno with Ethernet Shield, +but I successfully use it on ESP8266/ESP8255 boards in my projects.

+
+

Features

+
    +
  • Two-way communication (state reporting and command execution)

  • +
  • MQTT discovery (device is added to the Home Assistant panel automatically)

  • +
  • MQTT Last Will and Testament

  • +
  • Support for custom MQTT messages (publishing and subscribing)

  • +
  • Auto reconnect with MQTT broker

  • +
  • Reporting availability (online/offline states) of a device

  • +
  • Doxygen documentation

  • +
  • Covered by unit tests (AUnit + EpoxyDuino + AUniter)

  • +
+ +
+
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/docs/objects.inv b/docs/objects.inv new file mode 100644 index 0000000..fdbb0df Binary files /dev/null and b/docs/objects.inv differ diff --git a/docs/search.html b/docs/search.html new file mode 100644 index 0000000..f6241ad --- /dev/null +++ b/docs/search.html @@ -0,0 +1,185 @@ + + + + + + Search - ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + ArduinoHA + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +

Search

+
+

+ Please activate JavaScript to enable the search + functionality. +

+
+

+ From here you can search these documents. Enter your search + words into the box below and click "search". Note that the search + function will automatically search for all of the words. Pages + containing fewer words won't appear in the result list. +

+
+ + + +
+ +
+ +
+ +
+ +
+
+ + + + + \ No newline at end of file diff --git a/docs/searchindex.js b/docs/searchindex.js new file mode 100644 index 0000000..155bcfc --- /dev/null +++ b/docs/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({docnames:["documents/api/core/ha-device","documents/api/core/ha-mqtt","documents/api/core/index","documents/api/device-types/ha-base-device-type","documents/api/device-types/ha-binary-sensor","documents/api/device-types/ha-button","documents/api/device-types/ha-camera","documents/api/device-types/ha-cover","documents/api/device-types/ha-device-tracker","documents/api/device-types/ha-device-trigger","documents/api/device-types/ha-fan","documents/api/device-types/ha-hvac","documents/api/device-types/ha-light","documents/api/device-types/ha-lock","documents/api/device-types/ha-number","documents/api/device-types/ha-scene","documents/api/device-types/ha-select","documents/api/device-types/ha-sensor","documents/api/device-types/ha-sensor-number","documents/api/device-types/ha-switch","documents/api/device-types/ha-tag-scanner","documents/api/device-types/index","documents/api/index","documents/api/utils/ha-numeric","documents/api/utils/ha-serializer","documents/api/utils/ha-serializer-array","documents/api/utils/ha-utils","documents/api/utils/index","documents/getting-started/compatible-hardware","documents/getting-started/examples","documents/getting-started/index","documents/getting-started/installation","documents/getting-started/prerequisites","documents/library/availability-reporting","documents/library/compiler-macros","documents/library/connection-params","documents/library/device-configuration","documents/library/device-types","documents/library/discovery","documents/library/index","documents/library/introduction","documents/library/mqtt-advanced","documents/library/mqtt-security","index"],envversion:{"sphinx.domains.c":2,"sphinx.domains.changeset":1,"sphinx.domains.citation":1,"sphinx.domains.cpp":5,"sphinx.domains.index":1,"sphinx.domains.javascript":2,"sphinx.domains.math":2,"sphinx.domains.python":3,"sphinx.domains.rst":2,"sphinx.domains.std":2,sphinx:56},filenames:["documents/api/core/ha-device.rst","documents/api/core/ha-mqtt.rst","documents/api/core/index.rst","documents/api/device-types/ha-base-device-type.rst","documents/api/device-types/ha-binary-sensor.rst","documents/api/device-types/ha-button.rst","documents/api/device-types/ha-camera.rst","documents/api/device-types/ha-cover.rst","documents/api/device-types/ha-device-tracker.rst","documents/api/device-types/ha-device-trigger.rst","documents/api/device-types/ha-fan.rst","documents/api/device-types/ha-hvac.rst","documents/api/device-types/ha-light.rst","documents/api/device-types/ha-lock.rst","documents/api/device-types/ha-number.rst","documents/api/device-types/ha-scene.rst","documents/api/device-types/ha-select.rst","documents/api/device-types/ha-sensor.rst","documents/api/device-types/ha-sensor-number.rst","documents/api/device-types/ha-switch.rst","documents/api/device-types/ha-tag-scanner.rst","documents/api/device-types/index.rst","documents/api/index.rst","documents/api/utils/ha-numeric.rst","documents/api/utils/ha-serializer.rst","documents/api/utils/ha-serializer-array.rst","documents/api/utils/ha-utils.rst","documents/api/utils/index.rst","documents/getting-started/compatible-hardware.rst","documents/getting-started/examples.rst","documents/getting-started/index.rst","documents/getting-started/installation.rst","documents/getting-started/prerequisites.rst","documents/library/availability-reporting.rst","documents/library/compiler-macros.rst","documents/library/connection-params.rst","documents/library/device-configuration.rst","documents/library/device-types.rst","documents/library/discovery.rst","documents/library/index.rst","documents/library/introduction.rst","documents/library/mqtt-advanced.rst","documents/library/mqtt-security.rst","index.rst"],objects:{"":[[3,0,1,"_CPPv416HABaseDeviceType","HABaseDeviceType"],[3,1,1,"_CPPv4N16HABaseDeviceType12AvailabilityE","HABaseDeviceType::Availability"],[3,2,1,"_CPPv4N16HABaseDeviceType12Availability19AvailabilityDefaultE","HABaseDeviceType::Availability::AvailabilityDefault"],[3,2,1,"_CPPv4N16HABaseDeviceType12Availability19AvailabilityOfflineE","HABaseDeviceType::Availability::AvailabilityOffline"],[3,2,1,"_CPPv4N16HABaseDeviceType12Availability18AvailabilityOnlineE","HABaseDeviceType::Availability::AvailabilityOnline"],[3,2,1,"_CPPv4N16HABaseDeviceType12Availability19AvailabilityDefaultE","HABaseDeviceType::AvailabilityDefault"],[3,2,1,"_CPPv4N16HABaseDeviceType12Availability19AvailabilityOfflineE","HABaseDeviceType::AvailabilityOffline"],[3,2,1,"_CPPv4N16HABaseDeviceType12Availability18AvailabilityOnlineE","HABaseDeviceType::AvailabilityOnline"],[3,3,1,"_CPPv4N16HABaseDeviceType16HABaseDeviceTypeEPK19__FlashStringHelperPKc","HABaseDeviceType::HABaseDeviceType"],[3,4,1,"_CPPv4N16HABaseDeviceType16HABaseDeviceTypeEPK19__FlashStringHelperPKc","HABaseDeviceType::HABaseDeviceType::componentName"],[3,4,1,"_CPPv4N16HABaseDeviceType16HABaseDeviceTypeEPK19__FlashStringHelperPKc","HABaseDeviceType::HABaseDeviceType::uniqueId"],[3,1,1,"_CPPv4N16HABaseDeviceType15NumberPrecisionE","HABaseDeviceType::NumberPrecision"],[3,2,1,"_CPPv4N16HABaseDeviceType15NumberPrecision11PrecisionP0E","HABaseDeviceType::NumberPrecision::PrecisionP0"],[3,2,1,"_CPPv4N16HABaseDeviceType15NumberPrecision11PrecisionP1E","HABaseDeviceType::NumberPrecision::PrecisionP1"],[3,2,1,"_CPPv4N16HABaseDeviceType15NumberPrecision11PrecisionP2E","HABaseDeviceType::NumberPrecision::PrecisionP2"],[3,2,1,"_CPPv4N16HABaseDeviceType15NumberPrecision11PrecisionP3E","HABaseDeviceType::NumberPrecision::PrecisionP3"],[3,2,1,"_CPPv4N16HABaseDeviceType15NumberPrecision11PrecisionP0E","HABaseDeviceType::PrecisionP0"],[3,2,1,"_CPPv4N16HABaseDeviceType15NumberPrecision11PrecisionP1E","HABaseDeviceType::PrecisionP1"],[3,2,1,"_CPPv4N16HABaseDeviceType15NumberPrecision11PrecisionP2E","HABaseDeviceType::PrecisionP2"],[3,2,1,"_CPPv4N16HABaseDeviceType15NumberPrecision11PrecisionP3E","HABaseDeviceType::PrecisionP3"],[3,5,1,"_CPPv4N16HABaseDeviceType13_availabilityE","HABaseDeviceType::_availability"],[3,5,1,"_CPPv4N16HABaseDeviceType14_componentNameE","HABaseDeviceType::_componentName"],[3,5,1,"_CPPv4N16HABaseDeviceType5_nameE","HABaseDeviceType::_name"],[3,5,1,"_CPPv4N16HABaseDeviceType11_serializerE","HABaseDeviceType::_serializer"],[3,5,1,"_CPPv4N16HABaseDeviceType9_uniqueIdE","HABaseDeviceType::_uniqueId"],[3,3,1,"_CPPv4N16HABaseDeviceType15buildSerializerEv","HABaseDeviceType::buildSerializer"],[3,3,1,"_CPPv4NK16HABaseDeviceType13componentNameEv","HABaseDeviceType::componentName"],[3,3,1,"_CPPv4N16HABaseDeviceType17destroySerializerEv","HABaseDeviceType::destroySerializer"],[3,3,1,"_CPPv4NK16HABaseDeviceType7getNameEv","HABaseDeviceType::getName"],[3,3,1,"_CPPv4NK16HABaseDeviceType24isAvailabilityConfiguredEv","HABaseDeviceType::isAvailabilityConfigured"],[3,3,1,"_CPPv4NK16HABaseDeviceType8isOnlineEv","HABaseDeviceType::isOnline"],[3,3,1,"_CPPv4N16HABaseDeviceType4mqttEv","HABaseDeviceType::mqtt"],[3,3,1,"_CPPv4N16HABaseDeviceType15onMqttConnectedEv","HABaseDeviceType::onMqttConnected"],[3,3,1,"_CPPv4N16HABaseDeviceType13onMqttMessageEPKcPK7uint8_tK8uint16_t","HABaseDeviceType::onMqttMessage"],[3,4,1,"_CPPv4N16HABaseDeviceType13onMqttMessageEPKcPK7uint8_tK8uint16_t","HABaseDeviceType::onMqttMessage::length"],[3,4,1,"_CPPv4N16HABaseDeviceType13onMqttMessageEPKcPK7uint8_tK8uint16_t","HABaseDeviceType::onMqttMessage::payload"],[3,4,1,"_CPPv4N16HABaseDeviceType13onMqttMessageEPKcPK7uint8_tK8uint16_t","HABaseDeviceType::onMqttMessage::topic"],[3,3,1,"_CPPv4N16HABaseDeviceType19publishAvailabilityEv","HABaseDeviceType::publishAvailability"],[3,3,1,"_CPPv4N16HABaseDeviceType13publishConfigEv","HABaseDeviceType::publishConfig"],[3,3,1,"_CPPv4N16HABaseDeviceType18publishOnDataTopicEPK19__FlashStringHelperPK19__FlashStringHelperb","HABaseDeviceType::publishOnDataTopic"],[3,3,1,"_CPPv4N16HABaseDeviceType18publishOnDataTopicEPK19__FlashStringHelperPK7uint8_tK8uint16_tbb","HABaseDeviceType::publishOnDataTopic"],[3,3,1,"_CPPv4N16HABaseDeviceType18publishOnDataTopicEPK19__FlashStringHelperPKcb","HABaseDeviceType::publishOnDataTopic"],[3,4,1,"_CPPv4N16HABaseDeviceType18publishOnDataTopicEPK19__FlashStringHelperPK7uint8_tK8uint16_tbb","HABaseDeviceType::publishOnDataTopic::isProgmemData"],[3,4,1,"_CPPv4N16HABaseDeviceType18publishOnDataTopicEPK19__FlashStringHelperPK7uint8_tK8uint16_tbb","HABaseDeviceType::publishOnDataTopic::length"],[3,4,1,"_CPPv4N16HABaseDeviceType18publishOnDataTopicEPK19__FlashStringHelperPK19__FlashStringHelperb","HABaseDeviceType::publishOnDataTopic::payload"],[3,4,1,"_CPPv4N16HABaseDeviceType18publishOnDataTopicEPK19__FlashStringHelperPK7uint8_tK8uint16_tbb","HABaseDeviceType::publishOnDataTopic::payload"],[3,4,1,"_CPPv4N16HABaseDeviceType18publishOnDataTopicEPK19__FlashStringHelperPKcb","HABaseDeviceType::publishOnDataTopic::payload"],[3,4,1,"_CPPv4N16HABaseDeviceType18publishOnDataTopicEPK19__FlashStringHelperPK19__FlashStringHelperb","HABaseDeviceType::publishOnDataTopic::retained"],[3,4,1,"_CPPv4N16HABaseDeviceType18publishOnDataTopicEPK19__FlashStringHelperPK7uint8_tK8uint16_tbb","HABaseDeviceType::publishOnDataTopic::retained"],[3,4,1,"_CPPv4N16HABaseDeviceType18publishOnDataTopicEPK19__FlashStringHelperPKcb","HABaseDeviceType::publishOnDataTopic::retained"],[3,4,1,"_CPPv4N16HABaseDeviceType18publishOnDataTopicEPK19__FlashStringHelperPK19__FlashStringHelperb","HABaseDeviceType::publishOnDataTopic::topic"],[3,4,1,"_CPPv4N16HABaseDeviceType18publishOnDataTopicEPK19__FlashStringHelperPK7uint8_tK8uint16_tbb","HABaseDeviceType::publishOnDataTopic::topic"],[3,4,1,"_CPPv4N16HABaseDeviceType18publishOnDataTopicEPK19__FlashStringHelperPKcb","HABaseDeviceType::publishOnDataTopic::topic"],[3,3,1,"_CPPv4N16HABaseDeviceType15setAvailabilityEb","HABaseDeviceType::setAvailability"],[3,4,1,"_CPPv4N16HABaseDeviceType15setAvailabilityEb","HABaseDeviceType::setAvailability::online"],[3,3,1,"_CPPv4N16HABaseDeviceType7setNameEPKc","HABaseDeviceType::setName"],[3,4,1,"_CPPv4N16HABaseDeviceType7setNameEPKc","HABaseDeviceType::setName::name"],[3,3,1,"_CPPv4N16HABaseDeviceType14subscribeTopicEPKcPK19__FlashStringHelper","HABaseDeviceType::subscribeTopic"],[3,4,1,"_CPPv4N16HABaseDeviceType14subscribeTopicEPKcPK19__FlashStringHelper","HABaseDeviceType::subscribeTopic::topic"],[3,4,1,"_CPPv4N16HABaseDeviceType14subscribeTopicEPKcPK19__FlashStringHelper","HABaseDeviceType::subscribeTopic::uniqueId"],[3,3,1,"_CPPv4NK16HABaseDeviceType8uniqueIdEv","HABaseDeviceType::uniqueId"],[4,0,1,"_CPPv414HABinarySensor","HABinarySensor"],[4,3,1,"_CPPv4N14HABinarySensor14HABinarySensorEPKc","HABinarySensor::HABinarySensor"],[4,4,1,"_CPPv4N14HABinarySensor14HABinarySensorEPKc","HABinarySensor::HABinarySensor::uniqueId"],[4,5,1,"_CPPv4N14HABinarySensor6_classE","HABinarySensor::_class"],[4,5,1,"_CPPv4N14HABinarySensor13_currentStateE","HABinarySensor::_currentState"],[4,5,1,"_CPPv4N14HABinarySensor5_iconE","HABinarySensor::_icon"],[4,3,1,"_CPPv4N14HABinarySensor15buildSerializerEv","HABinarySensor::buildSerializer"],[4,3,1,"_CPPv4NK14HABinarySensor15getCurrentStateEv","HABinarySensor::getCurrentState"],[4,3,1,"_CPPv4N14HABinarySensor15onMqttConnectedEv","HABinarySensor::onMqttConnected"],[4,3,1,"_CPPv4N14HABinarySensor12publishStateEb","HABinarySensor::publishState"],[4,4,1,"_CPPv4N14HABinarySensor12publishStateEb","HABinarySensor::publishState::state"],[4,3,1,"_CPPv4N14HABinarySensor15setCurrentStateEKb","HABinarySensor::setCurrentState"],[4,4,1,"_CPPv4N14HABinarySensor15setCurrentStateEKb","HABinarySensor::setCurrentState::state"],[4,3,1,"_CPPv4N14HABinarySensor14setDeviceClassEPKc","HABinarySensor::setDeviceClass"],[4,4,1,"_CPPv4N14HABinarySensor14setDeviceClassEPKc","HABinarySensor::setDeviceClass::deviceClass"],[4,3,1,"_CPPv4N14HABinarySensor7setIconEPKc","HABinarySensor::setIcon"],[4,4,1,"_CPPv4N14HABinarySensor7setIconEPKc","HABinarySensor::setIcon::icon"],[4,3,1,"_CPPv4N14HABinarySensor8setStateEKbKb","HABinarySensor::setState"],[4,4,1,"_CPPv4N14HABinarySensor8setStateEKbKb","HABinarySensor::setState::force"],[4,4,1,"_CPPv4N14HABinarySensor8setStateEKbKb","HABinarySensor::setState::state"],[5,0,1,"_CPPv48HAButton","HAButton"],[5,3,1,"_CPPv4N8HAButton8HAButtonEPKc","HAButton::HAButton"],[5,4,1,"_CPPv4N8HAButton8HAButtonEPKc","HAButton::HAButton::uniqueId"],[5,5,1,"_CPPv4N8HAButton6_classE","HAButton::_class"],[5,5,1,"_CPPv4N8HAButton16_commandCallbackE","HAButton::_commandCallback"],[5,5,1,"_CPPv4N8HAButton5_iconE","HAButton::_icon"],[5,5,1,"_CPPv4N8HAButton7_retainE","HAButton::_retain"],[5,3,1,"_CPPv4N8HAButton15buildSerializerEv","HAButton::buildSerializer"],[5,3,1,"_CPPv4N8HAButton9onCommandEPFvP8HAButtonE","HAButton::onCommand"],[5,4,1,"_CPPv4N8HAButton9onCommandEPFvP8HAButtonE","HAButton::onCommand::callback"],[5,3,1,"_CPPv4N8HAButton15onMqttConnectedEv","HAButton::onMqttConnected"],[5,3,1,"_CPPv4N8HAButton13onMqttMessageEPKcPK7uint8_tK8uint16_t","HAButton::onMqttMessage"],[5,4,1,"_CPPv4N8HAButton13onMqttMessageEPKcPK7uint8_tK8uint16_t","HAButton::onMqttMessage::length"],[5,4,1,"_CPPv4N8HAButton13onMqttMessageEPKcPK7uint8_tK8uint16_t","HAButton::onMqttMessage::payload"],[5,4,1,"_CPPv4N8HAButton13onMqttMessageEPKcPK7uint8_tK8uint16_t","HAButton::onMqttMessage::topic"],[5,3,1,"_CPPv4N8HAButton14setDeviceClassEPKc","HAButton::setDeviceClass"],[5,4,1,"_CPPv4N8HAButton14setDeviceClassEPKc","HAButton::setDeviceClass::deviceClass"],[5,3,1,"_CPPv4N8HAButton7setIconEPKc","HAButton::setIcon"],[5,4,1,"_CPPv4N8HAButton7setIconEPKc","HAButton::setIcon::icon"],[5,3,1,"_CPPv4N8HAButton9setRetainEKb","HAButton::setRetain"],[5,4,1,"_CPPv4N8HAButton9setRetainEKb","HAButton::setRetain::retain"],[6,0,1,"_CPPv48HACamera","HACamera"],[6,2,1,"_CPPv4N8HACamera13ImageEncoding14EncodingBase64E","HACamera::EncodingBase64"],[6,2,1,"_CPPv4N8HACamera13ImageEncoding14EncodingBinaryE","HACamera::EncodingBinary"],[6,3,1,"_CPPv4N8HACamera8HACameraEPKc","HACamera::HACamera"],[6,4,1,"_CPPv4N8HACamera8HACameraEPKc","HACamera::HACamera::uniqueId"],[6,1,1,"_CPPv4N8HACamera13ImageEncodingE","HACamera::ImageEncoding"],[6,2,1,"_CPPv4N8HACamera13ImageEncoding14EncodingBase64E","HACamera::ImageEncoding::EncodingBase64"],[6,2,1,"_CPPv4N8HACamera13ImageEncoding14EncodingBinaryE","HACamera::ImageEncoding::EncodingBinary"],[6,5,1,"_CPPv4N8HACamera9_encodingE","HACamera::_encoding"],[6,5,1,"_CPPv4N8HACamera5_iconE","HACamera::_icon"],[6,3,1,"_CPPv4N8HACamera15buildSerializerEv","HACamera::buildSerializer"],[6,3,1,"_CPPv4NK8HACamera19getEncodingPropertyEv","HACamera::getEncodingProperty"],[6,3,1,"_CPPv4N8HACamera15onMqttConnectedEv","HACamera::onMqttConnected"],[6,3,1,"_CPPv4N8HACamera12publishImageEPK7uint8_tK8uint16_t","HACamera::publishImage"],[6,4,1,"_CPPv4N8HACamera12publishImageEPK7uint8_tK8uint16_t","HACamera::publishImage::data"],[6,4,1,"_CPPv4N8HACamera12publishImageEPK7uint8_tK8uint16_t","HACamera::publishImage::length"],[6,3,1,"_CPPv4N8HACamera11setEncodingEK13ImageEncoding","HACamera::setEncoding"],[6,4,1,"_CPPv4N8HACamera11setEncodingEK13ImageEncoding","HACamera::setEncoding::encoding"],[6,3,1,"_CPPv4N8HACamera7setIconEPKc","HACamera::setIcon"],[6,4,1,"_CPPv4N8HACamera7setIconEPKc","HACamera::setIcon::icon"],[7,0,1,"_CPPv47HACover","HACover"],[7,2,1,"_CPPv4N7HACover12CoverCommand12CommandCloseE","HACover::CommandClose"],[7,2,1,"_CPPv4N7HACover12CoverCommand11CommandOpenE","HACover::CommandOpen"],[7,2,1,"_CPPv4N7HACover12CoverCommand11CommandStopE","HACover::CommandStop"],[7,1,1,"_CPPv4N7HACover12CoverCommandE","HACover::CoverCommand"],[7,2,1,"_CPPv4N7HACover12CoverCommand12CommandCloseE","HACover::CoverCommand::CommandClose"],[7,2,1,"_CPPv4N7HACover12CoverCommand11CommandOpenE","HACover::CoverCommand::CommandOpen"],[7,2,1,"_CPPv4N7HACover12CoverCommand11CommandStopE","HACover::CoverCommand::CommandStop"],[7,1,1,"_CPPv4N7HACover10CoverStateE","HACover::CoverState"],[7,2,1,"_CPPv4N7HACover10CoverState11StateClosedE","HACover::CoverState::StateClosed"],[7,2,1,"_CPPv4N7HACover10CoverState12StateClosingE","HACover::CoverState::StateClosing"],[7,2,1,"_CPPv4N7HACover10CoverState9StateOpenE","HACover::CoverState::StateOpen"],[7,2,1,"_CPPv4N7HACover10CoverState12StateOpeningE","HACover::CoverState::StateOpening"],[7,2,1,"_CPPv4N7HACover10CoverState12StateStoppedE","HACover::CoverState::StateStopped"],[7,2,1,"_CPPv4N7HACover10CoverState12StateUnknownE","HACover::CoverState::StateUnknown"],[7,2,1,"_CPPv4N7HACover8Features15DefaultFeaturesE","HACover::DefaultFeatures"],[7,5,1,"_CPPv4N7HACover15DefaultPositionE","HACover::DefaultPosition"],[7,1,1,"_CPPv4N7HACover8FeaturesE","HACover::Features"],[7,2,1,"_CPPv4N7HACover8Features15DefaultFeaturesE","HACover::Features::DefaultFeatures"],[7,2,1,"_CPPv4N7HACover8Features15PositionFeatureE","HACover::Features::PositionFeature"],[7,3,1,"_CPPv4N7HACover7HACoverEPKcK8Features","HACover::HACover"],[7,4,1,"_CPPv4N7HACover7HACoverEPKcK8Features","HACover::HACover::features"],[7,4,1,"_CPPv4N7HACover7HACoverEPKcK8Features","HACover::HACover::uniqueId"],[7,2,1,"_CPPv4N7HACover8Features15PositionFeatureE","HACover::PositionFeature"],[7,2,1,"_CPPv4N7HACover10CoverState11StateClosedE","HACover::StateClosed"],[7,2,1,"_CPPv4N7HACover10CoverState12StateClosingE","HACover::StateClosing"],[7,2,1,"_CPPv4N7HACover10CoverState9StateOpenE","HACover::StateOpen"],[7,2,1,"_CPPv4N7HACover10CoverState12StateOpeningE","HACover::StateOpening"],[7,2,1,"_CPPv4N7HACover10CoverState12StateStoppedE","HACover::StateStopped"],[7,2,1,"_CPPv4N7HACover10CoverState12StateUnknownE","HACover::StateUnknown"],[7,5,1,"_CPPv4N7HACover6_classE","HACover::_class"],[7,5,1,"_CPPv4N7HACover16_commandCallbackE","HACover::_commandCallback"],[7,5,1,"_CPPv4N7HACover16_currentPositionE","HACover::_currentPosition"],[7,5,1,"_CPPv4N7HACover13_currentStateE","HACover::_currentState"],[7,5,1,"_CPPv4N7HACover9_featuresE","HACover::_features"],[7,5,1,"_CPPv4N7HACover5_iconE","HACover::_icon"],[7,5,1,"_CPPv4N7HACover11_optimisticE","HACover::_optimistic"],[7,5,1,"_CPPv4N7HACover7_retainE","HACover::_retain"],[7,3,1,"_CPPv4N7HACover15buildSerializerEv","HACover::buildSerializer"],[7,3,1,"_CPPv4NK7HACover18getCurrentPositionEv","HACover::getCurrentPosition"],[7,3,1,"_CPPv4NK7HACover15getCurrentStateEv","HACover::getCurrentState"],[7,3,1,"_CPPv4N7HACover13handleCommandEPK7uint8_tK8uint16_t","HACover::handleCommand"],[7,4,1,"_CPPv4N7HACover13handleCommandEPK7uint8_tK8uint16_t","HACover::handleCommand::cmd"],[7,4,1,"_CPPv4N7HACover13handleCommandEPK7uint8_tK8uint16_t","HACover::handleCommand::length"],[7,3,1,"_CPPv4N7HACover9onCommandEPFv12CoverCommandP7HACoverE","HACover::onCommand"],[7,4,1,"_CPPv4N7HACover9onCommandEPFv12CoverCommandP7HACoverE","HACover::onCommand::callback"],[7,3,1,"_CPPv4N7HACover15onMqttConnectedEv","HACover::onMqttConnected"],[7,3,1,"_CPPv4N7HACover13onMqttMessageEPKcPK7uint8_tK8uint16_t","HACover::onMqttMessage"],[7,4,1,"_CPPv4N7HACover13onMqttMessageEPKcPK7uint8_tK8uint16_t","HACover::onMqttMessage::length"],[7,4,1,"_CPPv4N7HACover13onMqttMessageEPKcPK7uint8_tK8uint16_t","HACover::onMqttMessage::payload"],[7,4,1,"_CPPv4N7HACover13onMqttMessageEPKcPK7uint8_tK8uint16_t","HACover::onMqttMessage::topic"],[7,3,1,"_CPPv4N7HACover15publishPositionEK7int16_t","HACover::publishPosition"],[7,4,1,"_CPPv4N7HACover15publishPositionEK7int16_t","HACover::publishPosition::position"],[7,3,1,"_CPPv4N7HACover12publishStateEK10CoverState","HACover::publishState"],[7,4,1,"_CPPv4N7HACover12publishStateEK10CoverState","HACover::publishState::state"],[7,3,1,"_CPPv4N7HACover18setCurrentPositionEK7int16_t","HACover::setCurrentPosition"],[7,4,1,"_CPPv4N7HACover18setCurrentPositionEK7int16_t","HACover::setCurrentPosition::position"],[7,3,1,"_CPPv4N7HACover15setCurrentStateEK10CoverState","HACover::setCurrentState"],[7,4,1,"_CPPv4N7HACover15setCurrentStateEK10CoverState","HACover::setCurrentState::state"],[7,3,1,"_CPPv4N7HACover14setDeviceClassEPKc","HACover::setDeviceClass"],[7,4,1,"_CPPv4N7HACover14setDeviceClassEPKc","HACover::setDeviceClass::deviceClass"],[7,3,1,"_CPPv4N7HACover7setIconEPKc","HACover::setIcon"],[7,4,1,"_CPPv4N7HACover7setIconEPKc","HACover::setIcon::icon"],[7,3,1,"_CPPv4N7HACover13setOptimisticEKb","HACover::setOptimistic"],[7,4,1,"_CPPv4N7HACover13setOptimisticEKb","HACover::setOptimistic::optimistic"],[7,3,1,"_CPPv4N7HACover11setPositionEK7int16_tKb","HACover::setPosition"],[7,4,1,"_CPPv4N7HACover11setPositionEK7int16_tKb","HACover::setPosition::force"],[7,4,1,"_CPPv4N7HACover11setPositionEK7int16_tKb","HACover::setPosition::position"],[7,3,1,"_CPPv4N7HACover9setRetainEKb","HACover::setRetain"],[7,4,1,"_CPPv4N7HACover9setRetainEKb","HACover::setRetain::retain"],[7,3,1,"_CPPv4N7HACover8setStateEK10CoverStateKb","HACover::setState"],[7,4,1,"_CPPv4N7HACover8setStateEK10CoverStateKb","HACover::setState::force"],[7,4,1,"_CPPv4N7HACover8setStateEK10CoverStateKb","HACover::setState::state"],[0,0,1,"_CPPv48HADevice","HADevice"],[0,3,1,"_CPPv4N8HADevice8HADeviceEPK4byteK8uint16_t","HADevice::HADevice"],[0,3,1,"_CPPv4N8HADevice8HADeviceEPKc","HADevice::HADevice"],[0,3,1,"_CPPv4N8HADevice8HADeviceEv","HADevice::HADevice"],[0,4,1,"_CPPv4N8HADevice8HADeviceEPK4byteK8uint16_t","HADevice::HADevice::length"],[0,4,1,"_CPPv4N8HADevice8HADeviceEPK4byteK8uint16_t","HADevice::HADevice::uniqueId"],[0,4,1,"_CPPv4N8HADevice8HADeviceEPKc","HADevice::HADevice::uniqueId"],[0,5,1,"_CPPv4N8HADevice18_availabilityTopicE","HADevice::_availabilityTopic"],[0,5,1,"_CPPv4N8HADevice10_availableE","HADevice::_available"],[0,5,1,"_CPPv4N8HADevice13_ownsUniqueIdE","HADevice::_ownsUniqueId"],[0,5,1,"_CPPv4N8HADevice11_serializerE","HADevice::_serializer"],[0,5,1,"_CPPv4N8HADevice19_sharedAvailabilityE","HADevice::_sharedAvailability"],[0,5,1,"_CPPv4N8HADevice9_uniqueIdE","HADevice::_uniqueId"],[0,3,1,"_CPPv4N8HADevice14enableLastWillEv","HADevice::enableLastWill"],[0,3,1,"_CPPv4N8HADevice24enableSharedAvailabilityEv","HADevice::enableSharedAvailability"],[0,3,1,"_CPPv4NK8HADevice20getAvailabilityTopicEv","HADevice::getAvailabilityTopic"],[0,3,1,"_CPPv4NK8HADevice13getSerializerEv","HADevice::getSerializer"],[0,3,1,"_CPPv4NK8HADevice11getUniqueIdEv","HADevice::getUniqueId"],[0,3,1,"_CPPv4NK8HADevice11isAvailableEv","HADevice::isAvailable"],[0,3,1,"_CPPv4NK8HADevice27isSharedAvailabilityEnabledEv","HADevice::isSharedAvailabilityEnabled"],[0,3,1,"_CPPv4NK8HADevice19publishAvailabilityEv","HADevice::publishAvailability"],[0,3,1,"_CPPv4N8HADevice15setAvailabilityEb","HADevice::setAvailability"],[0,4,1,"_CPPv4N8HADevice15setAvailabilityEb","HADevice::setAvailability::online"],[0,3,1,"_CPPv4N8HADevice15setManufacturerEPKc","HADevice::setManufacturer"],[0,4,1,"_CPPv4N8HADevice15setManufacturerEPKc","HADevice::setManufacturer::manufacturer"],[0,3,1,"_CPPv4N8HADevice8setModelEPKc","HADevice::setModel"],[0,4,1,"_CPPv4N8HADevice8setModelEPKc","HADevice::setModel::model"],[0,3,1,"_CPPv4N8HADevice7setNameEPKc","HADevice::setName"],[0,4,1,"_CPPv4N8HADevice7setNameEPKc","HADevice::setName::name"],[0,3,1,"_CPPv4N8HADevice18setSoftwareVersionEPKc","HADevice::setSoftwareVersion"],[0,4,1,"_CPPv4N8HADevice18setSoftwareVersionEPKc","HADevice::setSoftwareVersion::softwareVersion"],[0,3,1,"_CPPv4N8HADevice11setUniqueIdEPK4byteK8uint16_t","HADevice::setUniqueId"],[0,4,1,"_CPPv4N8HADevice11setUniqueIdEPK4byteK8uint16_t","HADevice::setUniqueId::length"],[0,4,1,"_CPPv4N8HADevice11setUniqueIdEPK4byteK8uint16_t","HADevice::setUniqueId::uniqueId"],[0,3,1,"_CPPv4N8HADeviceD0Ev","HADevice::~HADevice"],[8,0,1,"_CPPv415HADeviceTracker","HADeviceTracker"],[8,3,1,"_CPPv4N15HADeviceTracker15HADeviceTrackerEPKc","HADeviceTracker::HADeviceTracker"],[8,4,1,"_CPPv4N15HADeviceTracker15HADeviceTrackerEPKc","HADeviceTracker::HADeviceTracker::uniqueId"],[8,1,1,"_CPPv4N15HADeviceTracker10SourceTypeE","HADeviceTracker::SourceType"],[8,2,1,"_CPPv4N15HADeviceTracker10SourceType19SourceTypeBluetoothE","HADeviceTracker::SourceType::SourceTypeBluetooth"],[8,2,1,"_CPPv4N15HADeviceTracker10SourceType21SourceTypeBluetoothLEE","HADeviceTracker::SourceType::SourceTypeBluetoothLE"],[8,2,1,"_CPPv4N15HADeviceTracker10SourceType13SourceTypeGPSE","HADeviceTracker::SourceType::SourceTypeGPS"],[8,2,1,"_CPPv4N15HADeviceTracker10SourceType16SourceTypeRouterE","HADeviceTracker::SourceType::SourceTypeRouter"],[8,2,1,"_CPPv4N15HADeviceTracker10SourceType17SourceTypeUnknownE","HADeviceTracker::SourceType::SourceTypeUnknown"],[8,2,1,"_CPPv4N15HADeviceTracker10SourceType19SourceTypeBluetoothE","HADeviceTracker::SourceTypeBluetooth"],[8,2,1,"_CPPv4N15HADeviceTracker10SourceType21SourceTypeBluetoothLEE","HADeviceTracker::SourceTypeBluetoothLE"],[8,2,1,"_CPPv4N15HADeviceTracker10SourceType13SourceTypeGPSE","HADeviceTracker::SourceTypeGPS"],[8,2,1,"_CPPv4N15HADeviceTracker10SourceType16SourceTypeRouterE","HADeviceTracker::SourceTypeRouter"],[8,2,1,"_CPPv4N15HADeviceTracker10SourceType17SourceTypeUnknownE","HADeviceTracker::SourceTypeUnknown"],[8,2,1,"_CPPv4N15HADeviceTracker12TrackerState9StateHomeE","HADeviceTracker::StateHome"],[8,2,1,"_CPPv4N15HADeviceTracker12TrackerState17StateNotAvailableE","HADeviceTracker::StateNotAvailable"],[8,2,1,"_CPPv4N15HADeviceTracker12TrackerState12StateNotHomeE","HADeviceTracker::StateNotHome"],[8,2,1,"_CPPv4N15HADeviceTracker12TrackerState12StateUnknownE","HADeviceTracker::StateUnknown"],[8,1,1,"_CPPv4N15HADeviceTracker12TrackerStateE","HADeviceTracker::TrackerState"],[8,2,1,"_CPPv4N15HADeviceTracker12TrackerState9StateHomeE","HADeviceTracker::TrackerState::StateHome"],[8,2,1,"_CPPv4N15HADeviceTracker12TrackerState17StateNotAvailableE","HADeviceTracker::TrackerState::StateNotAvailable"],[8,2,1,"_CPPv4N15HADeviceTracker12TrackerState12StateNotHomeE","HADeviceTracker::TrackerState::StateNotHome"],[8,2,1,"_CPPv4N15HADeviceTracker12TrackerState12StateUnknownE","HADeviceTracker::TrackerState::StateUnknown"],[8,5,1,"_CPPv4N15HADeviceTracker13_currentStateE","HADeviceTracker::_currentState"],[8,5,1,"_CPPv4N15HADeviceTracker5_iconE","HADeviceTracker::_icon"],[8,5,1,"_CPPv4N15HADeviceTracker11_sourceTypeE","HADeviceTracker::_sourceType"],[8,3,1,"_CPPv4N15HADeviceTracker15buildSerializerEv","HADeviceTracker::buildSerializer"],[8,3,1,"_CPPv4NK15HADeviceTracker21getSourceTypePropertyEv","HADeviceTracker::getSourceTypeProperty"],[8,3,1,"_CPPv4NK15HADeviceTracker8getStateEv","HADeviceTracker::getState"],[8,3,1,"_CPPv4N15HADeviceTracker15onMqttConnectedEv","HADeviceTracker::onMqttConnected"],[8,3,1,"_CPPv4N15HADeviceTracker12publishStateE12TrackerState","HADeviceTracker::publishState"],[8,4,1,"_CPPv4N15HADeviceTracker12publishStateE12TrackerState","HADeviceTracker::publishState::state"],[8,3,1,"_CPPv4N15HADeviceTracker15setCurrentStateEK12TrackerState","HADeviceTracker::setCurrentState"],[8,4,1,"_CPPv4N15HADeviceTracker15setCurrentStateEK12TrackerState","HADeviceTracker::setCurrentState::state"],[8,3,1,"_CPPv4N15HADeviceTracker7setIconEPKc","HADeviceTracker::setIcon"],[8,4,1,"_CPPv4N15HADeviceTracker7setIconEPKc","HADeviceTracker::setIcon::icon"],[8,3,1,"_CPPv4N15HADeviceTracker13setSourceTypeEK10SourceType","HADeviceTracker::setSourceType"],[8,4,1,"_CPPv4N15HADeviceTracker13setSourceTypeEK10SourceType","HADeviceTracker::setSourceType::type"],[8,3,1,"_CPPv4N15HADeviceTracker8setStateEK12TrackerStateKb","HADeviceTracker::setState"],[8,4,1,"_CPPv4N15HADeviceTracker8setStateEK12TrackerStateKb","HADeviceTracker::setState::force"],[8,4,1,"_CPPv4N15HADeviceTracker8setStateEK12TrackerStateKb","HADeviceTracker::setState::state"],[9,0,1,"_CPPv415HADeviceTrigger","HADeviceTrigger"],[9,2,1,"_CPPv4N15HADeviceTrigger14TriggerSubtype14Button1SubtypeE","HADeviceTrigger::Button1Subtype"],[9,2,1,"_CPPv4N15HADeviceTrigger14TriggerSubtype14Button2SubtypeE","HADeviceTrigger::Button2Subtype"],[9,2,1,"_CPPv4N15HADeviceTrigger14TriggerSubtype14Button3SubtypeE","HADeviceTrigger::Button3Subtype"],[9,2,1,"_CPPv4N15HADeviceTrigger14TriggerSubtype14Button4SubtypeE","HADeviceTrigger::Button4Subtype"],[9,2,1,"_CPPv4N15HADeviceTrigger14TriggerSubtype14Button5SubtypeE","HADeviceTrigger::Button5Subtype"],[9,2,1,"_CPPv4N15HADeviceTrigger14TriggerSubtype14Button6SubtypeE","HADeviceTrigger::Button6Subtype"],[9,2,1,"_CPPv4N15HADeviceTrigger11TriggerType21ButtonDoublePressTypeE","HADeviceTrigger::ButtonDoublePressType"],[9,2,1,"_CPPv4N15HADeviceTrigger11TriggerType19ButtonLongPressTypeE","HADeviceTrigger::ButtonLongPressType"],[9,2,1,"_CPPv4N15HADeviceTrigger11TriggerType21ButtonLongReleaseTypeE","HADeviceTrigger::ButtonLongReleaseType"],[9,2,1,"_CPPv4N15HADeviceTrigger11TriggerType24ButtonQuadruplePressTypeE","HADeviceTrigger::ButtonQuadruplePressType"],[9,2,1,"_CPPv4N15HADeviceTrigger11TriggerType24ButtonQuintuplePressTypeE","HADeviceTrigger::ButtonQuintuplePressType"],[9,2,1,"_CPPv4N15HADeviceTrigger11TriggerType20ButtonShortPressTypeE","HADeviceTrigger::ButtonShortPressType"],[9,2,1,"_CPPv4N15HADeviceTrigger11TriggerType22ButtonShortReleaseTypeE","HADeviceTrigger::ButtonShortReleaseType"],[9,2,1,"_CPPv4N15HADeviceTrigger11TriggerType21ButtonTriplePressTypeE","HADeviceTrigger::ButtonTriplePressType"],[9,3,1,"_CPPv4N15HADeviceTrigger15HADeviceTriggerE11TriggerType14TriggerSubtype","HADeviceTrigger::HADeviceTrigger"],[9,3,1,"_CPPv4N15HADeviceTrigger15HADeviceTriggerE11TriggerTypePKc","HADeviceTrigger::HADeviceTrigger"],[9,3,1,"_CPPv4N15HADeviceTrigger15HADeviceTriggerEPKc14TriggerSubtype","HADeviceTrigger::HADeviceTrigger"],[9,3,1,"_CPPv4N15HADeviceTrigger15HADeviceTriggerEPKcPKc","HADeviceTrigger::HADeviceTrigger"],[9,4,1,"_CPPv4N15HADeviceTrigger15HADeviceTriggerE11TriggerType14TriggerSubtype","HADeviceTrigger::HADeviceTrigger::subtype"],[9,4,1,"_CPPv4N15HADeviceTrigger15HADeviceTriggerE11TriggerTypePKc","HADeviceTrigger::HADeviceTrigger::subtype"],[9,4,1,"_CPPv4N15HADeviceTrigger15HADeviceTriggerEPKc14TriggerSubtype","HADeviceTrigger::HADeviceTrigger::subtype"],[9,4,1,"_CPPv4N15HADeviceTrigger15HADeviceTriggerEPKcPKc","HADeviceTrigger::HADeviceTrigger::subtype"],[9,4,1,"_CPPv4N15HADeviceTrigger15HADeviceTriggerE11TriggerType14TriggerSubtype","HADeviceTrigger::HADeviceTrigger::type"],[9,4,1,"_CPPv4N15HADeviceTrigger15HADeviceTriggerE11TriggerTypePKc","HADeviceTrigger::HADeviceTrigger::type"],[9,4,1,"_CPPv4N15HADeviceTrigger15HADeviceTriggerEPKc14TriggerSubtype","HADeviceTrigger::HADeviceTrigger::type"],[9,4,1,"_CPPv4N15HADeviceTrigger15HADeviceTriggerEPKcPKc","HADeviceTrigger::HADeviceTrigger::type"],[9,1,1,"_CPPv4N15HADeviceTrigger14TriggerSubtypeE","HADeviceTrigger::TriggerSubtype"],[9,2,1,"_CPPv4N15HADeviceTrigger14TriggerSubtype14Button1SubtypeE","HADeviceTrigger::TriggerSubtype::Button1Subtype"],[9,2,1,"_CPPv4N15HADeviceTrigger14TriggerSubtype14Button2SubtypeE","HADeviceTrigger::TriggerSubtype::Button2Subtype"],[9,2,1,"_CPPv4N15HADeviceTrigger14TriggerSubtype14Button3SubtypeE","HADeviceTrigger::TriggerSubtype::Button3Subtype"],[9,2,1,"_CPPv4N15HADeviceTrigger14TriggerSubtype14Button4SubtypeE","HADeviceTrigger::TriggerSubtype::Button4Subtype"],[9,2,1,"_CPPv4N15HADeviceTrigger14TriggerSubtype14Button5SubtypeE","HADeviceTrigger::TriggerSubtype::Button5Subtype"],[9,2,1,"_CPPv4N15HADeviceTrigger14TriggerSubtype14Button6SubtypeE","HADeviceTrigger::TriggerSubtype::Button6Subtype"],[9,2,1,"_CPPv4N15HADeviceTrigger14TriggerSubtype14TurnOffSubtypeE","HADeviceTrigger::TriggerSubtype::TurnOffSubtype"],[9,2,1,"_CPPv4N15HADeviceTrigger14TriggerSubtype13TurnOnSubtypeE","HADeviceTrigger::TriggerSubtype::TurnOnSubtype"],[9,1,1,"_CPPv4N15HADeviceTrigger11TriggerTypeE","HADeviceTrigger::TriggerType"],[9,2,1,"_CPPv4N15HADeviceTrigger11TriggerType21ButtonDoublePressTypeE","HADeviceTrigger::TriggerType::ButtonDoublePressType"],[9,2,1,"_CPPv4N15HADeviceTrigger11TriggerType19ButtonLongPressTypeE","HADeviceTrigger::TriggerType::ButtonLongPressType"],[9,2,1,"_CPPv4N15HADeviceTrigger11TriggerType21ButtonLongReleaseTypeE","HADeviceTrigger::TriggerType::ButtonLongReleaseType"],[9,2,1,"_CPPv4N15HADeviceTrigger11TriggerType24ButtonQuadruplePressTypeE","HADeviceTrigger::TriggerType::ButtonQuadruplePressType"],[9,2,1,"_CPPv4N15HADeviceTrigger11TriggerType24ButtonQuintuplePressTypeE","HADeviceTrigger::TriggerType::ButtonQuintuplePressType"],[9,2,1,"_CPPv4N15HADeviceTrigger11TriggerType20ButtonShortPressTypeE","HADeviceTrigger::TriggerType::ButtonShortPressType"],[9,2,1,"_CPPv4N15HADeviceTrigger11TriggerType22ButtonShortReleaseTypeE","HADeviceTrigger::TriggerType::ButtonShortReleaseType"],[9,2,1,"_CPPv4N15HADeviceTrigger11TriggerType21ButtonTriplePressTypeE","HADeviceTrigger::TriggerType::ButtonTriplePressType"],[9,2,1,"_CPPv4N15HADeviceTrigger14TriggerSubtype14TurnOffSubtypeE","HADeviceTrigger::TurnOffSubtype"],[9,2,1,"_CPPv4N15HADeviceTrigger14TriggerSubtype13TurnOnSubtypeE","HADeviceTrigger::TurnOnSubtype"],[9,5,1,"_CPPv4N15HADeviceTrigger17_isProgmemSubtypeE","HADeviceTrigger::_isProgmemSubtype"],[9,5,1,"_CPPv4N15HADeviceTrigger14_isProgmemTypeE","HADeviceTrigger::_isProgmemType"],[9,5,1,"_CPPv4N15HADeviceTrigger8_subtypeE","HADeviceTrigger::_subtype"],[9,5,1,"_CPPv4N15HADeviceTrigger5_typeE","HADeviceTrigger::_type"],[9,3,1,"_CPPv4N15HADeviceTrigger15buildSerializerEv","HADeviceTrigger::buildSerializer"],[9,3,1,"_CPPv4N15HADeviceTrigger13buildUniqueIdEv","HADeviceTrigger::buildUniqueId"],[9,3,1,"_CPPv4NK15HADeviceTrigger15calculateIdSizeEv","HADeviceTrigger::calculateIdSize"],[9,3,1,"_CPPv4NK15HADeviceTrigger23determineProgmemSubtypeE14TriggerSubtype","HADeviceTrigger::determineProgmemSubtype"],[9,4,1,"_CPPv4NK15HADeviceTrigger23determineProgmemSubtypeE14TriggerSubtype","HADeviceTrigger::determineProgmemSubtype::subtype"],[9,3,1,"_CPPv4NK15HADeviceTrigger20determineProgmemTypeE11TriggerType","HADeviceTrigger::determineProgmemType"],[9,4,1,"_CPPv4NK15HADeviceTrigger20determineProgmemTypeE11TriggerType","HADeviceTrigger::determineProgmemType::type"],[9,3,1,"_CPPv4NK15HADeviceTrigger10getSubtypeEv","HADeviceTrigger::getSubtype"],[9,3,1,"_CPPv4NK15HADeviceTrigger7getTypeEv","HADeviceTrigger::getType"],[9,3,1,"_CPPv4NK15HADeviceTrigger16isProgmemSubtypeEv","HADeviceTrigger::isProgmemSubtype"],[9,3,1,"_CPPv4NK15HADeviceTrigger13isProgmemTypeEv","HADeviceTrigger::isProgmemType"],[9,3,1,"_CPPv4N15HADeviceTrigger15onMqttConnectedEv","HADeviceTrigger::onMqttConnected"],[9,3,1,"_CPPv4N15HADeviceTrigger7triggerEv","HADeviceTrigger::trigger"],[9,3,1,"_CPPv4N15HADeviceTriggerD0Ev","HADeviceTrigger::~HADeviceTrigger"],[10,0,1,"_CPPv45HAFan","HAFan"],[10,2,1,"_CPPv4N5HAFan8Features15DefaultFeaturesE","HAFan::DefaultFeatures"],[10,1,1,"_CPPv4N5HAFan8FeaturesE","HAFan::Features"],[10,2,1,"_CPPv4N5HAFan8Features15DefaultFeaturesE","HAFan::Features::DefaultFeatures"],[10,2,1,"_CPPv4N5HAFan8Features13SpeedsFeatureE","HAFan::Features::SpeedsFeature"],[10,3,1,"_CPPv4N5HAFan5HAFanEPKcK7uint8_t","HAFan::HAFan"],[10,4,1,"_CPPv4N5HAFan5HAFanEPKcK7uint8_t","HAFan::HAFan::features"],[10,4,1,"_CPPv4N5HAFan5HAFanEPKcK7uint8_t","HAFan::HAFan::uniqueId"],[10,2,1,"_CPPv4N5HAFan8Features13SpeedsFeatureE","HAFan::SpeedsFeature"],[10,5,1,"_CPPv4N5HAFan13_currentSpeedE","HAFan::_currentSpeed"],[10,5,1,"_CPPv4N5HAFan13_currentStateE","HAFan::_currentState"],[10,5,1,"_CPPv4N5HAFan9_featuresE","HAFan::_features"],[10,5,1,"_CPPv4N5HAFan5_iconE","HAFan::_icon"],[10,5,1,"_CPPv4N5HAFan11_optimisticE","HAFan::_optimistic"],[10,5,1,"_CPPv4N5HAFan7_retainE","HAFan::_retain"],[10,5,1,"_CPPv4N5HAFan14_speedCallbackE","HAFan::_speedCallback"],[10,5,1,"_CPPv4N5HAFan14_speedRangeMaxE","HAFan::_speedRangeMax"],[10,5,1,"_CPPv4N5HAFan14_speedRangeMinE","HAFan::_speedRangeMin"],[10,5,1,"_CPPv4N5HAFan14_stateCallbackE","HAFan::_stateCallback"],[10,3,1,"_CPPv4N5HAFan15buildSerializerEv","HAFan::buildSerializer"],[10,3,1,"_CPPv4NK5HAFan15getCurrentSpeedEv","HAFan::getCurrentSpeed"],[10,3,1,"_CPPv4NK5HAFan15getCurrentStateEv","HAFan::getCurrentState"],[10,3,1,"_CPPv4N5HAFan18handleSpeedCommandEPK7uint8_tK8uint16_t","HAFan::handleSpeedCommand"],[10,4,1,"_CPPv4N5HAFan18handleSpeedCommandEPK7uint8_tK8uint16_t","HAFan::handleSpeedCommand::cmd"],[10,4,1,"_CPPv4N5HAFan18handleSpeedCommandEPK7uint8_tK8uint16_t","HAFan::handleSpeedCommand::length"],[10,3,1,"_CPPv4N5HAFan18handleStateCommandEPK7uint8_tK8uint16_t","HAFan::handleStateCommand"],[10,4,1,"_CPPv4N5HAFan18handleStateCommandEPK7uint8_tK8uint16_t","HAFan::handleStateCommand::cmd"],[10,4,1,"_CPPv4N5HAFan18handleStateCommandEPK7uint8_tK8uint16_t","HAFan::handleStateCommand::length"],[10,3,1,"_CPPv4N5HAFan15onMqttConnectedEv","HAFan::onMqttConnected"],[10,3,1,"_CPPv4N5HAFan13onMqttMessageEPKcPK7uint8_tK8uint16_t","HAFan::onMqttMessage"],[10,4,1,"_CPPv4N5HAFan13onMqttMessageEPKcPK7uint8_tK8uint16_t","HAFan::onMqttMessage::length"],[10,4,1,"_CPPv4N5HAFan13onMqttMessageEPKcPK7uint8_tK8uint16_t","HAFan::onMqttMessage::payload"],[10,4,1,"_CPPv4N5HAFan13onMqttMessageEPKcPK7uint8_tK8uint16_t","HAFan::onMqttMessage::topic"],[10,3,1,"_CPPv4N5HAFan14onSpeedCommandEPFv8uint16_tP5HAFanE","HAFan::onSpeedCommand"],[10,4,1,"_CPPv4N5HAFan14onSpeedCommandEPFv8uint16_tP5HAFanE","HAFan::onSpeedCommand::callback"],[10,3,1,"_CPPv4N5HAFan14onStateCommandEPFvbP5HAFanE","HAFan::onStateCommand"],[10,4,1,"_CPPv4N5HAFan14onStateCommandEPFvbP5HAFanE","HAFan::onStateCommand::callback"],[10,3,1,"_CPPv4N5HAFan12publishSpeedEK8uint16_t","HAFan::publishSpeed"],[10,4,1,"_CPPv4N5HAFan12publishSpeedEK8uint16_t","HAFan::publishSpeed::speed"],[10,3,1,"_CPPv4N5HAFan12publishStateEKb","HAFan::publishState"],[10,4,1,"_CPPv4N5HAFan12publishStateEKb","HAFan::publishState::state"],[10,3,1,"_CPPv4N5HAFan15setCurrentSpeedEK8uint16_t","HAFan::setCurrentSpeed"],[10,4,1,"_CPPv4N5HAFan15setCurrentSpeedEK8uint16_t","HAFan::setCurrentSpeed::speed"],[10,3,1,"_CPPv4N5HAFan15setCurrentStateEKb","HAFan::setCurrentState"],[10,4,1,"_CPPv4N5HAFan15setCurrentStateEKb","HAFan::setCurrentState::state"],[10,3,1,"_CPPv4N5HAFan7setIconEPKc","HAFan::setIcon"],[10,4,1,"_CPPv4N5HAFan7setIconEPKc","HAFan::setIcon::icon"],[10,3,1,"_CPPv4N5HAFan13setOptimisticEKb","HAFan::setOptimistic"],[10,4,1,"_CPPv4N5HAFan13setOptimisticEKb","HAFan::setOptimistic::optimistic"],[10,3,1,"_CPPv4N5HAFan9setRetainEKb","HAFan::setRetain"],[10,4,1,"_CPPv4N5HAFan9setRetainEKb","HAFan::setRetain::retain"],[10,3,1,"_CPPv4N5HAFan8setSpeedEK8uint16_tKb","HAFan::setSpeed"],[10,4,1,"_CPPv4N5HAFan8setSpeedEK8uint16_tKb","HAFan::setSpeed::force"],[10,4,1,"_CPPv4N5HAFan8setSpeedEK8uint16_tKb","HAFan::setSpeed::speed"],[10,3,1,"_CPPv4N5HAFan16setSpeedRangeMaxEK8uint16_t","HAFan::setSpeedRangeMax"],[10,4,1,"_CPPv4N5HAFan16setSpeedRangeMaxEK8uint16_t","HAFan::setSpeedRangeMax::max"],[10,3,1,"_CPPv4N5HAFan16setSpeedRangeMinEK8uint16_t","HAFan::setSpeedRangeMin"],[10,4,1,"_CPPv4N5HAFan16setSpeedRangeMinEK8uint16_t","HAFan::setSpeedRangeMin::min"],[10,3,1,"_CPPv4N5HAFan8setStateEKbKb","HAFan::setState"],[10,4,1,"_CPPv4N5HAFan8setStateEKbKb","HAFan::setState::force"],[10,4,1,"_CPPv4N5HAFan8setStateEKbKb","HAFan::setState::state"],[10,3,1,"_CPPv4N5HAFan7turnOffEv","HAFan::turnOff"],[10,3,1,"_CPPv4N5HAFan6turnOnEv","HAFan::turnOn"],[11,0,1,"_CPPv46HAHVAC","HAHVAC"],[11,1,1,"_CPPv4N6HAHVAC6ActionE","HAHVAC::Action"],[11,2,1,"_CPPv4N6HAHVAC6Action13CoolingActionE","HAHVAC::Action::CoolingAction"],[11,2,1,"_CPPv4N6HAHVAC6Action12DryingActionE","HAHVAC::Action::DryingAction"],[11,2,1,"_CPPv4N6HAHVAC6Action9FanActionE","HAHVAC::Action::FanAction"],[11,2,1,"_CPPv4N6HAHVAC6Action13HeatingActionE","HAHVAC::Action::HeatingAction"],[11,2,1,"_CPPv4N6HAHVAC6Action10IdleActionE","HAHVAC::Action::IdleAction"],[11,2,1,"_CPPv4N6HAHVAC6Action9OffActionE","HAHVAC::Action::OffAction"],[11,2,1,"_CPPv4N6HAHVAC6Action13UnknownActionE","HAHVAC::Action::UnknownAction"],[11,2,1,"_CPPv4N6HAHVAC8Features13ActionFeatureE","HAHVAC::ActionFeature"],[11,2,1,"_CPPv4N6HAHVAC7FanMode11AutoFanModeE","HAHVAC::AutoFanMode"],[11,2,1,"_CPPv4N6HAHVAC4Mode8AutoModeE","HAHVAC::AutoMode"],[11,2,1,"_CPPv4N6HAHVAC8Features17AuxHeatingFeatureE","HAHVAC::AuxHeatingFeature"],[11,2,1,"_CPPv4N6HAHVAC15TemperatureUnit11CelsiusUnitE","HAHVAC::CelsiusUnit"],[11,2,1,"_CPPv4N6HAHVAC4Mode8CoolModeE","HAHVAC::CoolMode"],[11,2,1,"_CPPv4N6HAHVAC6Action13CoolingActionE","HAHVAC::CoolingAction"],[11,5,1,"_CPPv4N6HAHVAC15DefaultFanModesE","HAHVAC::DefaultFanModes"],[11,2,1,"_CPPv4N6HAHVAC8Features15DefaultFeaturesE","HAHVAC::DefaultFeatures"],[11,5,1,"_CPPv4N6HAHVAC12DefaultModesE","HAHVAC::DefaultModes"],[11,5,1,"_CPPv4N6HAHVAC17DefaultSwingModesE","HAHVAC::DefaultSwingModes"],[11,2,1,"_CPPv4N6HAHVAC15TemperatureUnit11DefaultUnitE","HAHVAC::DefaultUnit"],[11,2,1,"_CPPv4N6HAHVAC4Mode7DryModeE","HAHVAC::DryMode"],[11,2,1,"_CPPv4N6HAHVAC6Action12DryingActionE","HAHVAC::DryingAction"],[11,2,1,"_CPPv4N6HAHVAC15TemperatureUnit14FahrenheitUnitE","HAHVAC::FahrenheitUnit"],[11,2,1,"_CPPv4N6HAHVAC6Action9FanActionE","HAHVAC::FanAction"],[11,2,1,"_CPPv4N6HAHVAC8Features10FanFeatureE","HAHVAC::FanFeature"],[11,1,1,"_CPPv4N6HAHVAC7FanModeE","HAHVAC::FanMode"],[11,2,1,"_CPPv4N6HAHVAC7FanMode11AutoFanModeE","HAHVAC::FanMode::AutoFanMode"],[11,2,1,"_CPPv4N6HAHVAC7FanMode11HighFanModeE","HAHVAC::FanMode::HighFanMode"],[11,2,1,"_CPPv4N6HAHVAC7FanMode10LowFanModeE","HAHVAC::FanMode::LowFanMode"],[11,2,1,"_CPPv4N6HAHVAC7FanMode13MediumFanModeE","HAHVAC::FanMode::MediumFanMode"],[11,2,1,"_CPPv4N6HAHVAC7FanMode14UnknownFanModeE","HAHVAC::FanMode::UnknownFanMode"],[11,2,1,"_CPPv4N6HAHVAC4Mode11FanOnlyModeE","HAHVAC::FanOnlyMode"],[11,1,1,"_CPPv4N6HAHVAC8FeaturesE","HAHVAC::Features"],[11,2,1,"_CPPv4N6HAHVAC8Features13ActionFeatureE","HAHVAC::Features::ActionFeature"],[11,2,1,"_CPPv4N6HAHVAC8Features17AuxHeatingFeatureE","HAHVAC::Features::AuxHeatingFeature"],[11,2,1,"_CPPv4N6HAHVAC8Features15DefaultFeaturesE","HAHVAC::Features::DefaultFeatures"],[11,2,1,"_CPPv4N6HAHVAC8Features10FanFeatureE","HAHVAC::Features::FanFeature"],[11,2,1,"_CPPv4N6HAHVAC8Features12ModesFeatureE","HAHVAC::Features::ModesFeature"],[11,2,1,"_CPPv4N6HAHVAC8Features12PowerFeatureE","HAHVAC::Features::PowerFeature"],[11,2,1,"_CPPv4N6HAHVAC8Features12SwingFeatureE","HAHVAC::Features::SwingFeature"],[11,2,1,"_CPPv4N6HAHVAC8Features24TargetTemperatureFeatureE","HAHVAC::Features::TargetTemperatureFeature"],[11,3,1,"_CPPv4N6HAHVAC6HAHVACEPKcK8uint16_tK15NumberPrecision","HAHVAC::HAHVAC"],[11,4,1,"_CPPv4N6HAHVAC6HAHVACEPKcK8uint16_tK15NumberPrecision","HAHVAC::HAHVAC::features"],[11,4,1,"_CPPv4N6HAHVAC6HAHVACEPKcK8uint16_tK15NumberPrecision","HAHVAC::HAHVAC::precision"],[11,4,1,"_CPPv4N6HAHVAC6HAHVACEPKcK8uint16_tK15NumberPrecision","HAHVAC::HAHVAC::uniqueId"],[11,2,1,"_CPPv4N6HAHVAC4Mode8HeatModeE","HAHVAC::HeatMode"],[11,2,1,"_CPPv4N6HAHVAC6Action13HeatingActionE","HAHVAC::HeatingAction"],[11,2,1,"_CPPv4N6HAHVAC7FanMode11HighFanModeE","HAHVAC::HighFanMode"],[11,2,1,"_CPPv4N6HAHVAC6Action10IdleActionE","HAHVAC::IdleAction"],[11,2,1,"_CPPv4N6HAHVAC7FanMode10LowFanModeE","HAHVAC::LowFanMode"],[11,2,1,"_CPPv4N6HAHVAC7FanMode13MediumFanModeE","HAHVAC::MediumFanMode"],[11,1,1,"_CPPv4N6HAHVAC4ModeE","HAHVAC::Mode"],[11,2,1,"_CPPv4N6HAHVAC4Mode8AutoModeE","HAHVAC::Mode::AutoMode"],[11,2,1,"_CPPv4N6HAHVAC4Mode8CoolModeE","HAHVAC::Mode::CoolMode"],[11,2,1,"_CPPv4N6HAHVAC4Mode7DryModeE","HAHVAC::Mode::DryMode"],[11,2,1,"_CPPv4N6HAHVAC4Mode11FanOnlyModeE","HAHVAC::Mode::FanOnlyMode"],[11,2,1,"_CPPv4N6HAHVAC4Mode8HeatModeE","HAHVAC::Mode::HeatMode"],[11,2,1,"_CPPv4N6HAHVAC4Mode7OffModeE","HAHVAC::Mode::OffMode"],[11,2,1,"_CPPv4N6HAHVAC4Mode11UnknownModeE","HAHVAC::Mode::UnknownMode"],[11,2,1,"_CPPv4N6HAHVAC8Features12ModesFeatureE","HAHVAC::ModesFeature"],[11,2,1,"_CPPv4N6HAHVAC6Action9OffActionE","HAHVAC::OffAction"],[11,2,1,"_CPPv4N6HAHVAC4Mode7OffModeE","HAHVAC::OffMode"],[11,2,1,"_CPPv4N6HAHVAC9SwingMode12OffSwingModeE","HAHVAC::OffSwingMode"],[11,2,1,"_CPPv4N6HAHVAC9SwingMode11OnSwingModeE","HAHVAC::OnSwingMode"],[11,2,1,"_CPPv4N6HAHVAC8Features12PowerFeatureE","HAHVAC::PowerFeature"],[11,2,1,"_CPPv4N6HAHVAC8Features12SwingFeatureE","HAHVAC::SwingFeature"],[11,1,1,"_CPPv4N6HAHVAC9SwingModeE","HAHVAC::SwingMode"],[11,2,1,"_CPPv4N6HAHVAC9SwingMode12OffSwingModeE","HAHVAC::SwingMode::OffSwingMode"],[11,2,1,"_CPPv4N6HAHVAC9SwingMode11OnSwingModeE","HAHVAC::SwingMode::OnSwingMode"],[11,2,1,"_CPPv4N6HAHVAC9SwingMode16UnknownSwingModeE","HAHVAC::SwingMode::UnknownSwingMode"],[11,2,1,"_CPPv4N6HAHVAC8Features24TargetTemperatureFeatureE","HAHVAC::TargetTemperatureFeature"],[11,1,1,"_CPPv4N6HAHVAC15TemperatureUnitE","HAHVAC::TemperatureUnit"],[11,2,1,"_CPPv4N6HAHVAC15TemperatureUnit11CelsiusUnitE","HAHVAC::TemperatureUnit::CelsiusUnit"],[11,2,1,"_CPPv4N6HAHVAC15TemperatureUnit11DefaultUnitE","HAHVAC::TemperatureUnit::DefaultUnit"],[11,2,1,"_CPPv4N6HAHVAC15TemperatureUnit14FahrenheitUnitE","HAHVAC::TemperatureUnit::FahrenheitUnit"],[11,2,1,"_CPPv4N6HAHVAC6Action13UnknownActionE","HAHVAC::UnknownAction"],[11,2,1,"_CPPv4N6HAHVAC7FanMode14UnknownFanModeE","HAHVAC::UnknownFanMode"],[11,2,1,"_CPPv4N6HAHVAC4Mode11UnknownModeE","HAHVAC::UnknownMode"],[11,2,1,"_CPPv4N6HAHVAC9SwingMode16UnknownSwingModeE","HAHVAC::UnknownSwingMode"],[11,5,1,"_CPPv4N6HAHVAC7_actionE","HAHVAC::_action"],[11,5,1,"_CPPv4N6HAHVAC12_auxCallbackE","HAHVAC::_auxCallback"],[11,5,1,"_CPPv4N6HAHVAC9_auxStateE","HAHVAC::_auxState"],[11,5,1,"_CPPv4N6HAHVAC19_currentTemperatureE","HAHVAC::_currentTemperature"],[11,5,1,"_CPPv4N6HAHVAC8_fanModeE","HAHVAC::_fanMode"],[11,5,1,"_CPPv4N6HAHVAC16_fanModeCallbackE","HAHVAC::_fanModeCallback"],[11,5,1,"_CPPv4N6HAHVAC9_fanModesE","HAHVAC::_fanModes"],[11,5,1,"_CPPv4N6HAHVAC19_fanModesSerializerE","HAHVAC::_fanModesSerializer"],[11,5,1,"_CPPv4N6HAHVAC9_featuresE","HAHVAC::_features"],[11,5,1,"_CPPv4N6HAHVAC5_iconE","HAHVAC::_icon"],[11,5,1,"_CPPv4N6HAHVAC8_maxTempE","HAHVAC::_maxTemp"],[11,5,1,"_CPPv4N6HAHVAC8_minTempE","HAHVAC::_minTemp"],[11,5,1,"_CPPv4N6HAHVAC5_modeE","HAHVAC::_mode"],[11,5,1,"_CPPv4N6HAHVAC13_modeCallbackE","HAHVAC::_modeCallback"],[11,5,1,"_CPPv4N6HAHVAC6_modesE","HAHVAC::_modes"],[11,5,1,"_CPPv4N6HAHVAC16_modesSerializerE","HAHVAC::_modesSerializer"],[11,5,1,"_CPPv4N6HAHVAC14_powerCallbackE","HAHVAC::_powerCallback"],[11,5,1,"_CPPv4N6HAHVAC10_precisionE","HAHVAC::_precision"],[11,5,1,"_CPPv4N6HAHVAC7_retainE","HAHVAC::_retain"],[11,5,1,"_CPPv4N6HAHVAC10_swingModeE","HAHVAC::_swingMode"],[11,5,1,"_CPPv4N6HAHVAC18_swingModeCallbackE","HAHVAC::_swingModeCallback"],[11,5,1,"_CPPv4N6HAHVAC11_swingModesE","HAHVAC::_swingModes"],[11,5,1,"_CPPv4N6HAHVAC21_swingModesSerializerE","HAHVAC::_swingModesSerializer"],[11,5,1,"_CPPv4N6HAHVAC18_targetTemperatureE","HAHVAC::_targetTemperature"],[11,5,1,"_CPPv4N6HAHVAC26_targetTemperatureCallbackE","HAHVAC::_targetTemperatureCallback"],[11,5,1,"_CPPv4N6HAHVAC9_tempStepE","HAHVAC::_tempStep"],[11,5,1,"_CPPv4N6HAHVAC16_temperatureUnitE","HAHVAC::_temperatureUnit"],[11,3,1,"_CPPv4N6HAHVAC15buildSerializerEv","HAHVAC::buildSerializer"],[11,3,1,"_CPPv4N6HAHVAC27getCommandWithFloatTemplateEv","HAHVAC::getCommandWithFloatTemplate"],[11,3,1,"_CPPv4NK6HAHVAC16getCurrentActionEv","HAHVAC::getCurrentAction"],[11,3,1,"_CPPv4NK6HAHVAC18getCurrentAuxStateEv","HAHVAC::getCurrentAuxState"],[11,3,1,"_CPPv4NK6HAHVAC17getCurrentFanModeEv","HAHVAC::getCurrentFanMode"],[11,3,1,"_CPPv4NK6HAHVAC14getCurrentModeEv","HAHVAC::getCurrentMode"],[11,3,1,"_CPPv4NK6HAHVAC19getCurrentSwingModeEv","HAHVAC::getCurrentSwingMode"],[11,3,1,"_CPPv4NK6HAHVAC27getCurrentTargetTemperatureEv","HAHVAC::getCurrentTargetTemperature"],[11,3,1,"_CPPv4NK6HAHVAC21getCurrentTemperatureEv","HAHVAC::getCurrentTemperature"],[11,3,1,"_CPPv4N6HAHVAC21handleAuxStateCommandEPK7uint8_tK8uint16_t","HAHVAC::handleAuxStateCommand"],[11,4,1,"_CPPv4N6HAHVAC21handleAuxStateCommandEPK7uint8_tK8uint16_t","HAHVAC::handleAuxStateCommand::cmd"],[11,4,1,"_CPPv4N6HAHVAC21handleAuxStateCommandEPK7uint8_tK8uint16_t","HAHVAC::handleAuxStateCommand::length"],[11,3,1,"_CPPv4N6HAHVAC20handleFanModeCommandEPK7uint8_tK8uint16_t","HAHVAC::handleFanModeCommand"],[11,4,1,"_CPPv4N6HAHVAC20handleFanModeCommandEPK7uint8_tK8uint16_t","HAHVAC::handleFanModeCommand::cmd"],[11,4,1,"_CPPv4N6HAHVAC20handleFanModeCommandEPK7uint8_tK8uint16_t","HAHVAC::handleFanModeCommand::length"],[11,3,1,"_CPPv4N6HAHVAC17handleModeCommandEPK7uint8_tK8uint16_t","HAHVAC::handleModeCommand"],[11,4,1,"_CPPv4N6HAHVAC17handleModeCommandEPK7uint8_tK8uint16_t","HAHVAC::handleModeCommand::cmd"],[11,4,1,"_CPPv4N6HAHVAC17handleModeCommandEPK7uint8_tK8uint16_t","HAHVAC::handleModeCommand::length"],[11,3,1,"_CPPv4N6HAHVAC18handlePowerCommandEPK7uint8_tK8uint16_t","HAHVAC::handlePowerCommand"],[11,4,1,"_CPPv4N6HAHVAC18handlePowerCommandEPK7uint8_tK8uint16_t","HAHVAC::handlePowerCommand::cmd"],[11,4,1,"_CPPv4N6HAHVAC18handlePowerCommandEPK7uint8_tK8uint16_t","HAHVAC::handlePowerCommand::length"],[11,3,1,"_CPPv4N6HAHVAC22handleSwingModeCommandEPK7uint8_tK8uint16_t","HAHVAC::handleSwingModeCommand"],[11,4,1,"_CPPv4N6HAHVAC22handleSwingModeCommandEPK7uint8_tK8uint16_t","HAHVAC::handleSwingModeCommand::cmd"],[11,4,1,"_CPPv4N6HAHVAC22handleSwingModeCommandEPK7uint8_tK8uint16_t","HAHVAC::handleSwingModeCommand::length"],[11,3,1,"_CPPv4N6HAHVAC30handleTargetTemperatureCommandEPK7uint8_tK8uint16_t","HAHVAC::handleTargetTemperatureCommand"],[11,4,1,"_CPPv4N6HAHVAC30handleTargetTemperatureCommandEPK7uint8_tK8uint16_t","HAHVAC::handleTargetTemperatureCommand::cmd"],[11,4,1,"_CPPv4N6HAHVAC30handleTargetTemperatureCommandEPK7uint8_tK8uint16_t","HAHVAC::handleTargetTemperatureCommand::length"],[11,3,1,"_CPPv4N6HAHVAC17onAuxStateCommandEPFvbP6HAHVACE","HAHVAC::onAuxStateCommand"],[11,4,1,"_CPPv4N6HAHVAC17onAuxStateCommandEPFvbP6HAHVACE","HAHVAC::onAuxStateCommand::callback"],[11,3,1,"_CPPv4N6HAHVAC16onFanModeCommandEPFv7FanModeP6HAHVACE","HAHVAC::onFanModeCommand"],[11,4,1,"_CPPv4N6HAHVAC16onFanModeCommandEPFv7FanModeP6HAHVACE","HAHVAC::onFanModeCommand::callback"],[11,3,1,"_CPPv4N6HAHVAC13onModeCommandEPFv4ModeP6HAHVACE","HAHVAC::onModeCommand"],[11,4,1,"_CPPv4N6HAHVAC13onModeCommandEPFv4ModeP6HAHVACE","HAHVAC::onModeCommand::callback"],[11,3,1,"_CPPv4N6HAHVAC15onMqttConnectedEv","HAHVAC::onMqttConnected"],[11,3,1,"_CPPv4N6HAHVAC13onMqttMessageEPKcPK7uint8_tK8uint16_t","HAHVAC::onMqttMessage"],[11,4,1,"_CPPv4N6HAHVAC13onMqttMessageEPKcPK7uint8_tK8uint16_t","HAHVAC::onMqttMessage::length"],[11,4,1,"_CPPv4N6HAHVAC13onMqttMessageEPKcPK7uint8_tK8uint16_t","HAHVAC::onMqttMessage::payload"],[11,4,1,"_CPPv4N6HAHVAC13onMqttMessageEPKcPK7uint8_tK8uint16_t","HAHVAC::onMqttMessage::topic"],[11,3,1,"_CPPv4N6HAHVAC14onPowerCommandEPFvbP6HAHVACE","HAHVAC::onPowerCommand"],[11,4,1,"_CPPv4N6HAHVAC14onPowerCommandEPFvbP6HAHVACE","HAHVAC::onPowerCommand::callback"],[11,3,1,"_CPPv4N6HAHVAC18onSwingModeCommandEPFv9SwingModeP6HAHVACE","HAHVAC::onSwingModeCommand"],[11,4,1,"_CPPv4N6HAHVAC18onSwingModeCommandEPFv9SwingModeP6HAHVACE","HAHVAC::onSwingModeCommand::callback"],[11,3,1,"_CPPv4N6HAHVAC26onTargetTemperatureCommandEPFv9HANumericP6HAHVACE","HAHVAC::onTargetTemperatureCommand"],[11,4,1,"_CPPv4N6HAHVAC26onTargetTemperatureCommandEPFv9HANumericP6HAHVACE","HAHVAC::onTargetTemperatureCommand::callback"],[11,3,1,"_CPPv4N6HAHVAC13publishActionEK6Action","HAHVAC::publishAction"],[11,4,1,"_CPPv4N6HAHVAC13publishActionEK6Action","HAHVAC::publishAction::action"],[11,3,1,"_CPPv4N6HAHVAC15publishAuxStateEKb","HAHVAC::publishAuxState"],[11,4,1,"_CPPv4N6HAHVAC15publishAuxStateEKb","HAHVAC::publishAuxState::state"],[11,3,1,"_CPPv4N6HAHVAC25publishCurrentTemperatureERK9HANumeric","HAHVAC::publishCurrentTemperature"],[11,4,1,"_CPPv4N6HAHVAC25publishCurrentTemperatureERK9HANumeric","HAHVAC::publishCurrentTemperature::temperature"],[11,3,1,"_CPPv4N6HAHVAC14publishFanModeEK7FanMode","HAHVAC::publishFanMode"],[11,4,1,"_CPPv4N6HAHVAC14publishFanModeEK7FanMode","HAHVAC::publishFanMode::mode"],[11,3,1,"_CPPv4N6HAHVAC11publishModeEK4Mode","HAHVAC::publishMode"],[11,4,1,"_CPPv4N6HAHVAC11publishModeEK4Mode","HAHVAC::publishMode::mode"],[11,3,1,"_CPPv4N6HAHVAC16publishSwingModeEK9SwingMode","HAHVAC::publishSwingMode"],[11,4,1,"_CPPv4N6HAHVAC16publishSwingModeEK9SwingMode","HAHVAC::publishSwingMode::mode"],[11,3,1,"_CPPv4N6HAHVAC24publishTargetTemperatureERK9HANumeric","HAHVAC::publishTargetTemperature"],[11,4,1,"_CPPv4N6HAHVAC24publishTargetTemperatureERK9HANumeric","HAHVAC::publishTargetTemperature::temperature"],[11,3,1,"_CPPv4N6HAHVAC9setActionEK6ActionKb","HAHVAC::setAction"],[11,4,1,"_CPPv4N6HAHVAC9setActionEK6ActionKb","HAHVAC::setAction::action"],[11,4,1,"_CPPv4N6HAHVAC9setActionEK6ActionKb","HAHVAC::setAction::force"],[11,3,1,"_CPPv4N6HAHVAC11setAuxStateEKbKb","HAHVAC::setAuxState"],[11,4,1,"_CPPv4N6HAHVAC11setAuxStateEKbKb","HAHVAC::setAuxState::force"],[11,4,1,"_CPPv4N6HAHVAC11setAuxStateEKbKb","HAHVAC::setAuxState::state"],[11,3,1,"_CPPv4N6HAHVAC16setCurrentActionEK6Action","HAHVAC::setCurrentAction"],[11,4,1,"_CPPv4N6HAHVAC16setCurrentActionEK6Action","HAHVAC::setCurrentAction::action"],[11,3,1,"_CPPv4N6HAHVAC18setCurrentAuxStateEKb","HAHVAC::setCurrentAuxState"],[11,4,1,"_CPPv4N6HAHVAC18setCurrentAuxStateEKb","HAHVAC::setCurrentAuxState::state"],[11,3,1,"_CPPv4N6HAHVAC28setCurrentCurrentTemperatureEK6int8_t","HAHVAC::setCurrentCurrentTemperature"],[11,3,1,"_CPPv4N6HAHVAC28setCurrentCurrentTemperatureEK7int16_t","HAHVAC::setCurrentCurrentTemperature"],[11,3,1,"_CPPv4N6HAHVAC28setCurrentCurrentTemperatureEK7int32_t","HAHVAC::setCurrentCurrentTemperature"],[11,3,1,"_CPPv4N6HAHVAC28setCurrentCurrentTemperatureEK7uint8_t","HAHVAC::setCurrentCurrentTemperature"],[11,3,1,"_CPPv4N6HAHVAC28setCurrentCurrentTemperatureEK8uint16_t","HAHVAC::setCurrentCurrentTemperature"],[11,3,1,"_CPPv4N6HAHVAC28setCurrentCurrentTemperatureEK8uint32_t","HAHVAC::setCurrentCurrentTemperature"],[11,3,1,"_CPPv4N6HAHVAC28setCurrentCurrentTemperatureEKf","HAHVAC::setCurrentCurrentTemperature"],[11,3,1,"_CPPv4N6HAHVAC28setCurrentCurrentTemperatureERK9HANumeric","HAHVAC::setCurrentCurrentTemperature"],[11,4,1,"_CPPv4N6HAHVAC28setCurrentCurrentTemperatureEK6int8_t","HAHVAC::setCurrentCurrentTemperature::temperature"],[11,4,1,"_CPPv4N6HAHVAC28setCurrentCurrentTemperatureEK7int16_t","HAHVAC::setCurrentCurrentTemperature::temperature"],[11,4,1,"_CPPv4N6HAHVAC28setCurrentCurrentTemperatureEK7int32_t","HAHVAC::setCurrentCurrentTemperature::temperature"],[11,4,1,"_CPPv4N6HAHVAC28setCurrentCurrentTemperatureEK7uint8_t","HAHVAC::setCurrentCurrentTemperature::temperature"],[11,4,1,"_CPPv4N6HAHVAC28setCurrentCurrentTemperatureEK8uint16_t","HAHVAC::setCurrentCurrentTemperature::temperature"],[11,4,1,"_CPPv4N6HAHVAC28setCurrentCurrentTemperatureEK8uint32_t","HAHVAC::setCurrentCurrentTemperature::temperature"],[11,4,1,"_CPPv4N6HAHVAC28setCurrentCurrentTemperatureEKf","HAHVAC::setCurrentCurrentTemperature::temperature"],[11,4,1,"_CPPv4N6HAHVAC28setCurrentCurrentTemperatureERK9HANumeric","HAHVAC::setCurrentCurrentTemperature::temperature"],[11,3,1,"_CPPv4N6HAHVAC17setCurrentFanModeEK7FanMode","HAHVAC::setCurrentFanMode"],[11,4,1,"_CPPv4N6HAHVAC17setCurrentFanModeEK7FanMode","HAHVAC::setCurrentFanMode::mode"],[11,3,1,"_CPPv4N6HAHVAC14setCurrentModeEK4Mode","HAHVAC::setCurrentMode"],[11,4,1,"_CPPv4N6HAHVAC14setCurrentModeEK4Mode","HAHVAC::setCurrentMode::mode"],[11,3,1,"_CPPv4N6HAHVAC19setCurrentSwingModeEK9SwingMode","HAHVAC::setCurrentSwingMode"],[11,4,1,"_CPPv4N6HAHVAC19setCurrentSwingModeEK9SwingMode","HAHVAC::setCurrentSwingMode::mode"],[11,3,1,"_CPPv4N6HAHVAC27setCurrentTargetTemperatureEK6int8_t","HAHVAC::setCurrentTargetTemperature"],[11,3,1,"_CPPv4N6HAHVAC27setCurrentTargetTemperatureEK7int16_t","HAHVAC::setCurrentTargetTemperature"],[11,3,1,"_CPPv4N6HAHVAC27setCurrentTargetTemperatureEK7int32_t","HAHVAC::setCurrentTargetTemperature"],[11,3,1,"_CPPv4N6HAHVAC27setCurrentTargetTemperatureEK7uint8_t","HAHVAC::setCurrentTargetTemperature"],[11,3,1,"_CPPv4N6HAHVAC27setCurrentTargetTemperatureEK8uint16_t","HAHVAC::setCurrentTargetTemperature"],[11,3,1,"_CPPv4N6HAHVAC27setCurrentTargetTemperatureEK8uint32_t","HAHVAC::setCurrentTargetTemperature"],[11,3,1,"_CPPv4N6HAHVAC27setCurrentTargetTemperatureEKf","HAHVAC::setCurrentTargetTemperature"],[11,3,1,"_CPPv4N6HAHVAC27setCurrentTargetTemperatureERK9HANumeric","HAHVAC::setCurrentTargetTemperature"],[11,4,1,"_CPPv4N6HAHVAC27setCurrentTargetTemperatureEK6int8_t","HAHVAC::setCurrentTargetTemperature::temperature"],[11,4,1,"_CPPv4N6HAHVAC27setCurrentTargetTemperatureEK7int16_t","HAHVAC::setCurrentTargetTemperature::temperature"],[11,4,1,"_CPPv4N6HAHVAC27setCurrentTargetTemperatureEK7int32_t","HAHVAC::setCurrentTargetTemperature::temperature"],[11,4,1,"_CPPv4N6HAHVAC27setCurrentTargetTemperatureEK7uint8_t","HAHVAC::setCurrentTargetTemperature::temperature"],[11,4,1,"_CPPv4N6HAHVAC27setCurrentTargetTemperatureEK8uint16_t","HAHVAC::setCurrentTargetTemperature::temperature"],[11,4,1,"_CPPv4N6HAHVAC27setCurrentTargetTemperatureEK8uint32_t","HAHVAC::setCurrentTargetTemperature::temperature"],[11,4,1,"_CPPv4N6HAHVAC27setCurrentTargetTemperatureEKf","HAHVAC::setCurrentTargetTemperature::temperature"],[11,4,1,"_CPPv4N6HAHVAC27setCurrentTargetTemperatureERK9HANumeric","HAHVAC::setCurrentTargetTemperature::temperature"],[11,3,1,"_CPPv4N6HAHVAC21setCurrentTemperatureEK6int8_tKb","HAHVAC::setCurrentTemperature"],[11,3,1,"_CPPv4N6HAHVAC21setCurrentTemperatureEK7int16_tKb","HAHVAC::setCurrentTemperature"],[11,3,1,"_CPPv4N6HAHVAC21setCurrentTemperatureEK7int32_tKb","HAHVAC::setCurrentTemperature"],[11,3,1,"_CPPv4N6HAHVAC21setCurrentTemperatureEK7uint8_tKb","HAHVAC::setCurrentTemperature"],[11,3,1,"_CPPv4N6HAHVAC21setCurrentTemperatureEK8uint16_tKb","HAHVAC::setCurrentTemperature"],[11,3,1,"_CPPv4N6HAHVAC21setCurrentTemperatureEK8uint32_tKb","HAHVAC::setCurrentTemperature"],[11,3,1,"_CPPv4N6HAHVAC21setCurrentTemperatureEKfKb","HAHVAC::setCurrentTemperature"],[11,3,1,"_CPPv4N6HAHVAC21setCurrentTemperatureERK9HANumericKb","HAHVAC::setCurrentTemperature"],[11,4,1,"_CPPv4N6HAHVAC21setCurrentTemperatureEK6int8_tKb","HAHVAC::setCurrentTemperature::force"],[11,4,1,"_CPPv4N6HAHVAC21setCurrentTemperatureEK7int16_tKb","HAHVAC::setCurrentTemperature::force"],[11,4,1,"_CPPv4N6HAHVAC21setCurrentTemperatureEK7int32_tKb","HAHVAC::setCurrentTemperature::force"],[11,4,1,"_CPPv4N6HAHVAC21setCurrentTemperatureEK7uint8_tKb","HAHVAC::setCurrentTemperature::force"],[11,4,1,"_CPPv4N6HAHVAC21setCurrentTemperatureEK8uint16_tKb","HAHVAC::setCurrentTemperature::force"],[11,4,1,"_CPPv4N6HAHVAC21setCurrentTemperatureEK8uint32_tKb","HAHVAC::setCurrentTemperature::force"],[11,4,1,"_CPPv4N6HAHVAC21setCurrentTemperatureEKfKb","HAHVAC::setCurrentTemperature::force"],[11,4,1,"_CPPv4N6HAHVAC21setCurrentTemperatureERK9HANumericKb","HAHVAC::setCurrentTemperature::force"],[11,4,1,"_CPPv4N6HAHVAC21setCurrentTemperatureEK6int8_tKb","HAHVAC::setCurrentTemperature::temperature"],[11,4,1,"_CPPv4N6HAHVAC21setCurrentTemperatureEK7int16_tKb","HAHVAC::setCurrentTemperature::temperature"],[11,4,1,"_CPPv4N6HAHVAC21setCurrentTemperatureEK7int32_tKb","HAHVAC::setCurrentTemperature::temperature"],[11,4,1,"_CPPv4N6HAHVAC21setCurrentTemperatureEK7uint8_tKb","HAHVAC::setCurrentTemperature::temperature"],[11,4,1,"_CPPv4N6HAHVAC21setCurrentTemperatureEK8uint16_tKb","HAHVAC::setCurrentTemperature::temperature"],[11,4,1,"_CPPv4N6HAHVAC21setCurrentTemperatureEK8uint32_tKb","HAHVAC::setCurrentTemperature::temperature"],[11,4,1,"_CPPv4N6HAHVAC21setCurrentTemperatureEKfKb","HAHVAC::setCurrentTemperature::temperature"],[11,4,1,"_CPPv4N6HAHVAC21setCurrentTemperatureERK9HANumericKb","HAHVAC::setCurrentTemperature::temperature"],[11,3,1,"_CPPv4N6HAHVAC10setFanModeEK7FanModeKb","HAHVAC::setFanMode"],[11,4,1,"_CPPv4N6HAHVAC10setFanModeEK7FanModeKb","HAHVAC::setFanMode::force"],[11,4,1,"_CPPv4N6HAHVAC10setFanModeEK7FanModeKb","HAHVAC::setFanMode::mode"],[11,3,1,"_CPPv4N6HAHVAC11setFanModesEK7uint8_t","HAHVAC::setFanModes"],[11,4,1,"_CPPv4N6HAHVAC11setFanModesEK7uint8_t","HAHVAC::setFanModes::modes"],[11,3,1,"_CPPv4N6HAHVAC7setIconEPKc","HAHVAC::setIcon"],[11,4,1,"_CPPv4N6HAHVAC7setIconEPKc","HAHVAC::setIcon::icon"],[11,3,1,"_CPPv4N6HAHVAC10setMaxTempEKf","HAHVAC::setMaxTemp"],[11,4,1,"_CPPv4N6HAHVAC10setMaxTempEKf","HAHVAC::setMaxTemp::max"],[11,3,1,"_CPPv4N6HAHVAC10setMinTempEKf","HAHVAC::setMinTemp"],[11,4,1,"_CPPv4N6HAHVAC10setMinTempEKf","HAHVAC::setMinTemp::min"],[11,3,1,"_CPPv4N6HAHVAC7setModeEK4ModeKb","HAHVAC::setMode"],[11,4,1,"_CPPv4N6HAHVAC7setModeEK4ModeKb","HAHVAC::setMode::force"],[11,4,1,"_CPPv4N6HAHVAC7setModeEK4ModeKb","HAHVAC::setMode::mode"],[11,3,1,"_CPPv4N6HAHVAC8setModesEK7uint8_t","HAHVAC::setModes"],[11,4,1,"_CPPv4N6HAHVAC8setModesEK7uint8_t","HAHVAC::setModes::modes"],[11,3,1,"_CPPv4N6HAHVAC9setRetainEKb","HAHVAC::setRetain"],[11,4,1,"_CPPv4N6HAHVAC9setRetainEKb","HAHVAC::setRetain::retain"],[11,3,1,"_CPPv4N6HAHVAC12setSwingModeEK9SwingModeKb","HAHVAC::setSwingMode"],[11,4,1,"_CPPv4N6HAHVAC12setSwingModeEK9SwingModeKb","HAHVAC::setSwingMode::force"],[11,4,1,"_CPPv4N6HAHVAC12setSwingModeEK9SwingModeKb","HAHVAC::setSwingMode::mode"],[11,3,1,"_CPPv4N6HAHVAC13setSwingModesEK7uint8_t","HAHVAC::setSwingModes"],[11,4,1,"_CPPv4N6HAHVAC13setSwingModesEK7uint8_t","HAHVAC::setSwingModes::modes"],[11,3,1,"_CPPv4N6HAHVAC20setTargetTemperatureEK6int8_tKb","HAHVAC::setTargetTemperature"],[11,3,1,"_CPPv4N6HAHVAC20setTargetTemperatureEK7int16_tKb","HAHVAC::setTargetTemperature"],[11,3,1,"_CPPv4N6HAHVAC20setTargetTemperatureEK7int32_tKb","HAHVAC::setTargetTemperature"],[11,3,1,"_CPPv4N6HAHVAC20setTargetTemperatureEK7uint8_tKb","HAHVAC::setTargetTemperature"],[11,3,1,"_CPPv4N6HAHVAC20setTargetTemperatureEK8uint16_tKb","HAHVAC::setTargetTemperature"],[11,3,1,"_CPPv4N6HAHVAC20setTargetTemperatureEK8uint32_tKb","HAHVAC::setTargetTemperature"],[11,3,1,"_CPPv4N6HAHVAC20setTargetTemperatureEKfKb","HAHVAC::setTargetTemperature"],[11,3,1,"_CPPv4N6HAHVAC20setTargetTemperatureERK9HANumericKb","HAHVAC::setTargetTemperature"],[11,4,1,"_CPPv4N6HAHVAC20setTargetTemperatureEK6int8_tKb","HAHVAC::setTargetTemperature::force"],[11,4,1,"_CPPv4N6HAHVAC20setTargetTemperatureEK7int16_tKb","HAHVAC::setTargetTemperature::force"],[11,4,1,"_CPPv4N6HAHVAC20setTargetTemperatureEK7int32_tKb","HAHVAC::setTargetTemperature::force"],[11,4,1,"_CPPv4N6HAHVAC20setTargetTemperatureEK7uint8_tKb","HAHVAC::setTargetTemperature::force"],[11,4,1,"_CPPv4N6HAHVAC20setTargetTemperatureEK8uint16_tKb","HAHVAC::setTargetTemperature::force"],[11,4,1,"_CPPv4N6HAHVAC20setTargetTemperatureEK8uint32_tKb","HAHVAC::setTargetTemperature::force"],[11,4,1,"_CPPv4N6HAHVAC20setTargetTemperatureEKfKb","HAHVAC::setTargetTemperature::force"],[11,4,1,"_CPPv4N6HAHVAC20setTargetTemperatureERK9HANumericKb","HAHVAC::setTargetTemperature::force"],[11,4,1,"_CPPv4N6HAHVAC20setTargetTemperatureEK6int8_tKb","HAHVAC::setTargetTemperature::temperature"],[11,4,1,"_CPPv4N6HAHVAC20setTargetTemperatureEK7int16_tKb","HAHVAC::setTargetTemperature::temperature"],[11,4,1,"_CPPv4N6HAHVAC20setTargetTemperatureEK7int32_tKb","HAHVAC::setTargetTemperature::temperature"],[11,4,1,"_CPPv4N6HAHVAC20setTargetTemperatureEK7uint8_tKb","HAHVAC::setTargetTemperature::temperature"],[11,4,1,"_CPPv4N6HAHVAC20setTargetTemperatureEK8uint16_tKb","HAHVAC::setTargetTemperature::temperature"],[11,4,1,"_CPPv4N6HAHVAC20setTargetTemperatureEK8uint32_tKb","HAHVAC::setTargetTemperature::temperature"],[11,4,1,"_CPPv4N6HAHVAC20setTargetTemperatureEKfKb","HAHVAC::setTargetTemperature::temperature"],[11,4,1,"_CPPv4N6HAHVAC20setTargetTemperatureERK9HANumericKb","HAHVAC::setTargetTemperature::temperature"],[11,3,1,"_CPPv4N6HAHVAC11setTempStepEKf","HAHVAC::setTempStep"],[11,4,1,"_CPPv4N6HAHVAC11setTempStepEKf","HAHVAC::setTempStep::step"],[11,3,1,"_CPPv4N6HAHVAC18setTemperatureUnitE15TemperatureUnit","HAHVAC::setTemperatureUnit"],[11,4,1,"_CPPv4N6HAHVAC18setTemperatureUnitE15TemperatureUnit","HAHVAC::setTemperatureUnit::unit"],[11,3,1,"_CPPv4N6HAHVACD0Ev","HAHVAC::~HAHVAC"],[12,0,1,"_CPPv47HALight","HALight"],[12,2,1,"_CPPv4N7HALight8Features17BrightnessFeatureE","HALight::BrightnessFeature"],[12,2,1,"_CPPv4N7HALight8Features23ColorTemperatureFeatureE","HALight::ColorTemperatureFeature"],[12,2,1,"_CPPv4N7HALight8Features15DefaultFeaturesE","HALight::DefaultFeatures"],[12,1,1,"_CPPv4N7HALight8FeaturesE","HALight::Features"],[12,2,1,"_CPPv4N7HALight8Features17BrightnessFeatureE","HALight::Features::BrightnessFeature"],[12,2,1,"_CPPv4N7HALight8Features23ColorTemperatureFeatureE","HALight::Features::ColorTemperatureFeature"],[12,2,1,"_CPPv4N7HALight8Features15DefaultFeaturesE","HALight::Features::DefaultFeatures"],[12,2,1,"_CPPv4N7HALight8Features10RGBFeatureE","HALight::Features::RGBFeature"],[12,3,1,"_CPPv4N7HALight7HALightEPKcK7uint8_t","HALight::HALight"],[12,4,1,"_CPPv4N7HALight7HALightEPKcK7uint8_t","HALight::HALight::features"],[12,4,1,"_CPPv4N7HALight7HALightEPKcK7uint8_t","HALight::HALight::uniqueId"],[12,0,1,"_CPPv4N7HALight8RGBColorE","HALight::RGBColor"],[12,3,1,"_CPPv4N7HALight8RGBColor8RGBColorE7uint8_t7uint8_t7uint8_t","HALight::RGBColor::RGBColor"],[12,3,1,"_CPPv4N7HALight8RGBColor8RGBColorEv","HALight::RGBColor::RGBColor"],[12,4,1,"_CPPv4N7HALight8RGBColor8RGBColorE7uint8_t7uint8_t7uint8_t","HALight::RGBColor::RGBColor::b"],[12,4,1,"_CPPv4N7HALight8RGBColor8RGBColorE7uint8_t7uint8_t7uint8_t","HALight::RGBColor::RGBColor::g"],[12,4,1,"_CPPv4N7HALight8RGBColor8RGBColorE7uint8_t7uint8_t7uint8_t","HALight::RGBColor::RGBColor::r"],[12,5,1,"_CPPv4N7HALight8RGBColor4blueE","HALight::RGBColor::blue"],[12,3,1,"_CPPv4N7HALight8RGBColor10fromBufferEPK7uint8_tK8uint16_t","HALight::RGBColor::fromBuffer"],[12,4,1,"_CPPv4N7HALight8RGBColor10fromBufferEPK7uint8_tK8uint16_t","HALight::RGBColor::fromBuffer::data"],[12,4,1,"_CPPv4N7HALight8RGBColor10fromBufferEPK7uint8_tK8uint16_t","HALight::RGBColor::fromBuffer::length"],[12,5,1,"_CPPv4N7HALight8RGBColor5greenE","HALight::RGBColor::green"],[12,5,1,"_CPPv4N7HALight8RGBColor5isSetE","HALight::RGBColor::isSet"],[12,3,1,"_CPPv4NK7HALight8RGBColorneERK8RGBColor","HALight::RGBColor::operator!="],[12,4,1,"_CPPv4NK7HALight8RGBColorneERK8RGBColor","HALight::RGBColor::operator!=::a"],[12,3,1,"_CPPv4N7HALight8RGBColoraSERK8RGBColor","HALight::RGBColor::operator="],[12,4,1,"_CPPv4N7HALight8RGBColoraSERK8RGBColor","HALight::RGBColor::operator=::a"],[12,3,1,"_CPPv4NK7HALight8RGBColoreqERK8RGBColor","HALight::RGBColor::operator=="],[12,4,1,"_CPPv4NK7HALight8RGBColoreqERK8RGBColor","HALight::RGBColor::operator==::a"],[12,5,1,"_CPPv4N7HALight8RGBColor3redE","HALight::RGBColor::red"],[12,2,1,"_CPPv4N7HALight8Features10RGBFeatureE","HALight::RGBFeature"],[12,5,1,"_CPPv4N7HALight18RGBStringMaxLengthE","HALight::RGBStringMaxLength"],[12,5,1,"_CPPv4N7HALight19_brightnessCallbackE","HALight::_brightnessCallback"],[12,5,1,"_CPPv4N7HALight16_brightnessScaleE","HALight::_brightnessScale"],[12,5,1,"_CPPv4N7HALight25_colorTemperatureCallbackE","HALight::_colorTemperatureCallback"],[12,5,1,"_CPPv4N7HALight18_currentBrightnessE","HALight::_currentBrightness"],[12,5,1,"_CPPv4N7HALight24_currentColorTemperatureE","HALight::_currentColorTemperature"],[12,5,1,"_CPPv4N7HALight16_currentRGBColorE","HALight::_currentRGBColor"],[12,5,1,"_CPPv4N7HALight13_currentStateE","HALight::_currentState"],[12,5,1,"_CPPv4N7HALight9_featuresE","HALight::_features"],[12,5,1,"_CPPv4N7HALight5_iconE","HALight::_icon"],[12,5,1,"_CPPv4N7HALight10_maxMiredsE","HALight::_maxMireds"],[12,5,1,"_CPPv4N7HALight10_minMiredsE","HALight::_minMireds"],[12,5,1,"_CPPv4N7HALight11_optimisticE","HALight::_optimistic"],[12,5,1,"_CPPv4N7HALight7_retainE","HALight::_retain"],[12,5,1,"_CPPv4N7HALight17_rgbColorCallbackE","HALight::_rgbColorCallback"],[12,5,1,"_CPPv4N7HALight14_stateCallbackE","HALight::_stateCallback"],[12,3,1,"_CPPv4N7HALight15buildSerializerEv","HALight::buildSerializer"],[12,3,1,"_CPPv4NK7HALight20getCurrentBrightnessEv","HALight::getCurrentBrightness"],[12,3,1,"_CPPv4NK7HALight26getCurrentColorTemperatureEv","HALight::getCurrentColorTemperature"],[12,3,1,"_CPPv4NK7HALight18getCurrentRGBColorEv","HALight::getCurrentRGBColor"],[12,3,1,"_CPPv4NK7HALight15getCurrentStateEv","HALight::getCurrentState"],[12,3,1,"_CPPv4N7HALight23handleBrightnessCommandEPK7uint8_tK8uint16_t","HALight::handleBrightnessCommand"],[12,4,1,"_CPPv4N7HALight23handleBrightnessCommandEPK7uint8_tK8uint16_t","HALight::handleBrightnessCommand::cmd"],[12,4,1,"_CPPv4N7HALight23handleBrightnessCommandEPK7uint8_tK8uint16_t","HALight::handleBrightnessCommand::length"],[12,3,1,"_CPPv4N7HALight29handleColorTemperatureCommandEPK7uint8_tK8uint16_t","HALight::handleColorTemperatureCommand"],[12,4,1,"_CPPv4N7HALight29handleColorTemperatureCommandEPK7uint8_tK8uint16_t","HALight::handleColorTemperatureCommand::cmd"],[12,4,1,"_CPPv4N7HALight29handleColorTemperatureCommandEPK7uint8_tK8uint16_t","HALight::handleColorTemperatureCommand::length"],[12,3,1,"_CPPv4N7HALight16handleRGBCommandEPK7uint8_tK8uint16_t","HALight::handleRGBCommand"],[12,4,1,"_CPPv4N7HALight16handleRGBCommandEPK7uint8_tK8uint16_t","HALight::handleRGBCommand::cmd"],[12,4,1,"_CPPv4N7HALight16handleRGBCommandEPK7uint8_tK8uint16_t","HALight::handleRGBCommand::length"],[12,3,1,"_CPPv4N7HALight18handleStateCommandEPK7uint8_tK8uint16_t","HALight::handleStateCommand"],[12,4,1,"_CPPv4N7HALight18handleStateCommandEPK7uint8_tK8uint16_t","HALight::handleStateCommand::cmd"],[12,4,1,"_CPPv4N7HALight18handleStateCommandEPK7uint8_tK8uint16_t","HALight::handleStateCommand::length"],[12,3,1,"_CPPv4N7HALight19onBrightnessCommandEPFv7uint8_tP7HALightE","HALight::onBrightnessCommand"],[12,4,1,"_CPPv4N7HALight19onBrightnessCommandEPFv7uint8_tP7HALightE","HALight::onBrightnessCommand::callback"],[12,3,1,"_CPPv4N7HALight25onColorTemperatureCommandEPFv8uint16_tP7HALightE","HALight::onColorTemperatureCommand"],[12,4,1,"_CPPv4N7HALight25onColorTemperatureCommandEPFv8uint16_tP7HALightE","HALight::onColorTemperatureCommand::callback"],[12,3,1,"_CPPv4N7HALight15onMqttConnectedEv","HALight::onMqttConnected"],[12,3,1,"_CPPv4N7HALight13onMqttMessageEPKcPK7uint8_tK8uint16_t","HALight::onMqttMessage"],[12,4,1,"_CPPv4N7HALight13onMqttMessageEPKcPK7uint8_tK8uint16_t","HALight::onMqttMessage::length"],[12,4,1,"_CPPv4N7HALight13onMqttMessageEPKcPK7uint8_tK8uint16_t","HALight::onMqttMessage::payload"],[12,4,1,"_CPPv4N7HALight13onMqttMessageEPKcPK7uint8_tK8uint16_t","HALight::onMqttMessage::topic"],[12,3,1,"_CPPv4N7HALight17onRGBColorCommandEPFvN7HALight8RGBColorEP7HALightE","HALight::onRGBColorCommand"],[12,4,1,"_CPPv4N7HALight17onRGBColorCommandEPFvN7HALight8RGBColorEP7HALightE","HALight::onRGBColorCommand::callback"],[12,3,1,"_CPPv4N7HALight14onStateCommandEPFvbP7HALightE","HALight::onStateCommand"],[12,4,1,"_CPPv4N7HALight14onStateCommandEPFvbP7HALightE","HALight::onStateCommand::callback"],[12,3,1,"_CPPv4N7HALight17publishBrightnessEK7uint8_t","HALight::publishBrightness"],[12,4,1,"_CPPv4N7HALight17publishBrightnessEK7uint8_t","HALight::publishBrightness::brightness"],[12,3,1,"_CPPv4N7HALight23publishColorTemperatureEK8uint16_t","HALight::publishColorTemperature"],[12,4,1,"_CPPv4N7HALight23publishColorTemperatureEK8uint16_t","HALight::publishColorTemperature::temperature"],[12,3,1,"_CPPv4N7HALight15publishRGBColorERK8RGBColor","HALight::publishRGBColor"],[12,4,1,"_CPPv4N7HALight15publishRGBColorERK8RGBColor","HALight::publishRGBColor::color"],[12,3,1,"_CPPv4N7HALight12publishStateEKb","HALight::publishState"],[12,4,1,"_CPPv4N7HALight12publishStateEKb","HALight::publishState::state"],[12,3,1,"_CPPv4N7HALight13setBrightnessEK7uint8_tKb","HALight::setBrightness"],[12,4,1,"_CPPv4N7HALight13setBrightnessEK7uint8_tKb","HALight::setBrightness::brightness"],[12,4,1,"_CPPv4N7HALight13setBrightnessEK7uint8_tKb","HALight::setBrightness::force"],[12,3,1,"_CPPv4N7HALight18setBrightnessScaleEK7uint8_t","HALight::setBrightnessScale"],[12,4,1,"_CPPv4N7HALight18setBrightnessScaleEK7uint8_t","HALight::setBrightnessScale::scale"],[12,3,1,"_CPPv4N7HALight19setColorTemperatureEK8uint16_tKb","HALight::setColorTemperature"],[12,4,1,"_CPPv4N7HALight19setColorTemperatureEK8uint16_tKb","HALight::setColorTemperature::force"],[12,4,1,"_CPPv4N7HALight19setColorTemperatureEK8uint16_tKb","HALight::setColorTemperature::temperature"],[12,3,1,"_CPPv4N7HALight20setCurrentBrightnessEK7uint8_t","HALight::setCurrentBrightness"],[12,4,1,"_CPPv4N7HALight20setCurrentBrightnessEK7uint8_t","HALight::setCurrentBrightness::brightness"],[12,3,1,"_CPPv4N7HALight26setCurrentColorTemperatureEK8uint16_t","HALight::setCurrentColorTemperature"],[12,4,1,"_CPPv4N7HALight26setCurrentColorTemperatureEK8uint16_t","HALight::setCurrentColorTemperature::temperature"],[12,3,1,"_CPPv4N7HALight18setCurrentRGBColorERK8RGBColor","HALight::setCurrentRGBColor"],[12,4,1,"_CPPv4N7HALight18setCurrentRGBColorERK8RGBColor","HALight::setCurrentRGBColor::color"],[12,3,1,"_CPPv4N7HALight15setCurrentStateEKb","HALight::setCurrentState"],[12,4,1,"_CPPv4N7HALight15setCurrentStateEKb","HALight::setCurrentState::state"],[12,3,1,"_CPPv4N7HALight7setIconEPKc","HALight::setIcon"],[12,4,1,"_CPPv4N7HALight7setIconEPKc","HALight::setIcon::icon"],[12,3,1,"_CPPv4N7HALight12setMaxMiredsEK8uint16_t","HALight::setMaxMireds"],[12,4,1,"_CPPv4N7HALight12setMaxMiredsEK8uint16_t","HALight::setMaxMireds::mireds"],[12,3,1,"_CPPv4N7HALight12setMinMiredsEK8uint16_t","HALight::setMinMireds"],[12,4,1,"_CPPv4N7HALight12setMinMiredsEK8uint16_t","HALight::setMinMireds::mireds"],[12,3,1,"_CPPv4N7HALight13setOptimisticEKb","HALight::setOptimistic"],[12,4,1,"_CPPv4N7HALight13setOptimisticEKb","HALight::setOptimistic::optimistic"],[12,3,1,"_CPPv4N7HALight11setRGBColorERK8RGBColorKb","HALight::setRGBColor"],[12,4,1,"_CPPv4N7HALight11setRGBColorERK8RGBColorKb","HALight::setRGBColor::color"],[12,4,1,"_CPPv4N7HALight11setRGBColorERK8RGBColorKb","HALight::setRGBColor::force"],[12,3,1,"_CPPv4N7HALight9setRetainEKb","HALight::setRetain"],[12,4,1,"_CPPv4N7HALight9setRetainEKb","HALight::setRetain::retain"],[12,3,1,"_CPPv4N7HALight8setStateEKbKb","HALight::setState"],[12,4,1,"_CPPv4N7HALight8setStateEKbKb","HALight::setState::force"],[12,4,1,"_CPPv4N7HALight8setStateEKbKb","HALight::setState::state"],[12,3,1,"_CPPv4N7HALight7turnOffEv","HALight::turnOff"],[12,3,1,"_CPPv4N7HALight6turnOnEv","HALight::turnOn"],[13,0,1,"_CPPv46HALock","HALock"],[13,2,1,"_CPPv4N6HALock11LockCommand11CommandLockE","HALock::CommandLock"],[13,2,1,"_CPPv4N6HALock11LockCommand11CommandOpenE","HALock::CommandOpen"],[13,2,1,"_CPPv4N6HALock11LockCommand13CommandUnlockE","HALock::CommandUnlock"],[13,3,1,"_CPPv4N6HALock6HALockEPKc","HALock::HALock"],[13,4,1,"_CPPv4N6HALock6HALockEPKc","HALock::HALock::uniqueId"],[13,1,1,"_CPPv4N6HALock11LockCommandE","HALock::LockCommand"],[13,2,1,"_CPPv4N6HALock11LockCommand11CommandLockE","HALock::LockCommand::CommandLock"],[13,2,1,"_CPPv4N6HALock11LockCommand11CommandOpenE","HALock::LockCommand::CommandOpen"],[13,2,1,"_CPPv4N6HALock11LockCommand13CommandUnlockE","HALock::LockCommand::CommandUnlock"],[13,1,1,"_CPPv4N6HALock9LockStateE","HALock::LockState"],[13,2,1,"_CPPv4N6HALock9LockState11StateLockedE","HALock::LockState::StateLocked"],[13,2,1,"_CPPv4N6HALock9LockState12StateUnknownE","HALock::LockState::StateUnknown"],[13,2,1,"_CPPv4N6HALock9LockState13StateUnlockedE","HALock::LockState::StateUnlocked"],[13,2,1,"_CPPv4N6HALock9LockState11StateLockedE","HALock::StateLocked"],[13,2,1,"_CPPv4N6HALock9LockState12StateUnknownE","HALock::StateUnknown"],[13,2,1,"_CPPv4N6HALock9LockState13StateUnlockedE","HALock::StateUnlocked"],[13,5,1,"_CPPv4N6HALock16_commandCallbackE","HALock::_commandCallback"],[13,5,1,"_CPPv4N6HALock13_currentStateE","HALock::_currentState"],[13,5,1,"_CPPv4N6HALock5_iconE","HALock::_icon"],[13,5,1,"_CPPv4N6HALock11_optimisticE","HALock::_optimistic"],[13,5,1,"_CPPv4N6HALock7_retainE","HALock::_retain"],[13,3,1,"_CPPv4N6HALock15buildSerializerEv","HALock::buildSerializer"],[13,3,1,"_CPPv4NK6HALock15getCurrentStateEv","HALock::getCurrentState"],[13,3,1,"_CPPv4N6HALock13handleCommandEPK7uint8_tK8uint16_t","HALock::handleCommand"],[13,4,1,"_CPPv4N6HALock13handleCommandEPK7uint8_tK8uint16_t","HALock::handleCommand::cmd"],[13,4,1,"_CPPv4N6HALock13handleCommandEPK7uint8_tK8uint16_t","HALock::handleCommand::length"],[13,3,1,"_CPPv4N6HALock9onCommandEPFv11LockCommandP6HALockE","HALock::onCommand"],[13,4,1,"_CPPv4N6HALock9onCommandEPFv11LockCommandP6HALockE","HALock::onCommand::callback"],[13,3,1,"_CPPv4N6HALock15onMqttConnectedEv","HALock::onMqttConnected"],[13,3,1,"_CPPv4N6HALock13onMqttMessageEPKcPK7uint8_tK8uint16_t","HALock::onMqttMessage"],[13,4,1,"_CPPv4N6HALock13onMqttMessageEPKcPK7uint8_tK8uint16_t","HALock::onMqttMessage::length"],[13,4,1,"_CPPv4N6HALock13onMqttMessageEPKcPK7uint8_tK8uint16_t","HALock::onMqttMessage::payload"],[13,4,1,"_CPPv4N6HALock13onMqttMessageEPKcPK7uint8_tK8uint16_t","HALock::onMqttMessage::topic"],[13,3,1,"_CPPv4N6HALock12publishStateEK9LockState","HALock::publishState"],[13,4,1,"_CPPv4N6HALock12publishStateEK9LockState","HALock::publishState::state"],[13,3,1,"_CPPv4N6HALock15setCurrentStateEK9LockState","HALock::setCurrentState"],[13,4,1,"_CPPv4N6HALock15setCurrentStateEK9LockState","HALock::setCurrentState::state"],[13,3,1,"_CPPv4N6HALock7setIconEPKc","HALock::setIcon"],[13,4,1,"_CPPv4N6HALock7setIconEPKc","HALock::setIcon::icon"],[13,3,1,"_CPPv4N6HALock13setOptimisticEKb","HALock::setOptimistic"],[13,4,1,"_CPPv4N6HALock13setOptimisticEKb","HALock::setOptimistic::optimistic"],[13,3,1,"_CPPv4N6HALock9setRetainEKb","HALock::setRetain"],[13,4,1,"_CPPv4N6HALock9setRetainEKb","HALock::setRetain::retain"],[13,3,1,"_CPPv4N6HALock8setStateEK9LockStateKb","HALock::setState"],[13,4,1,"_CPPv4N6HALock8setStateEK9LockStateKb","HALock::setState::force"],[13,4,1,"_CPPv4N6HALock8setStateEK9LockStateKb","HALock::setState::state"],[1,0,1,"_CPPv46HAMqtt","HAMqtt"],[1,3,1,"_CPPv4N6HAMqtt6HAMqttER6ClientR8HADeviceK7uint8_t","HAMqtt::HAMqtt"],[1,4,1,"_CPPv4N6HAMqtt6HAMqttER6ClientR8HADeviceK7uint8_t","HAMqtt::HAMqtt::device"],[1,4,1,"_CPPv4N6HAMqtt6HAMqttER6ClientR8HADeviceK7uint8_t","HAMqtt::HAMqtt::maxDevicesTypesNb"],[1,4,1,"_CPPv4N6HAMqtt6HAMqttER6ClientR8HADeviceK7uint8_t","HAMqtt::HAMqtt::netClient"],[1,5,1,"_CPPv4N6HAMqtt17ReconnectIntervalE","HAMqtt::ReconnectInterval"],[1,5,1,"_CPPv4N6HAMqtt18_connectedCallbackE","HAMqtt::_connectedCallback"],[1,5,1,"_CPPv4N6HAMqtt11_dataPrefixE","HAMqtt::_dataPrefix"],[1,5,1,"_CPPv4N6HAMqtt7_deviceE","HAMqtt::_device"],[1,5,1,"_CPPv4N6HAMqtt13_devicesTypesE","HAMqtt::_devicesTypes"],[1,5,1,"_CPPv4N6HAMqtt15_devicesTypesNbE","HAMqtt::_devicesTypesNb"],[1,5,1,"_CPPv4N6HAMqtt16_discoveryPrefixE","HAMqtt::_discoveryPrefix"],[1,5,1,"_CPPv4N6HAMqtt12_initializedE","HAMqtt::_initialized"],[1,5,1,"_CPPv4N6HAMqtt9_instanceE","HAMqtt::_instance"],[1,5,1,"_CPPv4N6HAMqtt24_lastConnectionAttemptAtE","HAMqtt::_lastConnectionAttemptAt"],[1,5,1,"_CPPv4N6HAMqtt16_lastWillMessageE","HAMqtt::_lastWillMessage"],[1,5,1,"_CPPv4N6HAMqtt15_lastWillRetainE","HAMqtt::_lastWillRetain"],[1,5,1,"_CPPv4N6HAMqtt14_lastWillTopicE","HAMqtt::_lastWillTopic"],[1,5,1,"_CPPv4N6HAMqtt18_maxDevicesTypesNbE","HAMqtt::_maxDevicesTypesNb"],[1,5,1,"_CPPv4N6HAMqtt16_messageCallbackE","HAMqtt::_messageCallback"],[1,5,1,"_CPPv4N6HAMqtt5_mqttE","HAMqtt::_mqtt"],[1,5,1,"_CPPv4N6HAMqtt9_passwordE","HAMqtt::_password"],[1,5,1,"_CPPv4N6HAMqtt9_usernameE","HAMqtt::_username"],[1,3,1,"_CPPv4N6HAMqtt13addDeviceTypeEP16HABaseDeviceType","HAMqtt::addDeviceType"],[1,4,1,"_CPPv4N6HAMqtt13addDeviceTypeEP16HABaseDeviceType","HAMqtt::addDeviceType::deviceType"],[1,3,1,"_CPPv4N6HAMqtt5beginEK9IPAddressK8uint16_tPKcPKc","HAMqtt::begin"],[1,3,1,"_CPPv4N6HAMqtt5beginEK9IPAddressPKcPKc","HAMqtt::begin"],[1,3,1,"_CPPv4N6HAMqtt5beginEPKcK8uint16_tPKcPKc","HAMqtt::begin"],[1,3,1,"_CPPv4N6HAMqtt5beginEPKcPKcPKc","HAMqtt::begin"],[1,4,1,"_CPPv4N6HAMqtt5beginEK9IPAddressK8uint16_tPKcPKc","HAMqtt::begin::password"],[1,4,1,"_CPPv4N6HAMqtt5beginEK9IPAddressPKcPKc","HAMqtt::begin::password"],[1,4,1,"_CPPv4N6HAMqtt5beginEPKcK8uint16_tPKcPKc","HAMqtt::begin::password"],[1,4,1,"_CPPv4N6HAMqtt5beginEPKcPKcPKc","HAMqtt::begin::password"],[1,4,1,"_CPPv4N6HAMqtt5beginEPKcK8uint16_tPKcPKc","HAMqtt::begin::serverHostname"],[1,4,1,"_CPPv4N6HAMqtt5beginEPKcPKcPKc","HAMqtt::begin::serverHostname"],[1,4,1,"_CPPv4N6HAMqtt5beginEK9IPAddressK8uint16_tPKcPKc","HAMqtt::begin::serverIp"],[1,4,1,"_CPPv4N6HAMqtt5beginEK9IPAddressPKcPKc","HAMqtt::begin::serverIp"],[1,4,1,"_CPPv4N6HAMqtt5beginEK9IPAddressK8uint16_tPKcPKc","HAMqtt::begin::serverPort"],[1,4,1,"_CPPv4N6HAMqtt5beginEPKcK8uint16_tPKcPKc","HAMqtt::begin::serverPort"],[1,4,1,"_CPPv4N6HAMqtt5beginEK9IPAddressK8uint16_tPKcPKc","HAMqtt::begin::username"],[1,4,1,"_CPPv4N6HAMqtt5beginEK9IPAddressPKcPKc","HAMqtt::begin::username"],[1,4,1,"_CPPv4N6HAMqtt5beginEPKcK8uint16_tPKcPKc","HAMqtt::begin::username"],[1,4,1,"_CPPv4N6HAMqtt5beginEPKcPKcPKc","HAMqtt::begin::username"],[1,3,1,"_CPPv4N6HAMqtt12beginPublishEPKc8uint16_tb","HAMqtt::beginPublish"],[1,4,1,"_CPPv4N6HAMqtt12beginPublishEPKc8uint16_tb","HAMqtt::beginPublish::payloadLength"],[1,4,1,"_CPPv4N6HAMqtt12beginPublishEPKc8uint16_tb","HAMqtt::beginPublish::retained"],[1,4,1,"_CPPv4N6HAMqtt12beginPublishEPKc8uint16_tb","HAMqtt::beginPublish::topic"],[1,3,1,"_CPPv4N6HAMqtt15connectToServerEv","HAMqtt::connectToServer"],[1,3,1,"_CPPv4N6HAMqtt10disconnectEv","HAMqtt::disconnect"],[1,3,1,"_CPPv4N6HAMqtt10endPublishEv","HAMqtt::endPublish"],[1,3,1,"_CPPv4NK6HAMqtt13getDataPrefixEv","HAMqtt::getDataPrefix"],[1,3,1,"_CPPv4NK6HAMqtt9getDeviceEv","HAMqtt::getDevice"],[1,3,1,"_CPPv4NK6HAMqtt18getDiscoveryPrefixEv","HAMqtt::getDiscoveryPrefix"],[1,3,1,"_CPPv4N6HAMqtt8instanceEv","HAMqtt::instance"],[1,3,1,"_CPPv4NK6HAMqtt11isConnectedEv","HAMqtt::isConnected"],[1,3,1,"_CPPv4N6HAMqtt4loopEv","HAMqtt::loop"],[1,3,1,"_CPPv4N6HAMqtt11onConnectedEPFvvE","HAMqtt::onConnected"],[1,4,1,"_CPPv4N6HAMqtt11onConnectedEPFvvE","HAMqtt::onConnected::callback"],[1,3,1,"_CPPv4N6HAMqtt16onConnectedLogicEv","HAMqtt::onConnectedLogic"],[1,3,1,"_CPPv4N6HAMqtt9onMessageEPFvPKcPK7uint8_t8uint16_tE","HAMqtt::onMessage"],[1,4,1,"_CPPv4N6HAMqtt9onMessageEPFvPKcPK7uint8_t8uint16_tE","HAMqtt::onMessage::callback"],[1,3,1,"_CPPv4N6HAMqtt14processMessageEPKcPK7uint8_t8uint16_t","HAMqtt::processMessage"],[1,4,1,"_CPPv4N6HAMqtt14processMessageEPKcPK7uint8_t8uint16_t","HAMqtt::processMessage::length"],[1,4,1,"_CPPv4N6HAMqtt14processMessageEPKcPK7uint8_t8uint16_t","HAMqtt::processMessage::payload"],[1,4,1,"_CPPv4N6HAMqtt14processMessageEPKcPK7uint8_t8uint16_t","HAMqtt::processMessage::topic"],[1,3,1,"_CPPv4N6HAMqtt7publishEPKcPKcb","HAMqtt::publish"],[1,4,1,"_CPPv4N6HAMqtt7publishEPKcPKcb","HAMqtt::publish::payload"],[1,4,1,"_CPPv4N6HAMqtt7publishEPKcPKcb","HAMqtt::publish::retained"],[1,4,1,"_CPPv4N6HAMqtt7publishEPKcPKcb","HAMqtt::publish::topic"],[1,3,1,"_CPPv4N6HAMqtt13setDataPrefixEPKc","HAMqtt::setDataPrefix"],[1,4,1,"_CPPv4N6HAMqtt13setDataPrefixEPKc","HAMqtt::setDataPrefix::prefix"],[1,3,1,"_CPPv4N6HAMqtt18setDiscoveryPrefixEPKc","HAMqtt::setDiscoveryPrefix"],[1,4,1,"_CPPv4N6HAMqtt18setDiscoveryPrefixEPKc","HAMqtt::setDiscoveryPrefix::prefix"],[1,3,1,"_CPPv4N6HAMqtt11setLastWillEPKcPKcb","HAMqtt::setLastWill"],[1,4,1,"_CPPv4N6HAMqtt11setLastWillEPKcPKcb","HAMqtt::setLastWill::lastWillMessage"],[1,4,1,"_CPPv4N6HAMqtt11setLastWillEPKcPKcb","HAMqtt::setLastWill::lastWillRetain"],[1,4,1,"_CPPv4N6HAMqtt11setLastWillEPKcPKcb","HAMqtt::setLastWill::lastWillTopic"],[1,3,1,"_CPPv4N6HAMqtt9subscribeEPKc","HAMqtt::subscribe"],[1,4,1,"_CPPv4N6HAMqtt9subscribeEPKc","HAMqtt::subscribe::topic"],[1,3,1,"_CPPv4N6HAMqtt12writePayloadEPK19__FlashStringHelper","HAMqtt::writePayload"],[1,3,1,"_CPPv4N6HAMqtt12writePayloadEPK7uint8_tK8uint16_t","HAMqtt::writePayload"],[1,3,1,"_CPPv4N6HAMqtt12writePayloadEPKcK8uint16_t","HAMqtt::writePayload"],[1,4,1,"_CPPv4N6HAMqtt12writePayloadEPK19__FlashStringHelper","HAMqtt::writePayload::data"],[1,4,1,"_CPPv4N6HAMqtt12writePayloadEPK7uint8_tK8uint16_t","HAMqtt::writePayload::data"],[1,4,1,"_CPPv4N6HAMqtt12writePayloadEPKcK8uint16_t","HAMqtt::writePayload::data"],[1,4,1,"_CPPv4N6HAMqtt12writePayloadEPK7uint8_tK8uint16_t","HAMqtt::writePayload::length"],[1,4,1,"_CPPv4N6HAMqtt12writePayloadEPKcK8uint16_t","HAMqtt::writePayload::length"],[1,3,1,"_CPPv4N6HAMqttD0Ev","HAMqtt::~HAMqtt"],[14,0,1,"_CPPv48HANumber","HANumber"],[14,3,1,"_CPPv4N8HANumber8HANumberEPKcK15NumberPrecision","HANumber::HANumber"],[14,4,1,"_CPPv4N8HANumber8HANumberEPKcK15NumberPrecision","HANumber::HANumber::precision"],[14,4,1,"_CPPv4N8HANumber8HANumberEPKcK15NumberPrecision","HANumber::HANumber::uniqueId"],[14,1,1,"_CPPv4N8HANumber4ModeE","HANumber::Mode"],[14,2,1,"_CPPv4N8HANumber4Mode8ModeAutoE","HANumber::Mode::ModeAuto"],[14,2,1,"_CPPv4N8HANumber4Mode7ModeBoxE","HANumber::Mode::ModeBox"],[14,2,1,"_CPPv4N8HANumber4Mode10ModeSliderE","HANumber::Mode::ModeSlider"],[14,2,1,"_CPPv4N8HANumber4Mode8ModeAutoE","HANumber::ModeAuto"],[14,2,1,"_CPPv4N8HANumber4Mode7ModeBoxE","HANumber::ModeBox"],[14,2,1,"_CPPv4N8HANumber4Mode10ModeSliderE","HANumber::ModeSlider"],[14,5,1,"_CPPv4N8HANumber6_classE","HANumber::_class"],[14,5,1,"_CPPv4N8HANumber16_commandCallbackE","HANumber::_commandCallback"],[14,5,1,"_CPPv4N8HANumber13_currentStateE","HANumber::_currentState"],[14,5,1,"_CPPv4N8HANumber5_iconE","HANumber::_icon"],[14,5,1,"_CPPv4N8HANumber9_maxValueE","HANumber::_maxValue"],[14,5,1,"_CPPv4N8HANumber9_minValueE","HANumber::_minValue"],[14,5,1,"_CPPv4N8HANumber5_modeE","HANumber::_mode"],[14,5,1,"_CPPv4N8HANumber11_optimisticE","HANumber::_optimistic"],[14,5,1,"_CPPv4N8HANumber10_precisionE","HANumber::_precision"],[14,5,1,"_CPPv4N8HANumber7_retainE","HANumber::_retain"],[14,5,1,"_CPPv4N8HANumber5_stepE","HANumber::_step"],[14,5,1,"_CPPv4N8HANumber18_unitOfMeasurementE","HANumber::_unitOfMeasurement"],[14,3,1,"_CPPv4N8HANumber15buildSerializerEv","HANumber::buildSerializer"],[14,3,1,"_CPPv4N8HANumber18getCommandTemplateEv","HANumber::getCommandTemplate"],[14,3,1,"_CPPv4NK8HANumber15getCurrentStateEv","HANumber::getCurrentState"],[14,3,1,"_CPPv4NK8HANumber15getModePropertyEv","HANumber::getModeProperty"],[14,3,1,"_CPPv4N8HANumber13handleCommandEPK7uint8_tK8uint16_t","HANumber::handleCommand"],[14,4,1,"_CPPv4N8HANumber13handleCommandEPK7uint8_tK8uint16_t","HANumber::handleCommand::cmd"],[14,4,1,"_CPPv4N8HANumber13handleCommandEPK7uint8_tK8uint16_t","HANumber::handleCommand::length"],[14,3,1,"_CPPv4N8HANumber9onCommandEPFv9HANumericP8HANumberE","HANumber::onCommand"],[14,4,1,"_CPPv4N8HANumber9onCommandEPFv9HANumericP8HANumberE","HANumber::onCommand::callback"],[14,3,1,"_CPPv4N8HANumber15onMqttConnectedEv","HANumber::onMqttConnected"],[14,3,1,"_CPPv4N8HANumber13onMqttMessageEPKcPK7uint8_tK8uint16_t","HANumber::onMqttMessage"],[14,4,1,"_CPPv4N8HANumber13onMqttMessageEPKcPK7uint8_tK8uint16_t","HANumber::onMqttMessage::length"],[14,4,1,"_CPPv4N8HANumber13onMqttMessageEPKcPK7uint8_tK8uint16_t","HANumber::onMqttMessage::payload"],[14,4,1,"_CPPv4N8HANumber13onMqttMessageEPKcPK7uint8_tK8uint16_t","HANumber::onMqttMessage::topic"],[14,3,1,"_CPPv4N8HANumber12publishStateERK9HANumeric","HANumber::publishState"],[14,4,1,"_CPPv4N8HANumber12publishStateERK9HANumeric","HANumber::publishState::state"],[14,3,1,"_CPPv4N8HANumber15setCurrentStateEK6int8_t","HANumber::setCurrentState"],[14,3,1,"_CPPv4N8HANumber15setCurrentStateEK7int16_t","HANumber::setCurrentState"],[14,3,1,"_CPPv4N8HANumber15setCurrentStateEK7int32_t","HANumber::setCurrentState"],[14,3,1,"_CPPv4N8HANumber15setCurrentStateEK7uint8_t","HANumber::setCurrentState"],[14,3,1,"_CPPv4N8HANumber15setCurrentStateEK8uint16_t","HANumber::setCurrentState"],[14,3,1,"_CPPv4N8HANumber15setCurrentStateEK8uint32_t","HANumber::setCurrentState"],[14,3,1,"_CPPv4N8HANumber15setCurrentStateEKf","HANumber::setCurrentState"],[14,3,1,"_CPPv4N8HANumber15setCurrentStateERK9HANumeric","HANumber::setCurrentState"],[14,4,1,"_CPPv4N8HANumber15setCurrentStateEK6int8_t","HANumber::setCurrentState::state"],[14,4,1,"_CPPv4N8HANumber15setCurrentStateEK7int16_t","HANumber::setCurrentState::state"],[14,4,1,"_CPPv4N8HANumber15setCurrentStateEK7int32_t","HANumber::setCurrentState::state"],[14,4,1,"_CPPv4N8HANumber15setCurrentStateEK7uint8_t","HANumber::setCurrentState::state"],[14,4,1,"_CPPv4N8HANumber15setCurrentStateEK8uint16_t","HANumber::setCurrentState::state"],[14,4,1,"_CPPv4N8HANumber15setCurrentStateEK8uint32_t","HANumber::setCurrentState::state"],[14,4,1,"_CPPv4N8HANumber15setCurrentStateEKf","HANumber::setCurrentState::state"],[14,4,1,"_CPPv4N8HANumber15setCurrentStateERK9HANumeric","HANumber::setCurrentState::state"],[14,3,1,"_CPPv4N8HANumber14setDeviceClassEPKc","HANumber::setDeviceClass"],[14,4,1,"_CPPv4N8HANumber14setDeviceClassEPKc","HANumber::setDeviceClass::deviceClass"],[14,3,1,"_CPPv4N8HANumber7setIconEPKc","HANumber::setIcon"],[14,4,1,"_CPPv4N8HANumber7setIconEPKc","HANumber::setIcon::icon"],[14,3,1,"_CPPv4N8HANumber6setMaxEKf","HANumber::setMax"],[14,4,1,"_CPPv4N8HANumber6setMaxEKf","HANumber::setMax::max"],[14,3,1,"_CPPv4N8HANumber6setMinEKf","HANumber::setMin"],[14,4,1,"_CPPv4N8HANumber6setMinEKf","HANumber::setMin::min"],[14,3,1,"_CPPv4N8HANumber7setModeEK4Mode","HANumber::setMode"],[14,4,1,"_CPPv4N8HANumber7setModeEK4Mode","HANumber::setMode::mode"],[14,3,1,"_CPPv4N8HANumber13setOptimisticEKb","HANumber::setOptimistic"],[14,4,1,"_CPPv4N8HANumber13setOptimisticEKb","HANumber::setOptimistic::optimistic"],[14,3,1,"_CPPv4N8HANumber9setRetainEKb","HANumber::setRetain"],[14,4,1,"_CPPv4N8HANumber9setRetainEKb","HANumber::setRetain::retain"],[14,3,1,"_CPPv4N8HANumber8setStateEK6int8_tKb","HANumber::setState"],[14,3,1,"_CPPv4N8HANumber8setStateEK7int16_tKb","HANumber::setState"],[14,3,1,"_CPPv4N8HANumber8setStateEK7int32_tKb","HANumber::setState"],[14,3,1,"_CPPv4N8HANumber8setStateEK7uint8_tKb","HANumber::setState"],[14,3,1,"_CPPv4N8HANumber8setStateEK8uint16_tKb","HANumber::setState"],[14,3,1,"_CPPv4N8HANumber8setStateEK8uint32_tKb","HANumber::setState"],[14,3,1,"_CPPv4N8HANumber8setStateEKfKb","HANumber::setState"],[14,3,1,"_CPPv4N8HANumber8setStateERK9HANumericKb","HANumber::setState"],[14,4,1,"_CPPv4N8HANumber8setStateEK6int8_tKb","HANumber::setState::force"],[14,4,1,"_CPPv4N8HANumber8setStateEK7int16_tKb","HANumber::setState::force"],[14,4,1,"_CPPv4N8HANumber8setStateEK7int32_tKb","HANumber::setState::force"],[14,4,1,"_CPPv4N8HANumber8setStateEK7uint8_tKb","HANumber::setState::force"],[14,4,1,"_CPPv4N8HANumber8setStateEK8uint16_tKb","HANumber::setState::force"],[14,4,1,"_CPPv4N8HANumber8setStateEK8uint32_tKb","HANumber::setState::force"],[14,4,1,"_CPPv4N8HANumber8setStateEKfKb","HANumber::setState::force"],[14,4,1,"_CPPv4N8HANumber8setStateERK9HANumericKb","HANumber::setState::force"],[14,4,1,"_CPPv4N8HANumber8setStateEK6int8_tKb","HANumber::setState::state"],[14,4,1,"_CPPv4N8HANumber8setStateEK7int16_tKb","HANumber::setState::state"],[14,4,1,"_CPPv4N8HANumber8setStateEK7int32_tKb","HANumber::setState::state"],[14,4,1,"_CPPv4N8HANumber8setStateEK7uint8_tKb","HANumber::setState::state"],[14,4,1,"_CPPv4N8HANumber8setStateEK8uint16_tKb","HANumber::setState::state"],[14,4,1,"_CPPv4N8HANumber8setStateEK8uint32_tKb","HANumber::setState::state"],[14,4,1,"_CPPv4N8HANumber8setStateEKfKb","HANumber::setState::state"],[14,4,1,"_CPPv4N8HANumber8setStateERK9HANumericKb","HANumber::setState::state"],[14,3,1,"_CPPv4N8HANumber7setStepEKf","HANumber::setStep"],[14,4,1,"_CPPv4N8HANumber7setStepEKf","HANumber::setStep::step"],[14,3,1,"_CPPv4N8HANumber20setUnitOfMeasurementEPKc","HANumber::setUnitOfMeasurement"],[14,4,1,"_CPPv4N8HANumber20setUnitOfMeasurementEPKc","HANumber::setUnitOfMeasurement::unitOfMeasurement"],[23,0,1,"_CPPv49HANumeric","HANumeric"],[23,3,1,"_CPPv4N9HANumeric9HANumericEK6int8_tK7uint8_t","HANumeric::HANumeric"],[23,3,1,"_CPPv4N9HANumeric9HANumericEK7int16_tK7uint8_t","HANumeric::HANumeric"],[23,3,1,"_CPPv4N9HANumeric9HANumericEK7int32_tK7uint8_t","HANumeric::HANumeric"],[23,3,1,"_CPPv4N9HANumeric9HANumericEK7int64_t","HANumeric::HANumeric"],[23,3,1,"_CPPv4N9HANumeric9HANumericEK7uint8_tK7uint8_t","HANumeric::HANumeric"],[23,3,1,"_CPPv4N9HANumeric9HANumericEK8uint16_tK7uint8_t","HANumeric::HANumeric"],[23,3,1,"_CPPv4N9HANumeric9HANumericEK8uint32_tK7uint8_t","HANumeric::HANumeric"],[23,3,1,"_CPPv4N9HANumeric9HANumericEKfK7uint8_t","HANumeric::HANumeric"],[23,3,1,"_CPPv4N9HANumeric9HANumericEv","HANumeric::HANumeric"],[23,4,1,"_CPPv4N9HANumeric9HANumericEK6int8_tK7uint8_t","HANumeric::HANumeric::precision"],[23,4,1,"_CPPv4N9HANumeric9HANumericEK7int16_tK7uint8_t","HANumeric::HANumeric::precision"],[23,4,1,"_CPPv4N9HANumeric9HANumericEK7int32_tK7uint8_t","HANumeric::HANumeric::precision"],[23,4,1,"_CPPv4N9HANumeric9HANumericEK7uint8_tK7uint8_t","HANumeric::HANumeric::precision"],[23,4,1,"_CPPv4N9HANumeric9HANumericEK8uint16_tK7uint8_t","HANumeric::HANumeric::precision"],[23,4,1,"_CPPv4N9HANumeric9HANumericEK8uint32_tK7uint8_t","HANumeric::HANumeric::precision"],[23,4,1,"_CPPv4N9HANumeric9HANumericEKfK7uint8_t","HANumeric::HANumeric::precision"],[23,4,1,"_CPPv4N9HANumeric9HANumericEK6int8_tK7uint8_t","HANumeric::HANumeric::value"],[23,4,1,"_CPPv4N9HANumeric9HANumericEK7int16_tK7uint8_t","HANumeric::HANumeric::value"],[23,4,1,"_CPPv4N9HANumeric9HANumericEK7int32_tK7uint8_t","HANumeric::HANumeric::value"],[23,4,1,"_CPPv4N9HANumeric9HANumericEK7int64_t","HANumeric::HANumeric::value"],[23,4,1,"_CPPv4N9HANumeric9HANumericEK7uint8_tK7uint8_t","HANumeric::HANumeric::value"],[23,4,1,"_CPPv4N9HANumeric9HANumericEK8uint16_tK7uint8_t","HANumeric::HANumeric::value"],[23,4,1,"_CPPv4N9HANumeric9HANumericEK8uint32_tK7uint8_t","HANumeric::HANumeric::value"],[23,4,1,"_CPPv4N9HANumeric9HANumericEKfK7uint8_t","HANumeric::HANumeric::value"],[23,5,1,"_CPPv4N9HANumeric11MaxDigitsNbE","HANumeric::MaxDigitsNb"],[23,5,1,"_CPPv4N9HANumeric6_isSetE","HANumeric::_isSet"],[23,5,1,"_CPPv4N9HANumeric10_precisionE","HANumeric::_precision"],[23,5,1,"_CPPv4N9HANumeric6_valueE","HANumeric::_value"],[23,3,1,"_CPPv4NK9HANumeric13calculateSizeEv","HANumeric::calculateSize"],[23,3,1,"_CPPv4N9HANumeric7fromStrEPK7uint8_tK8uint16_t","HANumeric::fromStr"],[23,4,1,"_CPPv4N9HANumeric7fromStrEPK7uint8_tK8uint16_t","HANumeric::fromStr::buffer"],[23,4,1,"_CPPv4N9HANumeric7fromStrEPK7uint8_tK8uint16_t","HANumeric::fromStr::length"],[23,3,1,"_CPPv4NK9HANumeric12getBaseValueEv","HANumeric::getBaseValue"],[23,3,1,"_CPPv4NK9HANumeric12getPrecisionEv","HANumeric::getPrecision"],[23,3,1,"_CPPv4NK9HANumeric16getPrecisionBaseEv","HANumeric::getPrecisionBase"],[23,3,1,"_CPPv4NK9HANumeric7isFloatEv","HANumeric::isFloat"],[23,3,1,"_CPPv4NK9HANumeric7isInt16Ev","HANumeric::isInt16"],[23,3,1,"_CPPv4NK9HANumeric7isInt32Ev","HANumeric::isInt32"],[23,3,1,"_CPPv4NK9HANumeric6isInt8Ev","HANumeric::isInt8"],[23,3,1,"_CPPv4NK9HANumeric5isSetEv","HANumeric::isSet"],[23,3,1,"_CPPv4NK9HANumeric8isUInt16Ev","HANumeric::isUInt16"],[23,3,1,"_CPPv4NK9HANumeric8isUInt32Ev","HANumeric::isUInt32"],[23,3,1,"_CPPv4NK9HANumeric7isUInt8Ev","HANumeric::isUInt8"],[23,3,1,"_CPPv4N9HANumericaSERK9HANumeric","HANumeric::operator="],[23,4,1,"_CPPv4N9HANumericaSERK9HANumeric","HANumeric::operator=::a"],[23,3,1,"_CPPv4NK9HANumericeqERK9HANumeric","HANumeric::operator=="],[23,4,1,"_CPPv4NK9HANumericeqERK9HANumeric","HANumeric::operator==::a"],[23,3,1,"_CPPv4N9HANumeric5resetEv","HANumeric::reset"],[23,3,1,"_CPPv4N9HANumeric12setBaseValueE7int64_t","HANumeric::setBaseValue"],[23,4,1,"_CPPv4N9HANumeric12setBaseValueE7int64_t","HANumeric::setBaseValue::value"],[23,3,1,"_CPPv4N9HANumeric12setPrecisionEK7uint8_t","HANumeric::setPrecision"],[23,4,1,"_CPPv4N9HANumeric12setPrecisionEK7uint8_t","HANumeric::setPrecision::precision"],[23,3,1,"_CPPv4NK9HANumeric7toFloatEv","HANumeric::toFloat"],[23,3,1,"_CPPv4NK9HANumeric7toInt16Ev","HANumeric::toInt16"],[23,3,1,"_CPPv4NK9HANumeric7toInt32Ev","HANumeric::toInt32"],[23,3,1,"_CPPv4NK9HANumeric6toInt8Ev","HANumeric::toInt8"],[23,3,1,"_CPPv4NK9HANumeric5toStrEPc","HANumeric::toStr"],[23,4,1,"_CPPv4NK9HANumeric5toStrEPc","HANumeric::toStr::dst"],[23,3,1,"_CPPv4NK9HANumeric8toUInt16Ev","HANumeric::toUInt16"],[23,3,1,"_CPPv4NK9HANumeric8toUInt32Ev","HANumeric::toUInt32"],[23,3,1,"_CPPv4NK9HANumeric7toUInt8Ev","HANumeric::toUInt8"],[15,0,1,"_CPPv47HAScene","HAScene"],[15,3,1,"_CPPv4N7HAScene7HASceneEPKc","HAScene::HAScene"],[15,4,1,"_CPPv4N7HAScene7HASceneEPKc","HAScene::HAScene::uniqueId"],[15,5,1,"_CPPv4N7HAScene16_commandCallbackE","HAScene::_commandCallback"],[15,5,1,"_CPPv4N7HAScene5_iconE","HAScene::_icon"],[15,5,1,"_CPPv4N7HAScene7_retainE","HAScene::_retain"],[15,3,1,"_CPPv4N7HAScene15buildSerializerEv","HAScene::buildSerializer"],[15,3,1,"_CPPv4N7HAScene9onCommandEPFvP7HASceneE","HAScene::onCommand"],[15,4,1,"_CPPv4N7HAScene9onCommandEPFvP7HASceneE","HAScene::onCommand::callback"],[15,3,1,"_CPPv4N7HAScene15onMqttConnectedEv","HAScene::onMqttConnected"],[15,3,1,"_CPPv4N7HAScene13onMqttMessageEPKcPK7uint8_tK8uint16_t","HAScene::onMqttMessage"],[15,4,1,"_CPPv4N7HAScene13onMqttMessageEPKcPK7uint8_tK8uint16_t","HAScene::onMqttMessage::length"],[15,4,1,"_CPPv4N7HAScene13onMqttMessageEPKcPK7uint8_tK8uint16_t","HAScene::onMqttMessage::payload"],[15,4,1,"_CPPv4N7HAScene13onMqttMessageEPKcPK7uint8_tK8uint16_t","HAScene::onMqttMessage::topic"],[15,3,1,"_CPPv4N7HAScene7setIconEPKc","HAScene::setIcon"],[15,4,1,"_CPPv4N7HAScene7setIconEPKc","HAScene::setIcon::icon"],[15,3,1,"_CPPv4N7HAScene9setRetainEKb","HAScene::setRetain"],[15,4,1,"_CPPv4N7HAScene9setRetainEKb","HAScene::setRetain::retain"],[16,0,1,"_CPPv48HASelect","HASelect"],[16,3,1,"_CPPv4N8HASelect8HASelectEPKc","HASelect::HASelect"],[16,4,1,"_CPPv4N8HASelect8HASelectEPKc","HASelect::HASelect::uniqueId"],[16,5,1,"_CPPv4N8HASelect16_commandCallbackE","HASelect::_commandCallback"],[16,5,1,"_CPPv4N8HASelect13_currentStateE","HASelect::_currentState"],[16,5,1,"_CPPv4N8HASelect5_iconE","HASelect::_icon"],[16,5,1,"_CPPv4N8HASelect11_optimisticE","HASelect::_optimistic"],[16,5,1,"_CPPv4N8HASelect8_optionsE","HASelect::_options"],[16,5,1,"_CPPv4N8HASelect7_retainE","HASelect::_retain"],[16,3,1,"_CPPv4N8HASelect15buildSerializerEv","HASelect::buildSerializer"],[16,3,1,"_CPPv4NK8HASelect20countOptionsInStringEPKc","HASelect::countOptionsInString"],[16,4,1,"_CPPv4NK8HASelect20countOptionsInStringEPKc","HASelect::countOptionsInString::options"],[16,3,1,"_CPPv4NK8HASelect15getCurrentStateEv","HASelect::getCurrentState"],[16,3,1,"_CPPv4N8HASelect9onCommandEPFv6int8_tP8HASelectE","HASelect::onCommand"],[16,4,1,"_CPPv4N8HASelect9onCommandEPFv6int8_tP8HASelectE","HASelect::onCommand::callback"],[16,3,1,"_CPPv4N8HASelect15onMqttConnectedEv","HASelect::onMqttConnected"],[16,3,1,"_CPPv4N8HASelect13onMqttMessageEPKcPK7uint8_tK8uint16_t","HASelect::onMqttMessage"],[16,4,1,"_CPPv4N8HASelect13onMqttMessageEPKcPK7uint8_tK8uint16_t","HASelect::onMqttMessage::length"],[16,4,1,"_CPPv4N8HASelect13onMqttMessageEPKcPK7uint8_tK8uint16_t","HASelect::onMqttMessage::payload"],[16,4,1,"_CPPv4N8HASelect13onMqttMessageEPKcPK7uint8_tK8uint16_t","HASelect::onMqttMessage::topic"],[16,3,1,"_CPPv4N8HASelect12publishStateEK6int8_t","HASelect::publishState"],[16,4,1,"_CPPv4N8HASelect12publishStateEK6int8_t","HASelect::publishState::state"],[16,3,1,"_CPPv4N8HASelect15setCurrentStateEK6int8_t","HASelect::setCurrentState"],[16,4,1,"_CPPv4N8HASelect15setCurrentStateEK6int8_t","HASelect::setCurrentState::state"],[16,3,1,"_CPPv4N8HASelect7setIconEPKc","HASelect::setIcon"],[16,4,1,"_CPPv4N8HASelect7setIconEPKc","HASelect::setIcon::icon"],[16,3,1,"_CPPv4N8HASelect13setOptimisticEKb","HASelect::setOptimistic"],[16,4,1,"_CPPv4N8HASelect13setOptimisticEKb","HASelect::setOptimistic::optimistic"],[16,3,1,"_CPPv4N8HASelect10setOptionsEPKc","HASelect::setOptions"],[16,4,1,"_CPPv4N8HASelect10setOptionsEPKc","HASelect::setOptions::options"],[16,3,1,"_CPPv4N8HASelect9setRetainEKb","HASelect::setRetain"],[16,4,1,"_CPPv4N8HASelect9setRetainEKb","HASelect::setRetain::retain"],[16,3,1,"_CPPv4N8HASelect8setStateEK6int8_tKb","HASelect::setState"],[16,4,1,"_CPPv4N8HASelect8setStateEK6int8_tKb","HASelect::setState::force"],[16,4,1,"_CPPv4N8HASelect8setStateEK6int8_tKb","HASelect::setState::state"],[16,3,1,"_CPPv4N8HASelectD0Ev","HASelect::~HASelect"],[17,0,1,"_CPPv48HASensor","HASensor"],[17,3,1,"_CPPv4N8HASensor8HASensorEPKc","HASensor::HASensor"],[17,4,1,"_CPPv4N8HASensor8HASensorEPKc","HASensor::HASensor::uniqueId"],[17,5,1,"_CPPv4N8HASensor12_deviceClassE","HASensor::_deviceClass"],[17,5,1,"_CPPv4N8HASensor12_forceUpdateE","HASensor::_forceUpdate"],[17,5,1,"_CPPv4N8HASensor5_iconE","HASensor::_icon"],[17,5,1,"_CPPv4N8HASensor18_unitOfMeasurementE","HASensor::_unitOfMeasurement"],[17,3,1,"_CPPv4N8HASensor15buildSerializerEv","HASensor::buildSerializer"],[17,3,1,"_CPPv4N8HASensor15onMqttConnectedEv","HASensor::onMqttConnected"],[17,3,1,"_CPPv4N8HASensor14setDeviceClassEPKc","HASensor::setDeviceClass"],[17,4,1,"_CPPv4N8HASensor14setDeviceClassEPKc","HASensor::setDeviceClass::deviceClass"],[17,3,1,"_CPPv4N8HASensor14setForceUpdateEb","HASensor::setForceUpdate"],[17,4,1,"_CPPv4N8HASensor14setForceUpdateEb","HASensor::setForceUpdate::forceUpdate"],[17,3,1,"_CPPv4N8HASensor7setIconEPKc","HASensor::setIcon"],[17,4,1,"_CPPv4N8HASensor7setIconEPKc","HASensor::setIcon::icon"],[17,3,1,"_CPPv4N8HASensor20setUnitOfMeasurementEPKc","HASensor::setUnitOfMeasurement"],[17,4,1,"_CPPv4N8HASensor20setUnitOfMeasurementEPKc","HASensor::setUnitOfMeasurement::unitOfMeasurement"],[17,3,1,"_CPPv4N8HASensor8setValueEPKc","HASensor::setValue"],[17,4,1,"_CPPv4N8HASensor8setValueEPKc","HASensor::setValue::value"],[18,0,1,"_CPPv414HASensorNumber","HASensorNumber"],[18,3,1,"_CPPv4N14HASensorNumber14HASensorNumberEPKcK15NumberPrecision","HASensorNumber::HASensorNumber"],[18,4,1,"_CPPv4N14HASensorNumber14HASensorNumberEPKcK15NumberPrecision","HASensorNumber::HASensorNumber::precision"],[18,4,1,"_CPPv4N14HASensorNumber14HASensorNumberEPKcK15NumberPrecision","HASensorNumber::HASensorNumber::uniqueId"],[18,5,1,"_CPPv4N14HASensorNumber13_currentValueE","HASensorNumber::_currentValue"],[18,5,1,"_CPPv4N14HASensorNumber10_precisionE","HASensorNumber::_precision"],[18,3,1,"_CPPv4NK14HASensorNumber15getCurrentValueEv","HASensorNumber::getCurrentValue"],[18,3,1,"_CPPv4N14HASensorNumber15onMqttConnectedEv","HASensorNumber::onMqttConnected"],[18,3,1,"_CPPv4N14HASensorNumber12publishValueERK9HANumeric","HASensorNumber::publishValue"],[18,4,1,"_CPPv4N14HASensorNumber12publishValueERK9HANumeric","HASensorNumber::publishValue::value"],[18,3,1,"_CPPv4N14HASensorNumber15setCurrentValueEK6int8_t","HASensorNumber::setCurrentValue"],[18,3,1,"_CPPv4N14HASensorNumber15setCurrentValueEK7int16_t","HASensorNumber::setCurrentValue"],[18,3,1,"_CPPv4N14HASensorNumber15setCurrentValueEK7int32_t","HASensorNumber::setCurrentValue"],[18,3,1,"_CPPv4N14HASensorNumber15setCurrentValueEK7uint8_t","HASensorNumber::setCurrentValue"],[18,3,1,"_CPPv4N14HASensorNumber15setCurrentValueEK8uint16_t","HASensorNumber::setCurrentValue"],[18,3,1,"_CPPv4N14HASensorNumber15setCurrentValueEK8uint32_t","HASensorNumber::setCurrentValue"],[18,3,1,"_CPPv4N14HASensorNumber15setCurrentValueEKf","HASensorNumber::setCurrentValue"],[18,3,1,"_CPPv4N14HASensorNumber15setCurrentValueERK9HANumeric","HASensorNumber::setCurrentValue"],[18,4,1,"_CPPv4N14HASensorNumber15setCurrentValueEK6int8_t","HASensorNumber::setCurrentValue::value"],[18,4,1,"_CPPv4N14HASensorNumber15setCurrentValueEK7int16_t","HASensorNumber::setCurrentValue::value"],[18,4,1,"_CPPv4N14HASensorNumber15setCurrentValueEK7int32_t","HASensorNumber::setCurrentValue::value"],[18,4,1,"_CPPv4N14HASensorNumber15setCurrentValueEK7uint8_t","HASensorNumber::setCurrentValue::value"],[18,4,1,"_CPPv4N14HASensorNumber15setCurrentValueEK8uint16_t","HASensorNumber::setCurrentValue::value"],[18,4,1,"_CPPv4N14HASensorNumber15setCurrentValueEK8uint32_t","HASensorNumber::setCurrentValue::value"],[18,4,1,"_CPPv4N14HASensorNumber15setCurrentValueEKf","HASensorNumber::setCurrentValue::value"],[18,4,1,"_CPPv4N14HASensorNumber15setCurrentValueERK9HANumeric","HASensorNumber::setCurrentValue::value"],[18,3,1,"_CPPv4N14HASensorNumber8setValueEK6int8_tKb","HASensorNumber::setValue"],[18,3,1,"_CPPv4N14HASensorNumber8setValueEK7int16_tKb","HASensorNumber::setValue"],[18,3,1,"_CPPv4N14HASensorNumber8setValueEK7int32_tKb","HASensorNumber::setValue"],[18,3,1,"_CPPv4N14HASensorNumber8setValueEK7uint8_tKb","HASensorNumber::setValue"],[18,3,1,"_CPPv4N14HASensorNumber8setValueEK8uint16_tKb","HASensorNumber::setValue"],[18,3,1,"_CPPv4N14HASensorNumber8setValueEK8uint32_tKb","HASensorNumber::setValue"],[18,3,1,"_CPPv4N14HASensorNumber8setValueEKfKb","HASensorNumber::setValue"],[18,3,1,"_CPPv4N14HASensorNumber8setValueERK9HANumericKb","HASensorNumber::setValue"],[18,4,1,"_CPPv4N14HASensorNumber8setValueEK6int8_tKb","HASensorNumber::setValue::force"],[18,4,1,"_CPPv4N14HASensorNumber8setValueEK7int16_tKb","HASensorNumber::setValue::force"],[18,4,1,"_CPPv4N14HASensorNumber8setValueEK7int32_tKb","HASensorNumber::setValue::force"],[18,4,1,"_CPPv4N14HASensorNumber8setValueEK7uint8_tKb","HASensorNumber::setValue::force"],[18,4,1,"_CPPv4N14HASensorNumber8setValueEK8uint16_tKb","HASensorNumber::setValue::force"],[18,4,1,"_CPPv4N14HASensorNumber8setValueEK8uint32_tKb","HASensorNumber::setValue::force"],[18,4,1,"_CPPv4N14HASensorNumber8setValueEKfKb","HASensorNumber::setValue::force"],[18,4,1,"_CPPv4N14HASensorNumber8setValueERK9HANumericKb","HASensorNumber::setValue::force"],[18,4,1,"_CPPv4N14HASensorNumber8setValueEK6int8_tKb","HASensorNumber::setValue::value"],[18,4,1,"_CPPv4N14HASensorNumber8setValueEK7int16_tKb","HASensorNumber::setValue::value"],[18,4,1,"_CPPv4N14HASensorNumber8setValueEK7int32_tKb","HASensorNumber::setValue::value"],[18,4,1,"_CPPv4N14HASensorNumber8setValueEK7uint8_tKb","HASensorNumber::setValue::value"],[18,4,1,"_CPPv4N14HASensorNumber8setValueEK8uint16_tKb","HASensorNumber::setValue::value"],[18,4,1,"_CPPv4N14HASensorNumber8setValueEK8uint32_tKb","HASensorNumber::setValue::value"],[18,4,1,"_CPPv4N14HASensorNumber8setValueEKfKb","HASensorNumber::setValue::value"],[18,4,1,"_CPPv4N14HASensorNumber8setValueERK9HANumericKb","HASensorNumber::setValue::value"],[24,0,1,"_CPPv412HASerializer","HASerializer"],[24,2,1,"_CPPv4N12HASerializer17PropertyValueType17ArrayPropertyTypeE","HASerializer::ArrayPropertyType"],[24,2,1,"_CPPv4N12HASerializer17PropertyValueType16BoolPropertyTypeE","HASerializer::BoolPropertyType"],[24,2,1,"_CPPv4N12HASerializer17PropertyValueType22ConstCharPropertyValueE","HASerializer::ConstCharPropertyValue"],[24,1,1,"_CPPv4N12HASerializer9EntryTypeE","HASerializer::EntryType"],[24,2,1,"_CPPv4N12HASerializer9EntryType13FlagEntryTypeE","HASerializer::EntryType::FlagEntryType"],[24,2,1,"_CPPv4N12HASerializer9EntryType17PropertyEntryTypeE","HASerializer::EntryType::PropertyEntryType"],[24,2,1,"_CPPv4N12HASerializer9EntryType14TopicEntryTypeE","HASerializer::EntryType::TopicEntryType"],[24,2,1,"_CPPv4N12HASerializer9EntryType16UnknownEntryTypeE","HASerializer::EntryType::UnknownEntryType"],[24,2,1,"_CPPv4N12HASerializer9EntryType13FlagEntryTypeE","HASerializer::FlagEntryType"],[24,1,1,"_CPPv4N12HASerializer8FlagTypeE","HASerializer::FlagType"],[24,2,1,"_CPPv4N12HASerializer8FlagType16WithAvailabilityE","HASerializer::FlagType::WithAvailability"],[24,2,1,"_CPPv4N12HASerializer8FlagType10WithDeviceE","HASerializer::FlagType::WithDevice"],[24,3,1,"_CPPv4N12HASerializer12HASerializerEP16HABaseDeviceTypeK7uint8_t","HASerializer::HASerializer"],[24,4,1,"_CPPv4N12HASerializer12HASerializerEP16HABaseDeviceTypeK7uint8_t","HASerializer::HASerializer::deviceType"],[24,4,1,"_CPPv4N12HASerializer12HASerializerEP16HABaseDeviceTypeK7uint8_t","HASerializer::HASerializer::maxEntriesNb"],[24,2,1,"_CPPv4N12HASerializer17PropertyValueType18NumberPropertyTypeE","HASerializer::NumberPropertyType"],[24,2,1,"_CPPv4N12HASerializer17PropertyValueType20ProgmemPropertyValueE","HASerializer::ProgmemPropertyValue"],[24,2,1,"_CPPv4N12HASerializer9EntryType17PropertyEntryTypeE","HASerializer::PropertyEntryType"],[24,1,1,"_CPPv4N12HASerializer17PropertyValueTypeE","HASerializer::PropertyValueType"],[24,2,1,"_CPPv4N12HASerializer17PropertyValueType17ArrayPropertyTypeE","HASerializer::PropertyValueType::ArrayPropertyType"],[24,2,1,"_CPPv4N12HASerializer17PropertyValueType16BoolPropertyTypeE","HASerializer::PropertyValueType::BoolPropertyType"],[24,2,1,"_CPPv4N12HASerializer17PropertyValueType22ConstCharPropertyValueE","HASerializer::PropertyValueType::ConstCharPropertyValue"],[24,2,1,"_CPPv4N12HASerializer17PropertyValueType18NumberPropertyTypeE","HASerializer::PropertyValueType::NumberPropertyType"],[24,2,1,"_CPPv4N12HASerializer17PropertyValueType20ProgmemPropertyValueE","HASerializer::PropertyValueType::ProgmemPropertyValue"],[24,2,1,"_CPPv4N12HASerializer17PropertyValueType24UnknownPropertyValueTypeE","HASerializer::PropertyValueType::UnknownPropertyValueType"],[24,0,1,"_CPPv4N12HASerializer15SerializerEntryE","HASerializer::SerializerEntry"],[24,3,1,"_CPPv4N12HASerializer15SerializerEntry15SerializerEntryEv","HASerializer::SerializerEntry::SerializerEntry"],[24,5,1,"_CPPv4N12HASerializer15SerializerEntry8propertyE","HASerializer::SerializerEntry::property"],[24,5,1,"_CPPv4N12HASerializer15SerializerEntry7subtypeE","HASerializer::SerializerEntry::subtype"],[24,5,1,"_CPPv4N12HASerializer15SerializerEntry4typeE","HASerializer::SerializerEntry::type"],[24,5,1,"_CPPv4N12HASerializer15SerializerEntry5valueE","HASerializer::SerializerEntry::value"],[24,2,1,"_CPPv4N12HASerializer9EntryType14TopicEntryTypeE","HASerializer::TopicEntryType"],[24,2,1,"_CPPv4N12HASerializer9EntryType16UnknownEntryTypeE","HASerializer::UnknownEntryType"],[24,2,1,"_CPPv4N12HASerializer17PropertyValueType24UnknownPropertyValueTypeE","HASerializer::UnknownPropertyValueType"],[24,2,1,"_CPPv4N12HASerializer8FlagType16WithAvailabilityE","HASerializer::WithAvailability"],[24,2,1,"_CPPv4N12HASerializer8FlagType10WithDeviceE","HASerializer::WithDevice"],[24,5,1,"_CPPv4N12HASerializer11_deviceTypeE","HASerializer::_deviceType"],[24,5,1,"_CPPv4N12HASerializer8_entriesE","HASerializer::_entries"],[24,5,1,"_CPPv4N12HASerializer10_entriesNbE","HASerializer::_entriesNb"],[24,5,1,"_CPPv4N12HASerializer13_maxEntriesNbE","HASerializer::_maxEntriesNb"],[24,3,1,"_CPPv4N12HASerializer8addEntryEv","HASerializer::addEntry"],[24,3,1,"_CPPv4NK12HASerializer18calculateArraySizeEPK17HASerializerArray","HASerializer::calculateArraySize"],[24,4,1,"_CPPv4NK12HASerializer18calculateArraySizeEPK17HASerializerArray","HASerializer::calculateArraySize::array"],[24,3,1,"_CPPv4N12HASerializer26calculateConfigTopicLengthEPK19__FlashStringHelperPKc","HASerializer::calculateConfigTopicLength"],[24,4,1,"_CPPv4N12HASerializer26calculateConfigTopicLengthEPK19__FlashStringHelperPKc","HASerializer::calculateConfigTopicLength::component"],[24,4,1,"_CPPv4N12HASerializer26calculateConfigTopicLengthEPK19__FlashStringHelperPKc","HASerializer::calculateConfigTopicLength::objectId"],[24,3,1,"_CPPv4N12HASerializer24calculateDataTopicLengthEPKcPK19__FlashStringHelper","HASerializer::calculateDataTopicLength"],[24,4,1,"_CPPv4N12HASerializer24calculateDataTopicLengthEPKcPK19__FlashStringHelper","HASerializer::calculateDataTopicLength::objectId"],[24,4,1,"_CPPv4N12HASerializer24calculateDataTopicLengthEPKcPK19__FlashStringHelper","HASerializer::calculateDataTopicLength::topic"],[24,3,1,"_CPPv4NK12HASerializer18calculateEntrySizeEPK15SerializerEntry","HASerializer::calculateEntrySize"],[24,4,1,"_CPPv4NK12HASerializer18calculateEntrySizeEPK15SerializerEntry","HASerializer::calculateEntrySize::entry"],[24,3,1,"_CPPv4NK12HASerializer17calculateFlagSizeEK8FlagType","HASerializer::calculateFlagSize"],[24,4,1,"_CPPv4NK12HASerializer17calculateFlagSizeEK8FlagType","HASerializer::calculateFlagSize::flag"],[24,3,1,"_CPPv4NK12HASerializer26calculatePropertyValueSizeEPK15SerializerEntry","HASerializer::calculatePropertyValueSize"],[24,4,1,"_CPPv4NK12HASerializer26calculatePropertyValueSizeEPK15SerializerEntry","HASerializer::calculatePropertyValueSize::entry"],[24,3,1,"_CPPv4NK12HASerializer13calculateSizeEv","HASerializer::calculateSize"],[24,3,1,"_CPPv4NK12HASerializer23calculateTopicEntrySizeEPK15SerializerEntry","HASerializer::calculateTopicEntrySize"],[24,4,1,"_CPPv4NK12HASerializer23calculateTopicEntrySizeEPK15SerializerEntry","HASerializer::calculateTopicEntrySize::entry"],[24,3,1,"_CPPv4N12HASerializer17compareDataTopicsEPKcPKcPK19__FlashStringHelper","HASerializer::compareDataTopics"],[24,4,1,"_CPPv4N12HASerializer17compareDataTopicsEPKcPKcPK19__FlashStringHelper","HASerializer::compareDataTopics::actualTopic"],[24,4,1,"_CPPv4N12HASerializer17compareDataTopicsEPKcPKcPK19__FlashStringHelper","HASerializer::compareDataTopics::objectId"],[24,4,1,"_CPPv4N12HASerializer17compareDataTopicsEPKcPKcPK19__FlashStringHelper","HASerializer::compareDataTopics::topic"],[24,3,1,"_CPPv4NK12HASerializer5flushEv","HASerializer::flush"],[24,3,1,"_CPPv4NK12HASerializer10flushEntryEPK15SerializerEntry","HASerializer::flushEntry"],[24,4,1,"_CPPv4NK12HASerializer10flushEntryEPK15SerializerEntry","HASerializer::flushEntry::entry"],[24,3,1,"_CPPv4NK12HASerializer15flushEntryValueEPK15SerializerEntry","HASerializer::flushEntryValue"],[24,4,1,"_CPPv4NK12HASerializer15flushEntryValueEPK15SerializerEntry","HASerializer::flushEntryValue::entry"],[24,3,1,"_CPPv4NK12HASerializer9flushFlagEPK15SerializerEntry","HASerializer::flushFlag"],[24,4,1,"_CPPv4NK12HASerializer9flushFlagEPK15SerializerEntry","HASerializer::flushFlag::entry"],[24,3,1,"_CPPv4NK12HASerializer10flushTopicEPK15SerializerEntry","HASerializer::flushTopic"],[24,4,1,"_CPPv4NK12HASerializer10flushTopicEPK15SerializerEntry","HASerializer::flushTopic::entry"],[24,3,1,"_CPPv4N12HASerializer19generateConfigTopicEPcPK19__FlashStringHelperPKc","HASerializer::generateConfigTopic"],[24,4,1,"_CPPv4N12HASerializer19generateConfigTopicEPcPK19__FlashStringHelperPKc","HASerializer::generateConfigTopic::component"],[24,4,1,"_CPPv4N12HASerializer19generateConfigTopicEPcPK19__FlashStringHelperPKc","HASerializer::generateConfigTopic::objectId"],[24,4,1,"_CPPv4N12HASerializer19generateConfigTopicEPcPK19__FlashStringHelperPKc","HASerializer::generateConfigTopic::output"],[24,3,1,"_CPPv4N12HASerializer17generateDataTopicEPcPKcPK19__FlashStringHelper","HASerializer::generateDataTopic"],[24,4,1,"_CPPv4N12HASerializer17generateDataTopicEPcPKcPK19__FlashStringHelper","HASerializer::generateDataTopic::objectId"],[24,4,1,"_CPPv4N12HASerializer17generateDataTopicEPcPKcPK19__FlashStringHelper","HASerializer::generateDataTopic::output"],[24,4,1,"_CPPv4N12HASerializer17generateDataTopicEPcPKcPK19__FlashStringHelper","HASerializer::generateDataTopic::topic"],[24,3,1,"_CPPv4NK12HASerializer10getEntriesEv","HASerializer::getEntries"],[24,3,1,"_CPPv4NK12HASerializer12getEntriesNbEv","HASerializer::getEntriesNb"],[24,3,1,"_CPPv4N12HASerializer3setEK8FlagType","HASerializer::set"],[24,3,1,"_CPPv4N12HASerializer3setEPK19__FlashStringHelperPKv17PropertyValueType","HASerializer::set"],[24,4,1,"_CPPv4N12HASerializer3setEK8FlagType","HASerializer::set::flag"],[24,4,1,"_CPPv4N12HASerializer3setEPK19__FlashStringHelperPKv17PropertyValueType","HASerializer::set::property"],[24,4,1,"_CPPv4N12HASerializer3setEPK19__FlashStringHelperPKv17PropertyValueType","HASerializer::set::value"],[24,4,1,"_CPPv4N12HASerializer3setEPK19__FlashStringHelperPKv17PropertyValueType","HASerializer::set::valueType"],[24,3,1,"_CPPv4N12HASerializer5topicEPK19__FlashStringHelper","HASerializer::topic"],[24,4,1,"_CPPv4N12HASerializer5topicEPK19__FlashStringHelper","HASerializer::topic::topic"],[24,3,1,"_CPPv4N12HASerializerD0Ev","HASerializer::~HASerializer"],[25,0,1,"_CPPv417HASerializerArray","HASerializerArray"],[25,3,1,"_CPPv4N17HASerializerArray17HASerializerArrayEK7uint8_tKb","HASerializerArray::HASerializerArray"],[25,4,1,"_CPPv4N17HASerializerArray17HASerializerArrayEK7uint8_tKb","HASerializerArray::HASerializerArray::progmemItems"],[25,4,1,"_CPPv4N17HASerializerArray17HASerializerArrayEK7uint8_tKb","HASerializerArray::HASerializerArray::size"],[25,6,1,"_CPPv4N17HASerializerArray8ItemTypeE","HASerializerArray::ItemType"],[25,5,1,"_CPPv4N17HASerializerArray6_itemsE","HASerializerArray::_items"],[25,5,1,"_CPPv4N17HASerializerArray8_itemsNbE","HASerializerArray::_itemsNb"],[25,5,1,"_CPPv4N17HASerializerArray13_progmemItemsE","HASerializerArray::_progmemItems"],[25,5,1,"_CPPv4N17HASerializerArray5_sizeE","HASerializerArray::_size"],[25,3,1,"_CPPv4N17HASerializerArray3addE8ItemType","HASerializerArray::add"],[25,4,1,"_CPPv4N17HASerializerArray3addE8ItemType","HASerializerArray::add::item"],[25,3,1,"_CPPv4NK17HASerializerArray13calculateSizeEv","HASerializerArray::calculateSize"],[25,3,1,"_CPPv4N17HASerializerArray5clearEv","HASerializerArray::clear"],[25,3,1,"_CPPv4NK17HASerializerArray8getItemsEv","HASerializerArray::getItems"],[25,3,1,"_CPPv4NK17HASerializerArray10getItemsNbEv","HASerializerArray::getItemsNb"],[25,3,1,"_CPPv4NK17HASerializerArray9serializeEPc","HASerializerArray::serialize"],[25,4,1,"_CPPv4NK17HASerializerArray9serializeEPc","HASerializerArray::serialize::output"],[25,3,1,"_CPPv4N17HASerializerArrayD0Ev","HASerializerArray::~HASerializerArray"],[19,0,1,"_CPPv48HASwitch","HASwitch"],[19,3,1,"_CPPv4N8HASwitch8HASwitchEPKc","HASwitch::HASwitch"],[19,4,1,"_CPPv4N8HASwitch8HASwitchEPKc","HASwitch::HASwitch::uniqueId"],[19,5,1,"_CPPv4N8HASwitch6_classE","HASwitch::_class"],[19,5,1,"_CPPv4N8HASwitch16_commandCallbackE","HASwitch::_commandCallback"],[19,5,1,"_CPPv4N8HASwitch13_currentStateE","HASwitch::_currentState"],[19,5,1,"_CPPv4N8HASwitch5_iconE","HASwitch::_icon"],[19,5,1,"_CPPv4N8HASwitch11_optimisticE","HASwitch::_optimistic"],[19,5,1,"_CPPv4N8HASwitch7_retainE","HASwitch::_retain"],[19,3,1,"_CPPv4N8HASwitch15buildSerializerEv","HASwitch::buildSerializer"],[19,3,1,"_CPPv4NK8HASwitch15getCurrentStateEv","HASwitch::getCurrentState"],[19,3,1,"_CPPv4N8HASwitch9onCommandEPFvbP8HASwitchE","HASwitch::onCommand"],[19,4,1,"_CPPv4N8HASwitch9onCommandEPFvbP8HASwitchE","HASwitch::onCommand::callback"],[19,3,1,"_CPPv4N8HASwitch15onMqttConnectedEv","HASwitch::onMqttConnected"],[19,3,1,"_CPPv4N8HASwitch13onMqttMessageEPKcPK7uint8_tK8uint16_t","HASwitch::onMqttMessage"],[19,4,1,"_CPPv4N8HASwitch13onMqttMessageEPKcPK7uint8_tK8uint16_t","HASwitch::onMqttMessage::length"],[19,4,1,"_CPPv4N8HASwitch13onMqttMessageEPKcPK7uint8_tK8uint16_t","HASwitch::onMqttMessage::payload"],[19,4,1,"_CPPv4N8HASwitch13onMqttMessageEPKcPK7uint8_tK8uint16_t","HASwitch::onMqttMessage::topic"],[19,3,1,"_CPPv4N8HASwitch12publishStateEKb","HASwitch::publishState"],[19,4,1,"_CPPv4N8HASwitch12publishStateEKb","HASwitch::publishState::state"],[19,3,1,"_CPPv4N8HASwitch15setCurrentStateEKb","HASwitch::setCurrentState"],[19,4,1,"_CPPv4N8HASwitch15setCurrentStateEKb","HASwitch::setCurrentState::state"],[19,3,1,"_CPPv4N8HASwitch14setDeviceClassEPKc","HASwitch::setDeviceClass"],[19,4,1,"_CPPv4N8HASwitch14setDeviceClassEPKc","HASwitch::setDeviceClass::deviceClass"],[19,3,1,"_CPPv4N8HASwitch7setIconEPKc","HASwitch::setIcon"],[19,4,1,"_CPPv4N8HASwitch7setIconEPKc","HASwitch::setIcon::icon"],[19,3,1,"_CPPv4N8HASwitch13setOptimisticEKb","HASwitch::setOptimistic"],[19,4,1,"_CPPv4N8HASwitch13setOptimisticEKb","HASwitch::setOptimistic::optimistic"],[19,3,1,"_CPPv4N8HASwitch9setRetainEKb","HASwitch::setRetain"],[19,4,1,"_CPPv4N8HASwitch9setRetainEKb","HASwitch::setRetain::retain"],[19,3,1,"_CPPv4N8HASwitch8setStateEKbKb","HASwitch::setState"],[19,4,1,"_CPPv4N8HASwitch8setStateEKbKb","HASwitch::setState::force"],[19,4,1,"_CPPv4N8HASwitch8setStateEKbKb","HASwitch::setState::state"],[19,3,1,"_CPPv4N8HASwitch7turnOffEv","HASwitch::turnOff"],[19,3,1,"_CPPv4N8HASwitch6turnOnEv","HASwitch::turnOn"],[20,0,1,"_CPPv412HATagScanner","HATagScanner"],[20,3,1,"_CPPv4N12HATagScanner12HATagScannerEPKc","HATagScanner::HATagScanner"],[20,4,1,"_CPPv4N12HATagScanner12HATagScannerEPKc","HATagScanner::HATagScanner::uniqueId"],[20,3,1,"_CPPv4N12HATagScanner15buildSerializerEv","HATagScanner::buildSerializer"],[20,3,1,"_CPPv4N12HATagScanner15onMqttConnectedEv","HATagScanner::onMqttConnected"],[20,3,1,"_CPPv4N12HATagScanner10tagScannedEPKc","HATagScanner::tagScanned"],[20,4,1,"_CPPv4N12HATagScanner10tagScannedEPKc","HATagScanner::tagScanned::tag"],[26,0,1,"_CPPv47HAUtils","HAUtils"],[26,3,1,"_CPPv4N7HAUtils14byteArrayToStrEPK4byteK8uint16_t","HAUtils::byteArrayToStr"],[26,3,1,"_CPPv4N7HAUtils14byteArrayToStrEPcPK4byteK8uint16_t","HAUtils::byteArrayToStr"],[26,4,1,"_CPPv4N7HAUtils14byteArrayToStrEPcPK4byteK8uint16_t","HAUtils::byteArrayToStr::dst"],[26,4,1,"_CPPv4N7HAUtils14byteArrayToStrEPK4byteK8uint16_t","HAUtils::byteArrayToStr::length"],[26,4,1,"_CPPv4N7HAUtils14byteArrayToStrEPcPK4byteK8uint16_t","HAUtils::byteArrayToStr::length"],[26,4,1,"_CPPv4N7HAUtils14byteArrayToStrEPK4byteK8uint16_t","HAUtils::byteArrayToStr::src"],[26,4,1,"_CPPv4N7HAUtils14byteArrayToStrEPcPK4byteK8uint16_t","HAUtils::byteArrayToStr::src"],[26,3,1,"_CPPv4N7HAUtils8endsWithEPKcPKc","HAUtils::endsWith"],[26,4,1,"_CPPv4N7HAUtils8endsWithEPKcPKc","HAUtils::endsWith::str"],[26,4,1,"_CPPv4N7HAUtils8endsWithEPKcPKc","HAUtils::endsWith::suffix"]]},objnames:{"0":["cpp","class","C++ class"],"1":["cpp","enum","C++ enum"],"2":["cpp","enumerator","C++ enumerator"],"3":["cpp","function","C++ function"],"4":["cpp","functionParam","C++ function parameter"],"5":["cpp","member","C++ member"],"6":["cpp","type","C++ type"]},objtypes:{"0":"cpp:class","1":"cpp:enum","2":"cpp:enumerator","3":"cpp:function","4":"cpp:functionParam","5":"cpp:member","6":"cpp:type"},terms:{"0":[3,7,10,12,14,31,36,41],"001":14,"01":[28,37],"0x00":[33,35,36,37,38,40,41,42],"0x05":36,"0x10":[33,35,36,37,38,40,41,42],"0x1f":36,"0x38":[33,35,36,37,38,40,41,42],"0x4a":[33,35,36,37,38,40,41,42],"0x6e":[33,35,36,37,38,40,41,42],"0x8c":36,"0x9f":36,"0xb4":36,"0xbe":36,"0xc6":36,"0xc7":36,"0xce":36,"0xfa":[33,35,36,37,38,40,41,42],"1":[10,11,16,23,31,35,40,41,42],"10":23,"100":[7,10,42],"12":37,"123":[23,36],"1234":23,"153":12,"168":[35,40,41,42],"1883":[1,35],"192":[35,40,41,42],"2":[26,31,33],"255":12,"32768":7,"33":[28,29],"4":23,"5":33,"50":[35,40,41,42],"500":[12,40],"5000":1,"5m":1,"6":[1,31,37],"8":31,"8888":35,"byte":[0,1,23,26,33,35,37,38,40,41,42],"case":[1,33,38],"char":[0,1,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,23,24,25,26,38,41],"class":[2,21,22,27,28,34,35,36,37,38,40,41,43],"const":[0,1,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,23,24,25,26,38,41],"default":[1,4,6,7,8,10,11,12,13,14,16,18,19,23,32,33,35,37,38,42],"do":1,"enum":[3,6,7,8,9,10,11,12,13,14,24],"final":[0,17],"float":[11,14,18,23],"function":[0,1,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,23,24,25,26],"long":[28,33,42],"new":[1,3,4,7,8,10,11,12,13,14,15,16,18,19,24,25,26,30,37],"null":[0,1,23],"public":[0,1,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,23,24,25,26],"return":[0,1,3,4,6,7,8,9,10,11,12,13,14,16,17,18,19,20,23,24,25,26],"short":[0,3,36],"static":[1,3,7,11,12,23,24,25,26],"switch":[1,9,19,28,29,33,36,37,38],"true":[0,1,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,23,25,26,33,41],"try":[1,28,36],"void":[0,1,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,23,24,25,26,33,35,36,37,38,40,41,42],"while":40,A:[16,29],By:[4,6,7,8,10,11,12,13,14,16,18,19,33,37,42],For:[9,14,16,17,23,31,33],If:[0,1,5,7,8,9,10,11,12,13,14,15,16,17,19,23,24,30,31],In:[1,7,10,12,13,14,16,19,33,36,38],It:[0,1,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,24,25,28,34,37,40],Its:24,No:3,OR:12,On:[37,42],One:3,THe:[3,18],That:[33,38],The:[0,1,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,23,24,25,28,29,31,32,33,34,35,36,38,41,42,43],Then:31,There:[31,33,36,38],To:[31,34],Will:[29,43],_:24,__flashstringhelp:[1,3,6,8,11,14,24],_action:11,_auxcallback:11,_auxstat:11,_avail:[0,3],_availabilitytop:0,_brightnesscallback:12,_brightnessscal:12,_class:[4,5,7,14,19],_colortemperaturecallback:12,_commandcallback:[5,7,13,14,15,16,19],_componentnam:3,_connectedcallback:1,_currentbright:12,_currentcolortemperatur:12,_currentposit:7,_currentrgbcolor:12,_currentspe:10,_currentst:[4,7,8,10,12,13,14,16,19],_currenttemperatur:11,_currentvalu:18,_dataprefix:1,_devic:1,_deviceclass:17,_devicestyp:1,_devicestypesnb:1,_devicetyp:24,_discoveryprefix:1,_encod:6,_entri:24,_entriesnb:24,_fanmod:11,_fanmodecallback:11,_fanmodesseri:11,_featur:[7,10,11,12],_forceupd:17,_icon:[4,5,6,7,8,10,11,12,13,14,15,16,17,19],_initi:1,_instanc:1,_isprogmemsubtyp:9,_isprogmemtyp:9,_isset:23,_item:25,_itemsnb:25,_lastconnectionattemptat:1,_lastwillmessag:1,_lastwillretain:1,_lastwilltop:1,_maxdevicestypesnb:1,_maxentriesnb:24,_maxmir:12,_maxtemp:11,_maxvalu:14,_messagecallback:1,_minmir:12,_mintemp:11,_minvalu:14,_mode:[11,14],_modecallback:11,_modesseri:11,_mqtt:1,_name:3,_optimist:[7,10,12,13,14,16,19],_option:16,_ownsuniqueid:0,_password:1,_powercallback:11,_precis:[11,14,18,23],_progmemitem:25,_retain:[5,7,10,11,12,13,14,15,16,19],_rgbcolorcallback:12,_serial:[0,3],_sharedavail:0,_size:25,_sourcetyp:8,_speedcallback:10,_speedrangemax:10,_speedrangemin:10,_statecallback:[10,12],_step:14,_subtyp:9,_swingmod:11,_swingmodecallback:11,_swingmodesseri:11,_targettemperatur:11,_targettemperaturecallback:11,_temperatureunit:11,_tempstep:11,_type:9,_uniqueid:[0,3],_unitofmeasur:[14,17],_usernam:1,_valu:23,abc:36,about:[4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20],abov:[11,14,18],accept:[11,14,18,36],access:42,acquir:[0,1,3,4,7,8,10,11,12,13,14,16,18,19,38,42],across:23,act:32,action:[9,11],actionfeatur:11,activ:15,actual:24,actualtop:24,ad:[10,12,23,24,25,29,43],add:[1,14,15,16,24,25,31,40],adddevicetyp:1,addentri:24,addon:32,address:[1,36],admin:1,advanc:[29,31,39,43],after:[1,3,32,38,40],against:42,aha:[1,38],alia:[10,12,19],all:[0,1,3,30,32,33,35,36,38,39],alloc:[0,9,11,24,25,26],allow:[4,6,7,8,9,10,12,13,17,18,19,20,24,29,33,35,39,41,42,43],alphanumer:36,alreadi:40,also:[1,3,33,35,36,41,42],alwai:[1,3],amount:[1,16],an:[0,1,6,11,14,18,23,29,31,32,36,41,43],analog:29,analyz:42,ani:[0,1,3,4,5,6,7,8,10,11,12,13,14,15,16,17,19,28,36],anonym:1,anoth:40,anoym:35,anyth:[30,37],api:[1,28,36,43],appli:14,applic:40,approach:[24,31],ar:[1,16,25,31,34,36,38,40],arduino:[5,28,29,30,37,39,42,43],arduinoha:[30,32,33,35,36,37,38,40,41,42],arduinoha_debug:34,arduinohadefin:34,argument:[11,14,18],arrai:[0,1,11,16,24,25,26],arraypropertytyp:24,assign:[0,1,3,9,37],assist:[0,1,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,29,31,32,33,34,36,37,38,42,43],asynchron:35,attemp:1,attempt:[1,35],attribut:[1,3,7,11,12,23],aunit:43,authent:1,auto:43,autofanmod:11,autom:[9,20],automat:[1,33,38,43],automod:11,aux:11,auxheatingfeatur:11,avail:[0,1,3,4,5,7,8,11,13,14,16,17,19,24,28,29,31,39,43],availabilitydefault:3,availabilityofflin:3,availabilityonlin:3,b:[12,16],back:[7,10,11,12,13,14,16,19],base64:6,base:[0,9,20,23,25,43],basic:[28,29,33,38,39,40],becaus:[33,38,42],becom:33,bedroom:36,been:[4,6,7,8,9,10,11,12,13,14,16,17,18,19,20,25],befor:[1,4,7,8,10,11,12,13,14,16,18,19,24,40],begin:[1,33,35,37,40,41,42],beginpublish:1,being:24,belong:3,below:[24,33,34,35,37,41],best:31,better:3,between:[1,42],binari:[4,6,29,37],binary_sensor:[3,4,24],bind:41,bitwis:12,blind:7,blue:12,bluetooth:8,board:[37,43],boilerpl:[39,43],bool:[0,1,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,23,24,25,26,33],boolpropertytyp:24,boot:1,box:14,bridg:1,bright:[12,29],brightnessfeatur:12,broker:[0,1,4,7,8,10,11,12,13,14,16,18,19,24,29,32,33,35,38,40,41,42,43],brokker:32,btn0:9,bu:6,buffer:[23,24],build:[3,9,31],buildseri:[3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,19,20],builduniqueid:9,built:[3,9],busi:40,button1subtyp:9,button2subtyp:9,button3subtyp:9,button4subtyp:9,button5subtyp:9,button6subtyp:9,button:[4,5,7,10,11,12,16,19,29,33,37],buttondoublepresstyp:9,buttonlongpresstyp:9,buttonlongreleasetyp:9,buttonquadruplepresstyp:9,buttonquintuplepresstyp:9,buttonshortpresstyp:9,buttonshortreleasetyp:9,buttontriplepresstyp:9,bytearraytostr:26,c:[14,16,17],calcul:[9,23,24,25],calculatearrays:24,calculateconfigtopiclength:24,calculatedatatopiclength:24,calculateentrys:24,calculateflags:24,calculateids:9,calculatepropertyvalues:24,calculates:[23,24,25],calculatetopicentrys:24,call:[0,1,3,5,7,8,10,11,12,13,14,15,16,17,19,24,33,35,40,41],callback:[1,5,7,10,11,12,13,14,15,16,19,39,43],cam:[6,28,29],camera:[6,29,37],can:[0,1,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,23,24,25,31,33,34,35,36,37,38,40,41,42],cannot:37,capabl:33,care:[33,38],cd:31,celsiusunit:11,central:1,chang:[1,4,7,8,10,11,12,13,14,16,18,19,29,33,37,38],chapter:[39,40],charact:[23,36],check:[24,26],checkout:31,child:37,chip:36,clear:25,click:[5,7,9,31],client:[1,28,33,35,37,38,40,41,42],climat:11,clone:36,close:[1,29],cmd:[7,10,11,12,13,14],code:[39,40,43],color:[12,29],colortemp:12,colortemperaturefeatur:12,com:[4,5,6,7,8,10,11,12,13,14,15,16,17,19,31],combin:9,come:40,command:[5,7,10,11,12,13,14,15,16,19,43],commandclos:7,commandlock:13,commandopen:[7,13],commandstop:7,commandunlock:13,commun:[1,32,34,42,43],compar:[4,7,8,10,11,12,13,14,16,18,19,24],comparedatatop:24,compat:[30,43],compil:[31,39,43],complet:[28,33],compon:[3,24],componentnam:3,config:24,configur:[1,3,24,38,39,42,43],connect:[0,1,3,4,7,8,10,11,12,13,14,16,18,19,29,33,38,39,40,41,43],connecttoserv:1,consid:[33,42],constcharpropertyvalu:24,construct:[0,1,25,38],constructor:[0,1,3,9,11,37],contact:29,contain:[11,16,23,26],content:[1,6,36],control:[7,10,11,12,13,14,29,33,36],controllino:28,conveni:[11,14,18],convert:[0,23,26],coolingact:11,coolmod:11,copi:36,core:[22,28,39,43],corp:36,correspond:[34,36],count:16,countoptionsinstr:16,coupl:34,cover:[7,16,29,37,40,43],covercommand:7,coverst:7,creat:[1,3,9,14,23,24,38],credenti:[29,35,40,42],current:[0,3,4,7,8,10,11,12,13,14,16,18,19],curtain:28,custom:[8,9,13,29,41,42,43],custompayload:41,customtop:41,cut:33,cycl:[1,35],data:[1,3,6,7,10,11,12,13,14,24,38,40],dawidchyrzynski:31,debug:[39,43],decim:[3,23],defaultfanmod:11,defaultfeatur:[7,10,11,12],defaultmod:11,defaultposit:7,defaultswingmod:11,defaultunit:11,defin:[3,14,17,20,34],delai:40,delet:0,depend:[31,36],describ:[39,40],descript:29,deseri:23,design:43,desir:[9,25],destin:[23,26],destroi:[1,3],destroyseri:3,determin:[10,24],determineprogmemsubtyp:9,determineprogmemtyp:9,develop:36,devic:[0,1,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,22,24,28,29,31,32,34,35,38,39,40,41,42,43],device_track:8,device_trigg:9,deviceclass:[4,5,7,14,17,19],devicetyp:[1,24],differ:[11,14,18,23,36],digit:[3,23],directli:34,disabl:[7,10,11,12,13,14,16,19,33],disconnect:1,discov:42,discover:29,discoveri:[1,3,24,29,39,43],discuss:30,displai:[0,5,6,14,17,18,19,29,33,37],document:[3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,30,31,37,40],doesn:[1,7,10,12,13,14,16,17,19,40],don:[30,40],door:[7,13,29],doxygen:43,dropdown:[16,29,31],dryingact:11,drymod:11,dst:[23,26],dual:28,dure:35,dynam:[24,25],e:[3,6,17,24,33],each:[0,1,3,5,7,10,11,12,13,14,16,17,19,26,33,36,38,40,41],easier:26,easili:[24,33,42],element:25,empti:[1,23],enabl:[0,1,3,7,10,11,12,13,14,16,19,33,34],enablelastwil:[0,1,33],enablesharedavail:[0,33],encod:6,encodingbase64:6,encodingbinari:6,encrypt:42,end:[23,26,35,40],endpublish:1,endswith:26,entir:33,entiti:[0,4,5,6,7,8,9,10,11,12,13,14,15,16,17,19,20,29,37],entri:24,entrytyp:24,enumer:[3,6,7,8,9,10,11,12,13,14,24],environ:31,epoxyduino:43,equip:6,esp32:[6,28,29,31,39,42,43],esp8255:43,esp8266:[29,31,39,42,43],esp8266wifi:40,esp:[5,28,37,42,43],establish:[1,29,35,41,42],etc:[0,1,33,38],ethernet:[28,33,35,36,37,38,40,41,42,43],ethernetcli:[1,33,35,37,38,40,41,42],even:33,event:[9,20],ever:1,everyth:40,ex_arduinoha_binary_sensor:34,ex_arduinoha_button:34,ex_arduinoha_camera:34,ex_arduinoha_cov:34,ex_arduinoha_device_track:34,ex_arduinoha_device_trigg:34,ex_arduinoha_fan:34,ex_arduinoha_hvac:34,ex_arduinoha_light:34,ex_arduinoha_lock:34,ex_arduinoha_numb:34,ex_arduinoha_scen:34,ex_arduinoha_select:34,ex_arduinoha_sensor:34,ex_arduinoha_switch:34,ex_arduinoha_tag_scann:34,exampl:[4,5,6,7,8,9,10,11,12,13,14,15,16,17,19,23,30,33,34,35,37,41,42,43],except:36,execut:[7,10,11,12,13,14,43],exist:[1,3],expect:[6,23],explicit:[1,23],expos:[33,35,41],extra:[23,31,32],fahrenheitunit:11,fals:[1,3,4,7,8,10,11,12,13,14,16,18,19,33],famili:29,fan:[7,10,11,29,37,38],fanact:11,fanfeatur:11,fanmod:11,fanonlymod:11,featur:[0,3,7,10,11,12,30,33,34,39],feel:30,few:[35,40],fi:[28,36],field:31,file:34,find:[3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,26],fine:[28,42],finish:1,fire:1,firmwar:1,first:[0,1],flag:[5,7,10,11,12,13,14,15,16,17,19,24,34],flagentrytyp:24,flagtyp:24,flash:[3,9,25,33,34,36,37,43],flush:24,flushentri:24,flushentryvalu:24,flushflag:24,flushtop:24,follow:[3,24,31,33,37,38,40],forc:[4,7,8,10,11,12,13,14,16,17,18,19],forceupd:17,formula:23,foundat:39,free:[9,11,24],friend:[3,23],from:[1,4,5,6,7,8,10,11,12,13,14,15,16,17,18,19,23,29,31],frombuff:12,fromstr:23,full:39,fun:30,g:[3,6,12,17,24],garag:7,gener:[0,23,24],generateconfigtop:24,generatedatatop:24,get:[3,32,43],getavailabilitytop:0,getbasevalu:23,getcommandtempl:14,getcommandwithfloattempl:11,getcurrentact:11,getcurrentauxst:11,getcurrentbright:12,getcurrentcolortemperatur:12,getcurrentfanmod:11,getcurrentmod:11,getcurrentposit:7,getcurrentrgbcolor:12,getcurrentspe:10,getcurrentst:[4,7,10,12,13,14,16,19],getcurrentswingmod:11,getcurrenttargettemperatur:11,getcurrenttemperatur:11,getcurrentvalu:18,getdataprefix:1,getdevic:1,getdiscoveryprefix:1,getencodingproperti:6,getentri:24,getentriesnb:24,getitem:25,getitemsnb:25,getmodeproperti:14,getnam:3,getprecis:23,getprecisionbas:23,getseri:0,getsourcetypeproperti:8,getstat:8,getsubtyp:9,gettyp:9,getuniqueid:0,git:31,github:[10,12,30,31],given:[0,1,3,4,6,7,8,9,10,11,12,13,14,16,17,18,19,23,24,25,26],global:40,go:[0,1,24,25,32,40],goe:[37,40],gp:8,graph:17,greater:23,green:12,group:36,guid:30,h:[33,34,35,36,37,38,40,41,42],ha:[0,1,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,24,25,32,33,36,37],habasedevicetyp:[1,4,5,6,7,8,9,10,11,12,13,14,15,16,17,19,20,21,22,24,43],habinarysensor:[0,1,3,21,22,37,43],habutton:[3,21,22,37,43],hacamera:[3,21,22,37,43],hacov:[3,21,22,37,43],hadevic:[1,2,3,22,33,35,37,38,40,41,42,43],hadevicetrack:[3,21,22,37,43],hadevicetrigg:[3,21,22,37,43],hafan:[3,21,22,37,43],hahvac:[3,21,22,37,43],halight:[3,21,22,37,43],halock:[3,21,22,37,43],hamqtt:[0,2,3,22,33,35,37,38,40,41,42,43],handl:24,handleauxstatecommand:11,handlebrightnesscommand:12,handlecolortemperaturecommand:12,handlecommand:[7,13,14],handlefanmodecommand:11,handlemodecommand:11,handlepowercommand:11,handlergbcommand:12,handlespeedcommand:10,handlestatecommand:[10,12],handleswingmodecommand:11,handletargettemperaturecommand:11,hanumb:[3,11,21,22,37,43],hanumer:[10,11,12,14,18,22,27,43],happen:0,hardwar:[30,43],hascen:[3,21,22,37,43],haselect:[3,21,22,37,43],hasensor:[0,3,18,21,22,37,43],hasensorinteg:18,hasensornumb:[17,21,22,37,43],haseri:[0,3,22,25,27,43],haserializerarrai:[11,16,22,24,27,43],haswitch:[1,3,21,22,33,37,43],hatagscann:[3,21,22,37,43],hautil:[22,27,43],have:[17,23,30,37,40],heat:11,heatingact:11,heatmod:11,here:[4,5,7,14,17,19,28,37,38,40],hesit:30,hex:[0,26],highfanmod:11,highli:33,histori:17,hit:[24,37],hold:29,home:[0,1,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,29,31,32,33,34,36,37,38,42,43],homeassist:[1,38],hostnam:[1,35],how:[14,33],howev:42,http:[4,5,6,7,8,9,10,11,12,13,14,15,16,17,19,20,31],humidifi:37,hvac:[11,29,37],i:[33,43],icon:[4,5,6,7,8,10,11,12,13,14,15,16,17,19],id:[0,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,24,30,39,43],idea:40,idleact:11,imag:6,imageencod:6,implement:[1,3,8,13,29,33,36,40],includ:[10,31,33,35,36,37,38,40,41,42],incom:17,increas:[36,37],index:16,inform:[3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20],initi:[1,3,8,11,13,14,40,43],inlin:[0,1,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,23,24,25],input:[16,26,36],insid:1,instal:[30,32,36,43],instanc:[0,1,3,14,24,32,36,38,40],instead:1,int16_t:[7,11,14,18,23],int32_t:[11,14,18,23],int64_t:23,int8_t:[11,14,16,18,23],integ:[17,23,29],integr:[4,5,6,7,8,9,10,11,12,13,14,15,16,17,19,20,31,32,43],interact:[28,29],intern:[1,24,36,38],interv:1,introduct:[39,43],io:[4,5,6,7,8,9,10,11,12,13,14,15,16,17,19,20],iot:[28,29],ip:1,ipaddress:1,isavail:0,isavailabilityconfigur:3,isconnect:1,isfloat:23,isint16:23,isint32:23,isint8:23,isonlin:3,isprogmemdata:3,isprogmemsubtyp:9,isprogmemtyp:9,isset:[12,23],issharedavailabilityen:0,issu:[10,12],isuint16:23,isuint32:23,isuint8:23,item:[24,25],itemp:25,itemtyp:25,its:[3,8,31,33,36],jpeg:6,json:[0,24,25],just:[31,35],keep:[0,3,36,37],knolleari:31,known:[4,7,8,10,11,12,13,14,16,18,19,24],label:3,last:[1,4,7,8,10,11,12,13,14,16,18,19,29,43],lastwillmessag:1,lastwillretain:1,lastwilltop:1,later:40,latest:31,le:8,led:29,length:[0,1,3,5,6,7,10,11,12,13,14,15,16,19,23,26,36,41],less:37,let:11,lib:31,librari:[1,10,12,23,28,30,31,33,34,36,38,42,43],life:26,light:[12,29,33,36,37,38],like:[1,36,37,42],limit:[24,39,43],line:[31,33],list:[4,5,7,11,14,16,17,19,24,28,34,36,37],live:1,local:[35,42],lock:[13,29,37],lockcommand:13,lockstat:13,log:34,logic:[3,5,35,36,37,40],login:42,long_press:9,look:[17,41,42],loop:[1,33,35,36,37,38,40,41,42],lost:[1,33],low:43,lower:[25,36],lowfanmod:11,lwt:[0,29,39,43],mac:[33,35,36,37,38,40,41,42],macaddress:40,macro:[39,43],made:[35,41],mai:[1,4,7,8,10,11,12,13,14,16,18,19,20,24,28,34,36,37,38],main:[1,24],maintain:[35,37,38,40,41],make:[26,29],makeesparduino:[30,43],makefil:[31,34],manag:[31,38],manual:33,manufactur:[0,36],match:[1,18,24],materialdesignicon:[4,5,6,7,8,10,11,12,13,14,15,16,17,19],max:[10,11,14],maxdevicestypesnb:1,maxdigitsnb:23,maxentriesnb:24,maxi:28,maximum:[1,10,11,12,14,23,24,25,37],mcu:36,mdi:[4,5,6,7,8,10,11,12,13,14,15,16,17,19],mdn:29,mean:[3,17],meaning:17,meant:31,measur:[14,17],mediumfanmod:11,meet:35,mega:28,member:[0,1,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,23,24,25],memori:[0,3,9,11,24,25,26,34,37],menu:31,messag:[0,1,3,4,6,7,8,9,10,11,12,13,14,16,17,18,19,20,24,29,33,39,43],method:[0,1,3,4,7,8,10,11,12,13,14,16,17,18,19,23,24,26,31,32,33,35,38,40,41],mfrc522:29,millisecond:1,min:[10,11,14],mini:28,minim:[14,40],minimum:[10,11,12,14],mire:12,mix:17,mode:[7,10,11,12,13,14,16,19,29,39,43],modeauto:14,modebox:14,model:[0,36],modesfeatur:11,modeslid:14,modul:[6,28,29],more:[3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,31,42],mosquitto:[32,42],most:33,movement:14,mqtt:[0,1,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,24,29,32,35,37,38,39,40,43],multi:29,multipl:[5,7,10,11,12,13,14,15,16,19,29,37],multipli:23,must:[10,11,12,14,16,19],my:43,mybrok:35,mycustomprefix:38,mydataprefix:38,myid:36,mynetworkssid:40,mypassword:40,myswitch:33,myswitchid:33,mytop:41,myuniqueid:[33,36],name:[0,3,4,5,6,7,8,10,11,12,13,14,15,16,17,19,24,36],nano:[28,29],necessari:40,need:[0,1,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,24,31,32,33,34,36,38,40,41],netclient:1,network:[1,28,42],never:[1,3],newli:26,nodemcu:[28,29],non:[10,12,14,16,19,41],none:0,note:[0,1,3,4,5,7,8,9,10,11,12,13,14,15,16,18,19,23,24,28,33,36,37],noth:0,nullptr:[0,1,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,19,24],number:[0,1,10,11,14,17,18,23,24,25,29,37],numberprecis:[3,11,14,18],numberpropertytyp:24,numer:[10,14,18,23,29],object:[1,24,40],objectid:24,occupi:34,off:[4,10,19,33],offact:11,offlin:[0,29,33,43],offmod:11,offswingmod:11,onauxstatecommand:11,onbrightnesscommand:12,onc:[0,5,15,16,35,40],oncolortemperaturecommand:12,oncommand:[5,7,13,14,15,16,19],onconnect:[1,41],onconnectedlog:1,one:[1,4,7,8,10,11,12,13,14,16,18,19,31,34,35,36,38],onfanmodecommand:11,onli:[0,1,3,10,11,12,14,16,18,24,31,33,35],onlin:[0,3,29,33,43],onmessag:[1,41],onmodecommand:11,onmqttconnect:[1,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20],onmqttmessag:[1,3,5,7,10,11,12,13,14,15,16,19],onpowercommand:11,onrgbcolorcommand:12,onspeedcommand:10,onstatecommand:[10,12],onswingmod:11,onswingmodecommand:11,ontargettemperaturecommand:11,open:[10,12,13,24,29,30,31],oper:[12,23],optim:[39,43],optimist:[7,10,12,13,14,16,19],option:[16,36],order:32,other:[6,17,31],otherwis:0,output:[10,24,25,26],over:32,overload:[11,14,18],overrid:[4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20],own:[0,1,24,36],owner:24,ownership:1,panel:[0,1,3,4,5,6,7,8,10,11,12,13,14,15,16,17,18,19,29,33,37,42,43],paramet:[0,1,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,23,24,25,26,39,43],pars:[7,10,11,12,13,14],part:[23,40],pass:[1,9,24],password:[1,35,40,41,42],payload:[1,3,5,7,10,11,12,13,14,15,16,19,24,41],payloadlength:1,percentag:10,perform:[1,20],period:[1,40],physic:[36,37],pick:[35,36],piec:40,pin:29,pleas:[0,1,3,4,5,7,8,9,10,11,12,13,14,15,16,18,19,23,24,28,31,33,36,37,41,42],plu:23,point:[1,3,9,11,14,18],pointer:[0,1,9,24,25,36],port:[1,35],posit:7,positionfeatur:7,possibl:[5,7,10,11,12,13,14,15,16,17,19,35,43],potenti:39,pow:23,power:[11,29,33,37,42],powerfeatur:11,precis:[11,14,18,23],precisionp0:[3,14,18],precisionp1:[3,11],precisionp2:3,precisionp3:3,prefix:[1,24,39,43],prerequisit:[30,43],present:[26,30,35],press:[5,9,29],preview:29,previou:[4,7,8,10,11,12,13,14,16,17,18,19],privat:[0,1,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,23,24,25],pro:28,process:[1,17,38],processmessag:1,produc:[1,3,5,7,9,10,11,12,13,14,15,16,17,19,20],progmem:[1,3,6,8,9,11,14,24],progmemitem:25,progmempropertyvalu:24,project:[31,40,43],proper:[7,10,11,12,13,14,23,24],properti:[0,1,6,7,13,24,25,39,43],propertyentrytyp:24,propertyvaluetyp:24,protect:[3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20],protocol:32,provid:[11,14,18,26,34,40],publish:[0,1,3,4,6,7,8,9,10,11,12,13,14,16,17,18,19,20,24,29,33,38,39,43],publishact:11,publishauxst:11,publishavail:[0,3],publishbright:12,publishcolortemperatur:12,publishconfig:3,publishcurrenttemperatur:11,publishfanmod:11,publishimag:6,publishmod:11,publishondatatop:3,publishposit:7,publishrgbcolor:12,publishspe:10,publishst:[4,7,8,10,12,13,14,16,19],publishswingmod:11,publishtargettemperatur:11,publishvalu:18,pubsub:1,pubsubcli:[1,31],pure:28,purpos:[1,24],push:[7,10,12,38],quickli:37,r2:28,r3:28,r:12,ram:[33,36,37,43],random:37,rang:10,raw:6,rbb:12,re:[1,11,17,31,32,40],reboot:37,receiv:[1,3,5,7,10,11,12,13,14,16,19,24,41],recogn:24,recommend:[32,33,36,37],reconnect:[1,43],reconnectinterv:1,red:12,reduc:24,refer:[31,43],regist:[0,1,3,5,7,10,11,12,13,14,15,16,19,37,38],registri:0,relat:33,reli:[33,38],remov:1,replac:42,report:[3,7,8,10,11,12,13,14,16,19,29,39,43],repres:[0,1,4,5,6,8,9,10,11,14,16,23,25,26,36,37],represent:[0,9,17,23,24,25,26,29],requir:[33,35,37],reset:23,resourc:[3,33,37,43],result:[23,34,37],retain:[1,3,5,7,9,10,11,12,13,14,15,16,19,41],rfid:29,rgb:[12,29],rgbcolor:12,rgbfeatur:12,rgbstringmaxlength:12,roller:7,root:31,router:8,rule:[38,40],runtim:[33,37],s:[0,1,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,24,28,29,36,37,38,39,40,42,43],safe:1,safest:36,samd:29,same:[0,1,4,5,7,8,10,11,12,13,14,15,16,18,19,42],save:[0,3,23,26,33,34],scale:12,scan:[20,29],scanner:[20,29,37],scene:[15,29,37],scope:[3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,36],search:31,second:31,secur:[39,43],see:[11,33],select:[16,29,31,37],selector:29,semicolon:16,send:20,sender:[5,7,10,11,12,13,14,15,16,19],sensor:[1,4,14,17,18,19,29,33,36,37,38],separ:[16,33],sequenc:36,serial:[0,3,11,16,24,25],serializerentri:24,serverhostnam:1,serverip:1,serverport:1,session:24,set:[0,1,3,4,5,6,7,8,10,11,12,13,14,15,16,17,18,19,23,24,33,35,36],setact:11,setauxst:11,setavail:[0,3,33],setbasevalu:23,setbright:12,setbrightnessscal:12,setcolortemperatur:12,setcurrentact:11,setcurrentauxst:11,setcurrentbright:12,setcurrentcolortemperatur:12,setcurrentcurrenttemperatur:11,setcurrentfanmod:11,setcurrentmod:11,setcurrentposit:7,setcurrentrgbcolor:12,setcurrentspe:10,setcurrentst:[4,7,8,10,12,13,14,16,19],setcurrentswingmod:11,setcurrenttargettemperatur:11,setcurrenttemperatur:11,setcurrentvalu:18,setdataprefix:[1,38],setdeviceclass:[4,5,7,14,17,19],setdiscoveryprefix:[1,38],setencod:6,setfanmod:11,setforceupd:17,seticon:[4,5,6,7,8,10,11,12,13,14,15,16,17,19],setlastwil:1,setmanufactur:[0,36],setmax:14,setmaxmir:12,setmaxtemp:11,setmin:14,setminmir:12,setmintemp:11,setmod:[11,14],setmodel:[0,36],setnam:[0,3,36],setopt:16,setoptimist:[7,10,12,13,14,16,19],setp:11,setposit:7,setprecis:23,setretain:[5,7,10,11,12,13,14,15,16,19],setrgbcolor:12,setsoftwarevers:[0,36],setsourcetyp:8,setspe:10,setspeedrangemax:10,setspeedrangemin:10,setstat:[4,7,8,10,12,13,14,16,19],setstep:14,setswingmod:11,settargettemperatur:11,settemperatureunit:11,settempstep:11,setter:36,setuniqueid:[0,40],setunitofmeasur:[14,17],setup:[32,33,35,37,38,40,41,42],setvalu:[17,18],share:[0,39,43],shield:43,should:[0,1,3,7,10,11,12,14,16,23,28,35,42],show:33,shown:33,shutter:7,simpl:[29,36,37],simplifi:23,sinc:1,singl:[24,33,37],singleton:1,size:[9,23,24,25,26],sizeof:[33,35,36,37,38,40,41,42],sketch:31,skip:40,slider:[14,29],smallest:14,so:[0,3,10,26,32,36,37],softwar:[0,36],softwarevers:0,solid:39,solut:[33,36,42],some:[1,5,24,26,34,37,38,41],sonoff:28,sourc:8,sourcetyp:8,sourcetypebluetooth:8,sourcetypebluetoothl:8,sourcetypegp:8,sourcetyperout:8,sourcetypeunknown:8,spec:36,specif:[3,33,34],specifi:[0,1,3,9,25,35],speed:[10,29],speed_rang:10,speed_range_min:10,speedsfeatur:10,src:26,ssl:[39,43],start:[40,43],state:[0,3,4,7,8,10,11,12,13,14,16,18,19,29,33,38,43],stateclos:7,statehom:8,statelock:13,statenotavail:8,statenothom:8,stateopen:7,statestop:7,stateunknown:[7,8,13],stateunlock:13,statu:40,step:[10,11,14,30],stop:29,store:[1,3,14,16,17,24,25],str:26,strcmp:41,stream:[1,24],string:[0,1,3,6,8,9,11,14,16,17,23,24,25,26,29],struct:[12,24],structur:24,subclass:[3,17],submodul:31,subscrib:[1,3,29,41,43],subscribetop:3,subscript:[1,39,43],subtyp:[9,24],successfulli:[4,6,7,8,9,10,11,12,13,14,16,17,18,19,20,25,43],suffix:26,suppli:33,support:[3,9,10,11,12,28,33,34,36,39,43],swing:11,swingfeatur:11,swingmod:11,t:[1,4,7,8,10,11,12,13,14,16,17,18,19,30,33,40],tabl:[34,37],tag:[20,29,31,37],tagscan:20,take:[1,33,38,41,42],target:[11,29],targettemperaturefeatur:11,tcp:[1,32,33,42],teh:1,temperatur:[11,12,29],temperatureunit:11,templat:[11,14],termin:[0,23],test:[28,43],testament:[29,43],text:37,textual:17,than:[23,25],thei:[11,37],them:[34,36],thi:[0,1,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,23,24,26,30,33,34,35,37,39,40,41,42],those:34,three:[3,36],through:1,tick:40,time:[1,3,5,7,10,11,12,13,14,16,17,19,41],tl:42,tofloat:23,toint16:23,toint32:23,toint8:23,topic:[0,1,3,5,7,10,11,12,13,14,15,16,19,24,29,39,41,43],topicentrytyp:24,topicp:24,topictyp:24,tostr:23,touint16:23,touint32:23,touint8:23,track:33,tracker:[8,37],trackerst:8,traffic:[1,42],trigger:[5,9,15,29,37],triggersubtyp:9,triggertyp:9,truncat:34,turn:33,turnoff:[10,12,19],turnoffsubtyp:9,turnon:[10,12,19],turnonsubtyp:9,tuya:28,twice:0,two:[3,26,31,38,43],type:[1,3,6,7,8,9,10,11,12,13,14,17,22,23,24,25,31,34,36,38,39,40,43],typedef:25,ui:14,uint16_t:[0,1,3,5,6,7,9,10,11,12,13,14,15,16,18,19,23,24,25,26,41],uint32_t:[1,11,14,18,23],uint8_t:[1,3,5,6,7,10,11,12,13,14,15,16,18,19,23,24,25,41],unattend:42,unclear:30,uncom:34,understand:[3,39],uniqu:[0,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,24,39,43],uniqueid:[0,3,4,5,6,7,8,10,11,12,13,14,15,16,17,18,19,20],unit:[11,14,17,37,43],unitofmeasur:[14,17],unknownact:11,unknownentrytyp:24,unknownfanmod:11,unknownmod:11,unknownpropertyvaluetyp:24,unknownswingmod:11,unlik:17,unlock:[13,34],uno:[28,37,43],unsupport:9,up:40,updat:[4,6,7,8,10,11,12,13,14,16,17,18,19],upfront:24,uptim:29,us:[0,1,3,4,6,7,8,9,10,11,12,13,14,16,17,18,19,20,23,24,25,26,28,29,31,32,33,34,35,37,38,40,41,42,43],usag:36,user:[20,31],usernam:[1,35,40,41,42],util:[22,33,37,38,39,43],v2:31,vacuum:37,valu:[3,4,5,6,7,8,9,10,11,12,13,14,16,17,18,19,20,23,24],valuetyp:24,variabl:24,variant:35,verifi:[1,3,9],version:[0,31,36],via:[0,3,11,12,16,29,34],virtual:[3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,34],voltag:29,wa:[0,1,3,9,16,17,28,43],wai:[0,31,33,36,43],wait:40,wall:[9,29],want:[1,4,7,8,10,11,12,13,14,16,17,18,19,33,34],wasn:[8,11,13,14],welcom:30,were:[9,24,25],what:[11,14,17,18,40],when:[0,1,7,10,11,12,13,14,15,16,19,33,41],whenev:[1,38],where:[1,23,24,26,36],whether:[0,1,3,9,24,25,26],which:[3,28],whose:36,wi:[28,36],wifi:40,wificli:[1,40],wificlientsecur:42,window:29,withavail:24,withdevic:24,within:10,without:[0,4,7,8,10,11,12,13,14,16,18,19,23,33],wl_connect:40,wl_mac_addr_length:40,won:[1,4,7,8,10,11,12,13,14,16,18,19,33],work:[0,28,32,43],worri:40,wrapper:1,write:[1,24],writepayload:1,written:[1,23,24],www:[4,5,6,7,8,9,10,11,12,13,14,15,16,17,19,20],you:[0,1,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,28,30,31,32,33,34,35,36,37,38,39,40,41,42],your:[0,1,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,29,31,32,33,35,36,37,38,40,42],zero:23},titles:["HADevice class","HAMqtt class","Core API","HABaseDeviceType class","HABinarySensor class","HAButton class","HACamera class","HACover class","HADeviceTracker class","HADeviceTrigger class","HAFan class","HAHVAC class","HALight class","HALock class","HANumber class","HAScene class","HASelect class","HASensor class","HASensorNumber class","HASwitch class","HATagScanner class","Device types API","API reference","HANumeric class","HASerializer class","HASerializerArray class","HAUtils class","Utils API","Compatible Hardware","Examples","Getting started","Installation","Prerequisites","Availability reporting","Compiler macros","Connection parameters","Device configuration","Device types","Discovery","Library","Introduction","MQTT advanced features","MQTT security","ArduinoHA documentation"],titleterms:{"1":36,"2":36,"3":36,"byte":36,"char":36,"class":[0,1,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,23,24,25,26],"const":36,advanc:41,api:[2,21,22,27],arduino:[31,40],arduinoha:43,arrai:36,avail:33,boilerpl:40,callback:41,code:34,compat:28,compil:34,configur:36,connect:[35,42],constructor:36,core:2,debug:34,devic:[21,33,36,37],discoveri:38,doc:43,document:43,dure:36,esp32:40,esp8266:40,exampl:29,featur:[41,43],get:30,habasedevicetyp:3,habinarysensor:4,habutton:5,hacamera:6,hacov:7,hadevic:[0,36],hadevicetrack:8,hadevicetrigg:9,hafan:10,hahvac:11,halight:12,halock:13,hamqtt:1,hanumb:14,hanumer:23,hardwar:28,hascen:15,haselect:16,hasensor:17,hasensornumb:18,haseri:24,haserializerarrai:25,haswitch:19,hatagscann:20,hautil:26,id:[31,36],instal:31,introduct:40,librari:39,limit:37,lwt:33,macro:34,makeesparduino:31,messag:41,method:36,mode:34,mqtt:[33,41,42],optim:34,paramet:35,prefix:38,prerequisit:32,properti:36,provid:36,publish:41,refer:22,report:33,s:33,secur:42,setuniqueid:36,setup:36,share:33,ssl:42,start:30,string:36,subscript:41,support:37,topic:38,type:[21,33,37],uniqu:36,us:36,util:27}}) \ No newline at end of file diff --git a/docsrc/Makefile b/docsrc/Makefile new file mode 100644 index 0000000..b0fb0d0 --- /dev/null +++ b/docsrc/Makefile @@ -0,0 +1,31 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = source +BUILDDIR = build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +# Build Github pages +github: + @make clean + @rm -rf xml + @doxygen source/Doxyfile + @make html + @mkdir -p ../docs + @rm -rf ../docs/* + @touch ../docs/.nojekyll + @cp -a build/html/. ../docs + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docsrc/Pipfile b/docsrc/Pipfile new file mode 100644 index 0000000..e5cacc4 --- /dev/null +++ b/docsrc/Pipfile @@ -0,0 +1,17 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[packages] +exhale = "0.3.4" +breathe = "4.34.0" +sphinx = "5.0.2" +lxml = "4.8.0" +sphinx-press-theme = "0.8.0" +sphinxcontrib-email = "0.3.5" + +[dev-packages] + +[requires] +python_version = "3.9" diff --git a/docsrc/Pipfile.lock b/docsrc/Pipfile.lock new file mode 100644 index 0000000..4b42416 --- /dev/null +++ b/docsrc/Pipfile.lock @@ -0,0 +1,389 @@ +{ + "_meta": { + "hash": { + "sha256": "06cbc4b751660842e50f1cd113469dcedc03e5f6ed5be43ab74f58b69b09e7f1" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.9" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "alabaster": { + "hashes": [ + "sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359", + "sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02" + ], + "version": "==0.7.12" + }, + "babel": { + "hashes": [ + "sha256:7614553711ee97490f732126dc077f8d0ae084ebc6a96e23db1482afabdb2c51", + "sha256:ff56f4892c1c4bf0d814575ea23471c230d544203c7748e8c68f0089478d48eb" + ], + "markers": "python_version >= '3.6'", + "version": "==2.10.3" + }, + "beautifulsoup4": { + "hashes": [ + "sha256:58d5c3d29f5a36ffeb94f02f0d786cd53014cf9b3b3951d42e0080d8a9498d30", + "sha256:ad9aa55b65ef2808eb405f46cf74df7fcb7044d5cbc26487f96eb2ef2e436693" + ], + "markers": "python_version >= '3.6'", + "version": "==4.11.1" + }, + "breathe": { + "hashes": [ + "sha256:48804dcf0e607a89fb6ad88c729ef12743a42db03ae9489be4ef8f7c4011774a", + "sha256:ac0768a5e84addad3e632028fe67749c567aba2b29088493b64c2c1634bcdba1" + ], + "index": "pypi", + "version": "==4.34.0" + }, + "certifi": { + "hashes": [ + "sha256:84c85a9078b11105f04f3036a9482ae10e4621616db313fe045dd24743a0820d", + "sha256:fe86415d55e84719d75f8b69414f6438ac3547d2078ab91b67e779ef69378412" + ], + "markers": "python_version >= '3.6'", + "version": "==2022.6.15" + }, + "charset-normalizer": { + "hashes": [ + "sha256:5189b6f22b01957427f35b6a08d9a0bc45b46d3788ef5a92e978433c7a35f8a5", + "sha256:575e708016ff3a5e3681541cb9d79312c416835686d054a23accb873b254f413" + ], + "markers": "python_version >= '3.6'", + "version": "==2.1.0" + }, + "docutils": { + "hashes": [ + "sha256:686577d2e4c32380bb50cbb22f575ed742d58168cee37e99117a854bcd88f125", + "sha256:cf316c8370a737a022b72b56874f6602acf974a37a9fba42ec2876387549fc61" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==0.17.1" + }, + "exhale": { + "hashes": [ + "sha256:0871fa29ff9ac91c14e0dd69ad40db798068b4407e2e7ba5f650e07cedd6f365", + "sha256:8fe83b2d96ef41e0f921b865c1bf46c40c6907cbeff0207ab9b445fd54539a16" + ], + "index": "pypi", + "version": "==0.3.4" + }, + "idna": { + "hashes": [ + "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff", + "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d" + ], + "markers": "python_version >= '3.5'", + "version": "==3.3" + }, + "imagesize": { + "hashes": [ + "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b", + "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.4.1" + }, + "importlib-metadata": { + "hashes": [ + "sha256:637245b8bab2b6502fcbc752cc4b7a6f6243bb02b31c5c26156ad103d3d45670", + "sha256:7401a975809ea1fdc658c3aa4f78cc2195a0e019c5cbc4c06122884e9ae80c23" + ], + "markers": "python_version < '3.10'", + "version": "==4.12.0" + }, + "jinja2": { + "hashes": [ + "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852", + "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61" + ], + "markers": "python_version >= '3.7'", + "version": "==3.1.2" + }, + "lxml": { + "hashes": [ + "sha256:04da965dfebb5dac2619cb90fcf93efdb35b3c6994fea58a157a834f2f94b318", + "sha256:0538747a9d7827ce3e16a8fdd201a99e661c7dee3c96c885d8ecba3c35d1032c", + "sha256:0645e934e940107e2fdbe7c5b6fb8ec6232444260752598bc4d09511bd056c0b", + "sha256:079b68f197c796e42aa80b1f739f058dcee796dc725cc9a1be0cdb08fc45b000", + "sha256:0f3f0059891d3254c7b5fb935330d6db38d6519ecd238ca4fce93c234b4a0f73", + "sha256:10d2017f9150248563bb579cd0d07c61c58da85c922b780060dcc9a3aa9f432d", + "sha256:1355755b62c28950f9ce123c7a41460ed9743c699905cbe664a5bcc5c9c7c7fb", + "sha256:13c90064b224e10c14dcdf8086688d3f0e612db53766e7478d7754703295c7c8", + "sha256:1423631e3d51008871299525b541413c9b6c6423593e89f9c4cfbe8460afc0a2", + "sha256:1436cf0063bba7888e43f1ba8d58824f085410ea2025befe81150aceb123e345", + "sha256:1a7c59c6ffd6ef5db362b798f350e24ab2cfa5700d53ac6681918f314a4d3b94", + "sha256:1e1cf47774373777936c5aabad489fef7b1c087dcd1f426b621fda9dcc12994e", + "sha256:206a51077773c6c5d2ce1991327cda719063a47adc02bd703c56a662cdb6c58b", + "sha256:21fb3d24ab430fc538a96e9fbb9b150029914805d551deeac7d7822f64631dfc", + "sha256:27e590352c76156f50f538dbcebd1925317a0f70540f7dc8c97d2931c595783a", + "sha256:287605bede6bd36e930577c5925fcea17cb30453d96a7b4c63c14a257118dbb9", + "sha256:2aaf6a0a6465d39b5ca69688fce82d20088c1838534982996ec46633dc7ad6cc", + "sha256:32a73c53783becdb7eaf75a2a1525ea8e49379fb7248c3eeefb9412123536387", + "sha256:41fb58868b816c202e8881fd0f179a4644ce6e7cbbb248ef0283a34b73ec73bb", + "sha256:4780677767dd52b99f0af1f123bc2c22873d30b474aa0e2fc3fe5e02217687c7", + "sha256:4878e667ebabe9b65e785ac8da4d48886fe81193a84bbe49f12acff8f7a383a4", + "sha256:487c8e61d7acc50b8be82bda8c8d21d20e133c3cbf41bd8ad7eb1aaeb3f07c97", + "sha256:49a866923e69bc7da45a0565636243707c22752fc38f6b9d5c8428a86121022c", + "sha256:4beea0f31491bc086991b97517b9683e5cfb369205dac0148ef685ac12a20a67", + "sha256:4cfbe42c686f33944e12f45a27d25a492cc0e43e1dc1da5d6a87cbcaf2e95627", + "sha256:4d5bae0a37af799207140652a700f21a85946f107a199bcb06720b13a4f1f0b7", + "sha256:4e285b5f2bf321fc0857b491b5028c5f276ec0c873b985d58d7748ece1d770dd", + "sha256:57e4d637258703d14171b54203fd6822fda218c6c2658a7d30816b10995f29f3", + "sha256:5974895115737a74a00b321e339b9c3f45c20275d226398ae79ac008d908bff7", + "sha256:5ef87fca280fb15342726bd5f980f6faf8b84a5287fcc2d4962ea8af88b35130", + "sha256:603a464c2e67d8a546ddaa206d98e3246e5db05594b97db844c2f0a1af37cf5b", + "sha256:6653071f4f9bac46fbc30f3c7838b0e9063ee335908c5d61fb7a4a86c8fd2036", + "sha256:6ca2264f341dd81e41f3fffecec6e446aa2121e0b8d026fb5130e02de1402785", + "sha256:6d279033bf614953c3fc4a0aa9ac33a21e8044ca72d4fa8b9273fe75359d5cca", + "sha256:6d949f53ad4fc7cf02c44d6678e7ff05ec5f5552b235b9e136bd52e9bf730b91", + "sha256:6daa662aba22ef3258934105be2dd9afa5bb45748f4f702a3b39a5bf53a1f4dc", + "sha256:6eafc048ea3f1b3c136c71a86db393be36b5b3d9c87b1c25204e7d397cee9536", + "sha256:830c88747dce8a3e7525defa68afd742b4580df6aa2fdd6f0855481e3994d391", + "sha256:86e92728ef3fc842c50a5cb1d5ba2bc66db7da08a7af53fb3da79e202d1b2cd3", + "sha256:8caf4d16b31961e964c62194ea3e26a0e9561cdf72eecb1781458b67ec83423d", + "sha256:8d1a92d8e90b286d491e5626af53afef2ba04da33e82e30744795c71880eaa21", + "sha256:8f0a4d179c9a941eb80c3a63cdb495e539e064f8054230844dcf2fcb812b71d3", + "sha256:9232b09f5efee6a495a99ae6824881940d6447debe272ea400c02e3b68aad85d", + "sha256:927a9dd016d6033bc12e0bf5dee1dde140235fc8d0d51099353c76081c03dc29", + "sha256:93e414e3206779ef41e5ff2448067213febf260ba747fc65389a3ddaa3fb8715", + "sha256:98cafc618614d72b02185ac583c6f7796202062c41d2eeecdf07820bad3295ed", + "sha256:9c3a88d20e4fe4a2a4a84bf439a5ac9c9aba400b85244c63a1ab7088f85d9d25", + "sha256:9f36de4cd0c262dd9927886cc2305aa3f2210db437aa4fed3fb4940b8bf4592c", + "sha256:a60f90bba4c37962cbf210f0188ecca87daafdf60271f4c6948606e4dabf8785", + "sha256:a614e4afed58c14254e67862456d212c4dcceebab2eaa44d627c2ca04bf86837", + "sha256:ae06c1e4bc60ee076292e582a7512f304abdf6c70db59b56745cca1684f875a4", + "sha256:b122a188cd292c4d2fcd78d04f863b789ef43aa129b233d7c9004de08693728b", + "sha256:b570da8cd0012f4af9fa76a5635cd31f707473e65a5a335b186069d5c7121ff2", + "sha256:bcaa1c495ce623966d9fc8a187da80082334236a2a1c7e141763ffaf7a405067", + "sha256:bd34f6d1810d9354dc7e35158aa6cc33456be7706df4420819af6ed966e85448", + "sha256:be9eb06489bc975c38706902cbc6888f39e946b81383abc2838d186f0e8b6a9d", + "sha256:c4b2e0559b68455c085fb0f6178e9752c4be3bba104d6e881eb5573b399d1eb2", + "sha256:c62e8dd9754b7debda0c5ba59d34509c4688f853588d75b53c3791983faa96fc", + "sha256:c852b1530083a620cb0de5f3cd6826f19862bafeaf77586f1aef326e49d95f0c", + "sha256:d9fc0bf3ff86c17348dfc5d322f627d78273eba545db865c3cd14b3f19e57fa5", + "sha256:dad7b164905d3e534883281c050180afcf1e230c3d4a54e8038aa5cfcf312b84", + "sha256:e5f66bdf0976ec667fc4594d2812a00b07ed14d1b44259d19a41ae3fff99f2b8", + "sha256:e8f0c9d65da595cfe91713bc1222af9ecabd37971762cb830dea2fc3b3bb2acf", + "sha256:edffbe3c510d8f4bf8640e02ca019e48a9b72357318383ca60e3330c23aaffc7", + "sha256:eea5d6443b093e1545ad0210e6cf27f920482bfcf5c77cdc8596aec73523bb7e", + "sha256:ef72013e20dd5ba86a8ae1aed7f56f31d3374189aa8b433e7b12ad182c0d2dfb", + "sha256:f05251bbc2145349b8d0b77c0d4e5f3b228418807b1ee27cefb11f69ed3d233b", + "sha256:f1be258c4d3dc609e654a1dc59d37b17d7fef05df912c01fc2e15eb43a9735f3", + "sha256:f9ced82717c7ec65a67667bb05865ffe38af0e835cdd78728f1209c8fffe0cad", + "sha256:fe17d10b97fdf58155f858606bddb4e037b805a60ae023c009f760d8361a4eb8", + "sha256:fe749b052bb7233fe5d072fcb549221a8cb1a16725c47c37e42b0b9cb3ff2c3f" + ], + "index": "pypi", + "version": "==4.9.1" + }, + "markupsafe": { + "hashes": [ + "sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003", + "sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88", + "sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5", + "sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7", + "sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a", + "sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603", + "sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1", + "sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135", + "sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247", + "sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6", + "sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601", + "sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77", + "sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02", + "sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e", + "sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63", + "sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f", + "sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980", + "sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b", + "sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812", + "sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff", + "sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96", + "sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1", + "sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925", + "sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a", + "sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6", + "sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e", + "sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f", + "sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4", + "sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f", + "sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3", + "sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c", + "sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a", + "sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417", + "sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a", + "sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a", + "sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37", + "sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452", + "sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933", + "sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a", + "sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7" + ], + "markers": "python_version >= '3.7'", + "version": "==2.1.1" + }, + "packaging": { + "hashes": [ + "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb", + "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522" + ], + "markers": "python_version >= '3.6'", + "version": "==21.3" + }, + "pygments": { + "hashes": [ + "sha256:5eb116118f9612ff1ee89ac96437bb6b49e8f04d8a13b514ba26f620208e26eb", + "sha256:dc9c10fb40944260f6ed4c688ece0cd2048414940f1cea51b8b226318411c519" + ], + "markers": "python_version >= '3.6'", + "version": "==2.12.0" + }, + "pyparsing": { + "hashes": [ + "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb", + "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc" + ], + "markers": "python_full_version >= '3.6.8'", + "version": "==3.0.9" + }, + "pytz": { + "hashes": [ + "sha256:1e760e2fe6a8163bc0b3d9a19c4f84342afa0a2affebfaa84b01b978a02ecaa7", + "sha256:e68985985296d9a66a881eb3193b0906246245294a881e7c8afe623866ac6a5c" + ], + "version": "==2022.1" + }, + "requests": { + "hashes": [ + "sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983", + "sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349" + ], + "markers": "python_version >= '3.7' and python_version < '4'", + "version": "==2.28.1" + }, + "six": { + "hashes": [ + "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", + "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.16.0" + }, + "snowballstemmer": { + "hashes": [ + "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1", + "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a" + ], + "version": "==2.2.0" + }, + "soupsieve": { + "hashes": [ + "sha256:3b2503d3c7084a42b1ebd08116e5f81aadfaea95863628c80a3b774a11b7c759", + "sha256:fc53893b3da2c33de295667a0e19f078c14bf86544af307354de5fcf12a3f30d" + ], + "markers": "python_version >= '3.6'", + "version": "==2.3.2.post1" + }, + "sphinx": { + "hashes": [ + "sha256:7bf8ca9637a4ee15af412d1a1d9689fec70523a68ca9bb9127c2f3eeb344e2e6", + "sha256:ebf612653238bcc8f4359627a9b7ce44ede6fdd75d9d30f68255c7383d3a6226" + ], + "index": "pypi", + "version": "==4.5.0" + }, + "sphinx-press-theme": { + "hashes": [ + "sha256:2884caab1dc01ecb11d158d4dd6d3179e2dd97cd48516c769cc27360272e62b3", + "sha256:ddf877d414a2c66e13396d726115aa3f0c94d1ac9133b4df028c261bf388ab25" + ], + "index": "pypi", + "version": "==0.8.0" + }, + "sphinxcontrib-applehelp": { + "hashes": [ + "sha256:806111e5e962be97c29ec4c1e7fe277bfd19e9652fb1a4392105b43e01af885a", + "sha256:a072735ec80e7675e3f432fcae8610ecf509c5f1869d17e2eecff44389cdbc58" + ], + "markers": "python_version >= '3.5'", + "version": "==1.0.2" + }, + "sphinxcontrib-devhelp": { + "hashes": [ + "sha256:8165223f9a335cc1af7ffe1ed31d2871f325254c0423bc0c4c7cd1c1e4734a2e", + "sha256:ff7f1afa7b9642e7060379360a67e9c41e8f3121f2ce9164266f61b9f4b338e4" + ], + "markers": "python_version >= '3.5'", + "version": "==1.0.2" + }, + "sphinxcontrib-email": { + "hashes": [ + "sha256:2387fc0691f3a4ed9c0b7d32acce5a42495340cc45f6e759a1b38e1eb86fe888", + "sha256:74738235afd602b7f692d2b62b4582034e8bb32dbcaa7ecab34be985d8bae590" + ], + "index": "pypi", + "version": "==0.3.5" + }, + "sphinxcontrib-htmlhelp": { + "hashes": [ + "sha256:d412243dfb797ae3ec2b59eca0e52dac12e75a241bf0e4eb861e450d06c6ed07", + "sha256:f5f8bb2d0d629f398bf47d0d69c07bc13b65f75a81ad9e2f71a63d4b7a2f6db2" + ], + "markers": "python_version >= '3.6'", + "version": "==2.0.0" + }, + "sphinxcontrib-jsmath": { + "hashes": [ + "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178", + "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8" + ], + "markers": "python_version >= '3.5'", + "version": "==1.0.1" + }, + "sphinxcontrib-qthelp": { + "hashes": [ + "sha256:4c33767ee058b70dba89a6fc5c1892c0d57a54be67ddd3e7875a18d14cba5a72", + "sha256:bd9fc24bcb748a8d51fd4ecaade681350aa63009a347a8c14e637895444dfab6" + ], + "markers": "python_version >= '3.5'", + "version": "==1.0.3" + }, + "sphinxcontrib-serializinghtml": { + "hashes": [ + "sha256:352a9a00ae864471d3a7ead8d7d79f5fc0b57e8b3f95e9867eb9eb28999b92fd", + "sha256:aa5f6de5dfdf809ef505c4895e51ef5c9eac17d0f287933eb49ec495280b6952" + ], + "markers": "python_version >= '3.5'", + "version": "==1.1.5" + }, + "urllib3": { + "hashes": [ + "sha256:44ece4d53fb1706f667c9bd1c648f5469a2ec925fcf3a776667042d645472c14", + "sha256:aabaf16477806a5e1dd19aa41f8c2b7950dd3c746362d7e3223dbe6de6ac448e" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'", + "version": "==1.26.9" + }, + "zipp": { + "hashes": [ + "sha256:56bf8aadb83c24db6c4b577e13de374ccfb67da2078beba1d037c17980bf43ad", + "sha256:c4f6e5bbf48e74f7a38e7cc5b0480ff42b0ae5178957d564d18932525d5cf099" + ], + "markers": "python_version >= '3.7'", + "version": "==3.8.0" + } + }, + "develop": {} +} diff --git a/docsrc/README.md b/docsrc/README.md new file mode 100644 index 0000000..e9c22d9 --- /dev/null +++ b/docsrc/README.md @@ -0,0 +1,41 @@ +# Documentation + +This document describes how to generate documentation of the library from the sources. +If you're looking for the documentation please [follow this link](#). + +## Prerequsites + +1. Doxygen +2. Python 3.9+ +3. Pipenv + +## Installation + +The first time setup is required before generating the documentation. Follow these steps: +1. Open terminal in the `docsrc` directory +2. Run `pipenv install` + +### Apple Silicon M1 + +On Apple M1 processors you may get this error when trying to build the documentation: `Could not parse the contents of index.xml as an xml.` + +Most likely this issue is caused by an architecture mismatch of the `lxml` package. +To fix this issue open the Pipenv shell by running `pipenv shell` and follow these steps: +1. Run `pip uninstall lxml` +2. Run `arch -arm64 pip install lxml --no-binary lxml` + +This solution forces `lxml` to be built from the sources. + +## Generating the documentation + +1. Open terminal in the `docsrc` directory +2. Run the Doxygen command `doxygen` +3. Open the Pipenv shell `pipenv shell` +4. Run the build `make html` + +The generated documentation will be available in the `docsrc/build/html` directory. + +## Github pages + +In order to build the documentation that's going to be published as Github pages run `make github`. +The generated HTML build will be automatically moved to the `docs` directory. diff --git a/docsrc/make.bat b/docsrc/make.bat new file mode 100644 index 0000000..747ffb7 --- /dev/null +++ b/docsrc/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=source +set BUILDDIR=build + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.https://www.sphinx-doc.org/ + exit /b 1 +) + +if "%1" == "" goto help + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/docsrc/source/Doxyfile b/docsrc/source/Doxyfile new file mode 100644 index 0000000..ec4c3ec --- /dev/null +++ b/docsrc/source/Doxyfile @@ -0,0 +1,2603 @@ +# Doxyfile 1.9.3 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the configuration +# file that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# https://www.gnu.org/software/libiconv/ for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = "ArduinoHA" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = + +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, +# Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = YES + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = ../src + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = ../src + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = NO + +# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line +# such as +# /*************** +# as being the beginning of a Javadoc-style comment "banner". If set to NO, the +# Javadoc-style will behave just like regular comments and it will not be +# interpreted by doxygen. +# The default value is: NO. + +JAVADOC_BANNER = NO + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# By default Python docstrings are displayed as preformatted text and doxygen's +# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the +# doxygen's special commands can be used and the contents of the docstring +# documentation blocks is shown as doxygen documentation. +# The default value is: YES. + +PYTHON_DOCSTRING = YES + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:^^" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". Note that you cannot put \n's in the value part of an alias +# to insert newlines (in the resulting output). You can put ^^ in the value part +# of an alias to insert a newline as if a physical newline was in the original +# file. When you need a literal { or } or , in the value part of an alias you +# have to escape them by means of a backslash (\), this can lead to conflicts +# with the commands \{ and \} for these it is advised to use the version @{ and +# @} or use a double escape (\\{ and \\}) + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice +# sources only. Doxygen will then generate output that is more tailored for that +# language. For instance, namespaces will be presented as modules, types will be +# separated into more groups, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_SLICE = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, JavaScript, +# Csharp (C#), C, C++, Lex, D, PHP, md (Markdown), Objective-C, Python, Slice, +# VHDL, Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: +# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser +# tries to guess whether the code is fixed or free formatted code, this is the +# default for Fortran type files). For instance to make doxygen treat .inc files +# as Fortran files (default is PHP), and .f files as C (default is Fortran), +# use: inc=Fortran f=C. +# +# Note: For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. When specifying no_extension you should add +# * to the FILE_PATTERNS. +# +# Note see also the list of default file extension mappings. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See https://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up +# to that level are automatically included in the table of contents, even if +# they do not have an id attribute. +# Note: This feature currently applies only to Markdown headings. +# Minimum value: 0, maximum value: 99, default value: 5. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +TOC_INCLUDE_HEADINGS = 5 + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +# The NUM_PROC_THREADS specifies the number threads doxygen is allowed to use +# during processing. When set to 0 doxygen will based this on the number of +# cores available in the system. You can set it explicitly to a value larger +# than 0 to get more control over the balance between CPU load and processing +# speed. At this moment only the input processing can be done using multiple +# threads. Since this is still an experimental feature the default is set to 1, +# which effectively disables parallel processing. Please report any issues you +# encounter. Generating dot graphs in parallel is controlled by the +# DOT_NUM_THREADS setting. +# Minimum value: 0, maximum value: 32, default value: 1. + +NUM_PROC_THREADS = 1 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual +# methods of a class will be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIV_VIRTUAL = NO + +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. If set to YES, local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO, only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If this flag is set to YES, the name of an unnamed parameter in a declaration +# will be determined by the corresponding definition. By default unnamed +# parameters remain unnamed in the output. +# The default value is: YES. + +RESOLVE_UNNAMED_PARAMS = YES + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = YES + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO, these classes will be included in the various overviews. This option +# has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = YES + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# declarations. If set to NO, these declarations will be included in the +# documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = YES + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO, these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = YES + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# With the correct setting of option CASE_SENSE_NAMES doxygen will better be +# able to match the capabilities of the underlying filesystem. In case the +# filesystem is case sensitive (i.e. it supports files in the same directory +# whose names only differ in casing), the option must be set to YES to properly +# deal with such files in case they appear in the input. For filesystems that +# are not case sensitive the option should be be set to NO to properly deal with +# output files written for symbols that only differ in casing, such as for two +# classes, one named CLASS and the other named Class, and to also support +# references to files without having to specify the exact matching casing. On +# Windows (including Cygwin) and MacOS, users should typically set this option +# to NO, whereas on Linux or other Unix flavors it should typically be set to +# YES. +# The default value is: system dependent. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES, the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = NO + +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO + +# If the SHOW_HEADERFILE tag is set to YES then the documentation for a class +# will show which file needs to be included to use the class. +# The default value is: YES. + +SHOW_HEADERFILE = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = NO + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if ... \endif and \cond +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES, the +# list will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = NO + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = NO + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. See also section "Changing the +# layout of pages" for information. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. See also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as documenting some parameters in +# a documented function twice, or documenting parameters that don't exist or +# using markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# If WARN_IF_INCOMPLETE_DOC is set to YES, doxygen will warn about incomplete +# function parameter documentation. If set to NO, doxygen will accept that some +# parameters have no documentation without warning. +# The default value is: YES. + +WARN_IF_INCOMPLETE_DOC = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO, doxygen will only warn about wrong parameter +# documentation, but not about the absence of documentation. If EXTRACT_ALL is +# set to YES then this flag will automatically be disabled. See also +# WARN_IF_INCOMPLETE_DOC +# The default value is: NO. + +WARN_NO_PARAMDOC = NO + +# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when +# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS +# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but +# at the end of the doxygen process doxygen will return with a non-zero status. +# Possible values are: NO, YES and FAIL_ON_WARNINGS. +# The default value is: NO. + +WARN_AS_ERROR = NO + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). In case the file specified cannot be opened for writing the +# warning and error messages are written to standard error. When as file - is +# specified the warning and error messages are written to standard output +# (stdout). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING +# Note: If this tag is empty the current directory is searched. + +INPUT = ../src + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: +# https://www.gnu.org/software/libiconv/) for the list of possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# Note the list of default checked file patterns might differ from the list of +# default file extension mappings. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, +# *.hh, *.hxx, *.hpp, *.h++, *.l, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, +# *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C +# comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, +# *.vhdl, *.ucf, *.qsf and *.ice. + +FILE_PATTERNS = *.h + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = YES + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = */HADictionary.* */mocks/* + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# ANamespace::AClass, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = ARDUINOHA_* HADEVICE* HAMQTT* + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# +# +# where is the value of the INPUT_FILTER tag, and is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# entity all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see https://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = NO + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). For an example see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the style sheet and background images according to +# this color. Hue is specified as an angle on a color-wheel, see +# https://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use gray-scales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to YES can help to show when doxygen was last run and thus if the +# documentation is up to date. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = NO + +# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML +# documentation will contain a main index with vertical navigation menus that +# are dynamically created via JavaScript. If disabled, the navigation index will +# consists of multiple levels of tabs that are statically embedded in every HTML +# page. Disable this option to support browsers that do not have JavaScript, +# like the Qt help browser. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_MENUS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: +# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To +# create a documentation set, doxygen will generate a Makefile in the HTML +# output directory. Running make will produce the docset in that directory and +# running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy +# genXcode/_index.html for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag determines the URL of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDURL = + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# on Windows. In the beginning of 2021 Microsoft took the original page, with +# a.o. the download links, offline the HTML help workshop was already many years +# in maintenance mode). You can download the HTML help workshop from the web +# archives at Installation executable (see: +# http://web.archive.org/web/20160201063255/http://download.microsoft.com/downlo +# ad/0/A/9/0A939EF6-E31C-430F-A3DF-DFAE7960D564/htmlhelp.exe). +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler (hhc.exe). If non-empty, +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the main .chm file (NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location (absolute path +# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to +# run qhelpgenerator on the generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can +# further fine tune the look of the index (see "Fine-tuning the output"). As an +# example, the default style sheet generated by doxygen has an example that +# shows how to put an image at the root of the tree instead of the PROJECT_NAME. +# Since the tree basically has the same information as the tab index, you could +# consider setting DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = NO + +# When both GENERATE_TREEVIEW and DISABLE_INDEX are set to YES, then the +# FULL_SIDEBAR option determines if the side bar is limited to only the treeview +# area (value NO) or if it should extend to the full height of the window (value +# YES). Setting this to YES gives a layout similar to +# https://docs.readthedocs.io with more room for contents, but less room for the +# project logo, title, and description. If either GENERATE_TREEVIEW or +# DISABLE_INDEX is set to NO, this option has no effect. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FULL_SIDEBAR = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# If the OBFUSCATE_EMAILS tag is set to YES, doxygen will obfuscate email +# addresses. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +OBFUSCATE_EMAILS = YES + +# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg +# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see +# https://inkscape.org) to generate formulas as SVG images instead of PNGs for +# the HTML output. These images will generally look nicer at scaled resolutions. +# Possible values are: png (the default) and svg (looks nicer but requires the +# pdf2svg or inkscape tool). +# The default value is: png. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FORMULA_FORMAT = png + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANSPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_TRANSPARENT = YES + +# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands +# to create new LaTeX commands to be used in formulas as building blocks. See +# the section "Including formulas" for details. + +FORMULA_MACROFILE = + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# https://www.mathjax.org) which uses client side JavaScript for the rendering +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# With MATHJAX_VERSION it is possible to specify the MathJax version to be used. +# Note that the different versions of MathJax have different requirements with +# regards to the different settings, so it is possible that also other MathJax +# settings have to be changed when switching between the different MathJax +# versions. +# Possible values are: MathJax_2 and MathJax_3. +# The default value is: MathJax_2. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_VERSION = MathJax_2 + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. For more details about the output format see MathJax +# version 2 (see: +# http://docs.mathjax.org/en/v2.7-latest/output.html) and MathJax version 3 +# (see: +# http://docs.mathjax.org/en/latest/web/components/output.html). +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility. This is the name for Mathjax version 2, for MathJax version 3 +# this will be translated into chtml), NativeMML (i.e. MathML. Only supported +# for NathJax 2. For MathJax version 3 chtml will be used instead.), chtml (This +# is the name for Mathjax version 3, for MathJax version 2 this will be +# translated into HTML-CSS) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from https://www.mathjax.org before deployment. The default value is: +# - in case of MathJax version 2: https://cdn.jsdelivr.net/npm/mathjax@2 +# - in case of MathJax version 3: https://cdn.jsdelivr.net/npm/mathjax@3 +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# for MathJax version 2 (see https://docs.mathjax.org/en/v2.7-latest/tex.html +# #tex-and-latex-extensions): +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# For example for MathJax version 3 (see +# http://docs.mathjax.org/en/latest/input/tex/extensions/index.html): +# MATHJAX_EXTENSIONS = ams +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: +# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use + S +# (what the is depends on the OS and browser, but it is typically +# , /