diff --git a/.gitignore b/.gitignore
index 293347b3..6d487764 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,3 +7,4 @@
.vscode/ipch
build_output
src/GUI-Generic.ino.cpp
+.project
diff --git a/fr.h b/fr.h
new file mode 100644
index 00000000..d127405a
--- /dev/null
+++ b/fr.h
@@ -0,0 +1,105 @@
+#ifndef _LANGUAGE_FR_S_H_
+#define _LANGUAGE_FR_S_H_
+
+// translated by Fryga
+#define S_SETTING_WIFI_SSID "Mettre à jour du WIFI"
+#define S_WIFI_SSID "Nom du WIFI"
+#define S_WIFI_PASS "Mot de passe"
+#define S_HOST_NAME "Nom du module"
+#define S_SETTING_SUPLA "Paramètres SUPLA"
+#define S_SUPLA_SERVER "Adresse du serveur"
+#define S_SUPLA_EMAIL "E-mail"
+#define S_SETTING_ADMIN "Paramètres administrateur"
+#define S_LOGIN "Connexion"
+#define S_LOGIN_PASS "Mot de passe"
+#define S_ROLLERSHUTTERS "Volet roulant"
+#define S_SAVE "Enregistrer"
+#define S_DEVICE_SETTINGS "Paramètres du module"
+#define S_UPDATE "Mettre à jour"
+#define S_RESTART "Réinitialisation"
+#define S_RETURN "Retour"
+#define S_TEMPLATE_BOARD "Modèle de la planches"
+#define S_TYPE "Genre"
+#define S_RELAYS "LES RELAIS"
+#define S_BUTTONS "LES BOUTONS"
+#define S_SENSORS_1WIRE "LES SENSORS du 1Wire"
+#define S_SENSORS_I2C "LES SENSORS du i2c"
+#define S_SENSORS_SPI "LES SENSORS du SPI"
+#define S_LED_BUTTON_CFG "LED, BOUTON metre à jour"
+#define S_QUANTITY "Quantité"
+#define S_GPIO_SETTINGS_FOR_RELAYS "Paramètres du GPIO pour les relais"
+#define S_RELAY "LE RELAIS"
+#define S_RELAY_NR_SETTINGS "Paramètres de la relais No."
+#define S_NO_RELAY_NR "Manquant numéro de relais"
+#define S_STATE_CONTROL "Contrôle d'état"
+#define S_REACTION_AFTER_RESET "Réaction après réinitialisation"
+#define S_GPIO_SETTINGS_FOR_BUTTONS "Paramètres GPIO pour les boutons"
+#define S_BUTTON "BOUTON"
+#define S_BUTTON_NR_SETTINGS "Bouton mettre à jour"
+#define S_NO_BUTTON_NR "Manquant numéro de bouton"
+#define S_REACTION_TO "Réaction à"
+#define S_GPIO_SETTINGS_FOR_LIMIT_SWITCH "Paramètres GPIO pour capteur de limite"
+#define S_LIMIT_SWITCH "Capteur de limite"
+#define S_GPIO_SETTINGS_FOR "GPIO mettre à jour pour"
+#define S_FOUND "Trouvé"
+#define S_NO_SENSORS_CONNECTED "Aucun capteur connecté"
+#define S_SAVE_FOUND "Enregistrer trouvé"
+#define S_TEMPERATURE "Température"
+#define S_NAME "Nom"
+#define S_ALTITUDE_ABOVE_SEA_LEVEL "Altitude"
+#define S_GPIO_SETTINGS_FOR_CONFIG "Paramètres GPIO pour la à jour"
+#define S_SOFTWARE_UPDATE "Mise à jour du logiciel"
+#define S_DATA_SAVED "Données enregistrées"
+#define S_RESTART_MODULE "Redémarrer le module"
+#define S_DATA_ERASED_RESTART_DEVICE "Données effacées - redémarrer le module"
+#define S_WRITE_ERROR_UNABLE_TO_READ_FILE_FS_PARTITION_MISSING "Erreur d'écriture - impossible de lire à partir du fichier FS. Partition manquante"
+#define S_DATA_SAVED_RESTART_MODULE "Données enregistrées - redémarrer le module"
+#define S_WRITE_ERROR_BAD_DATA "Erreur d'écriture - données incorrectes"
+
+//#### SuplaConfigESP.cpp ####
+#define S_ALEREADY_INITIATED "Déjà lancé"
+#define S_NOT_ASSIGNED_CB "CB non attribué"
+#define S_INVALID_GUID_OR_DEVICE_REGISTRATION_INACTIVE "GUID non valide ou enregistrement de l'appareil INACTIF"
+#define S_UNKNOWN_SEVER_ADDRESS "Adresse de serveur inconnue"
+#define S_UNKNOWN_ID "ID inconnu"
+#define S_INITIATED "Initié"
+#define S_CHANNEL_LIMIT_EXCEEDED "Limite de canal dépassée"
+#define S_DISCONNECTED "Déconnecté"
+#define S_REGISRATION_IS_PENDING "L'enregistrement est en attente"
+#define S_VARIABLE_ERROR "Erreur de variable"
+#define S_PROTOCOL_VERSION_ERROR "Erreur de version de protocole"
+#define S_BAD_CREDENTIALS "Informations d'identification incorrectes"
+#define S_TEMPORARILY_UNAVAILABLE "Temporairement indisponible"
+#define S_LOCATION_CONFLICT "Conflit d'emplacement"
+#define S_CHANNEL_CONFLICT "Conflit de canal"
+#define S_REGISTERED_AND_READY "Enregistré et prêt"
+#define S_DEVICE_IS_DISCONNECTED "L'appareil est déconnecté"
+#define S_LOCATION_IS_DISABLED "L'emplacement est désactivé"
+#define S_DEVICE_LIMIT_EXCEEDED "Limite d'appareils dépassée"
+
+// #### SuplaCommonPROGMEM.h ####
+#define S_OFF "ÉTEINDRE"
+#define S_ON "ALLUMER"
+#define S_LOW "BASSE"
+#define S_HIGH "HAUT"
+#define S_POSITION_MEMORY "MEMOIRE DE POSITION"
+#define S_REACTION_ON_PRESS "ON PRESSE"
+#define S_REACTION_ON_RELEASE "EN LIBÉRATION"
+#define S_REACTION_ON_CHANGE "SUR LE CHANGEMENT"
+#define S_CFG_10_PRESSES "10 FOIS SUR PRESSE"
+#define S_5SEK_HOLD "5 SEC TENIR"
+
+// #### SuplaTemplateBoard.h ####
+#define S_ABSENT "ABSENT"
+
+// #### SuplaWebPageSensor.cpp ####
+#define S_IMPULSE_COUNTER "Compteur d'impulsions"
+#define S_IMPULSE_COUNTER_DEBOUNCE_TIMEOUT "Délai anti-rebond"
+#define S_IMPULSE_COUNTER_RAISING_EDGE "Bord montant"
+#define S_IMPULSE_COUNTER_PULL_UP "Remonter"
+#define S_IMPULSE_COUNTER_CHANGE_VALUE "Modifier la valeur"
+#define S_IMPULSE_COUNTER_SETTINGS_NR "Paramètres Compteur d'impulsions No."
+#define S_NO_IMPULSE_COUNTER_NR "Aucun Compteur d'impulsions No."
+
+
+#endif // _LANGUAGE_FR_S_H_
\ No newline at end of file
diff --git a/lib/SuplaDevice/.drone.yml b/lib/SuplaDevice/.drone.yml
new file mode 100644
index 00000000..688641c7
--- /dev/null
+++ b/lib/SuplaDevice/.drone.yml
@@ -0,0 +1,17 @@
+kind: pipeline
+name: default
+
+steps:
+- name: compilation
+ image: rikorose/gcc-cmake
+ commands:
+ - mkdir extras/test/build
+ - cd extras/test/build
+ - cmake ..
+ - make
+
+- name: test
+ image: rikorose/gcc-cmake
+ commands:
+ - cd extras/test/build
+ - ./supladevicetests
diff --git a/lib/SuplaDevice/.gitignore b/lib/SuplaDevice/.gitignore
new file mode 100644
index 00000000..dcd241ea
--- /dev/null
+++ b/lib/SuplaDevice/.gitignore
@@ -0,0 +1 @@
+extras/test/build/
diff --git a/lib/SuplaDevice/.travis.yml b/lib/SuplaDevice/.travis.yml
new file mode 100644
index 00000000..bd33cea0
--- /dev/null
+++ b/lib/SuplaDevice/.travis.yml
@@ -0,0 +1,18 @@
+os: linux
+dist: xenial
+sudo: false
+language: cpp
+
+addons:
+ apt:
+ sources:
+ - ubuntu-toolchain-r-test
+ packages:
+ - g++-6
+
+script:
+ - mkdir extras/test/build
+ - cd extras/test/build
+ - CXX=/usr/bin/g++-6 CC=/usr/bin/gcc-6 cmake ..
+ - make
+ - ./supladevicetests
diff --git a/lib/SuplaDevice/LICENSE b/lib/SuplaDevice/LICENSE
new file mode 100644
index 00000000..23cb7903
--- /dev/null
+++ b/lib/SuplaDevice/LICENSE
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ 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
+this service 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.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+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
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the 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 a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE 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.
+
+ 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
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ {description}
+ Copyright (C) {year} {fullname}
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ {signature of Ty Coon}, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/lib/SuplaDevice/_clang-format b/lib/SuplaDevice/_clang-format
new file mode 100644
index 00000000..5915a3e9
--- /dev/null
+++ b/lib/SuplaDevice/_clang-format
@@ -0,0 +1,91 @@
+---
+Language: Cpp
+BasedOnStyle: Google
+AccessModifierOffset: -1
+AlignAfterOpenBracket: Align
+AlignConsecutiveAssignments: false
+AlignConsecutiveDeclarations: false
+AlignConsecutiveMacros: true
+AlignEscapedNewlinesLeft: true
+AlignOperands: true
+AlignTrailingComments: true
+AllowAllParametersOfDeclarationOnNextLine: true
+AllowShortBlocksOnASingleLine: Never
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: None
+AllowShortIfStatementsOnASingleLine: true
+AllowShortLoopsOnASingleLine: true
+AlwaysBreakAfterDefinitionReturnType: None
+AlwaysBreakAfterReturnType: None
+AlwaysBreakBeforeMultilineStrings: true
+AlwaysBreakTemplateDeclarations: true
+BinPackArguments: false
+BinPackParameters: false
+BraceWrapping:
+ AfterClass: false
+ AfterControlStatement: false
+ AfterEnum: false
+ AfterFunction: false
+ AfterNamespace: false
+ AfterObjCDeclaration: false
+ AfterStruct: false
+ AfterUnion: false
+ BeforeCatch: false
+ BeforeElse: false
+ IndentBraces: false
+BreakBeforeBinaryOperators: None
+BreakBeforeBraces: Attach
+BreakBeforeTernaryOperators: true
+BreakConstructorInitializersBeforeComma: false
+ColumnLimit: 80
+CommentPragmas: '^ IWYU pragma:'
+ConstructorInitializerAllOnOneLineOrOnePerLine: true
+ConstructorInitializerIndentWidth: 4
+ContinuationIndentWidth: 4
+Cpp11BracedListStyle: true
+DerivePointerAlignment: true
+DisableFormat: false
+ExperimentalAutoDetectBinPacking: false
+ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
+IncludeCategories:
+ - Regex: '^<.*\.h>'
+ Priority: 1
+ - Regex: '^<.*'
+ Priority: 2
+ - Regex: '.*'
+ Priority: 3
+IndentCaseLabels: true
+IndentWidth: 2
+IndentWrappedFunctionNames: false
+KeepEmptyLinesAtTheStartOfBlocks: false
+MacroBlockBegin: ''
+MacroBlockEnd: ''
+MaxEmptyLinesToKeep: 1
+NamespaceIndentation: None
+ObjCBlockIndentWidth: 2
+ObjCSpaceAfterProperty: false
+ObjCSpaceBeforeProtocolList: false
+PenaltyBreakBeforeFirstCallParameter: 1
+PenaltyBreakComment: 300
+PenaltyBreakFirstLessLess: 120
+PenaltyBreakString: 1000
+PenaltyExcessCharacter: 1000000
+PenaltyReturnTypeOnItsOwnLine: 200
+PointerAlignment: Left
+ReflowComments: true
+SortIncludes: true
+SpaceAfterCStyleCast: false
+SpaceBeforeAssignmentOperators: true
+SpaceBeforeParens: ControlStatements
+SpaceInEmptyParentheses: false
+SpacesBeforeTrailingComments: 2
+SpacesInAngles: false
+SpacesInContainerLiterals: true
+SpacesInCStyleCastParentheses: false
+SpacesInParentheses: false
+SpacesInSquareBrackets: false
+Standard: Auto
+TabWidth: 8
+UseTab: Never
+...
+
diff --git a/lib/SuplaDevice/_config.yml b/lib/SuplaDevice/_config.yml
new file mode 100644
index 00000000..c4192631
--- /dev/null
+++ b/lib/SuplaDevice/_config.yml
@@ -0,0 +1 @@
+theme: jekyll-theme-cayman
\ No newline at end of file
diff --git a/lib/SuplaDevice/examples/Afore/Afore.ino b/lib/SuplaDevice/examples/Afore/Afore.ino
index eaace6d9..859636c9 100644
--- a/lib/SuplaDevice/examples/Afore/Afore.ino
+++ b/lib/SuplaDevice/examples/Afore/Afore.ino
@@ -14,28 +14,25 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-#include
#include
#include
// Choose proper network interface for your card:
-// Arduino Mega with EthernetShield W5100:
-#include
-// Ethernet MAC address
-uint8_t mac[6] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05};
-Supla::EthernetShield ethernet(mac);
-//
-// Arduino Mega with ENC28J60:
-// #include
-// Supla::ENC28J60 ethernet(mac);
-//
-// ESP8266 based board:
-// #include
-// Supla::ESPWifi wifi("your_wifi_ssid", "your_wifi_password");
-//
-// ESP32 based board:
-// #include
-// Supla::ESP32Wifi wifi("your_wifi_ssid", "your_wifi_password");
+#ifdef ARDUINO_ARCH_AVR
+ // Arduino Mega with EthernetShield W5100:
+ #include
+ // Ethernet MAC address
+ uint8_t mac[6] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05};
+ Supla::EthernetShield ethernet(mac);
+
+ // Arduino Mega with ENC28J60:
+ // #include
+ // Supla::ENC28J60 ethernet(mac);
+#elif defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
+ // ESP8266 and ESP32 based board:
+ #include
+ Supla::ESPWifi wifi("your_wifi_ssid", "your_wifi_password");
+#endif
void setup() {
diff --git a/lib/SuplaDevice/examples/DHT/DHT.ino b/lib/SuplaDevice/examples/DHT/DHT.ino
index b91c0fea..e0c85e2a 100644
--- a/lib/SuplaDevice/examples/DHT/DHT.ino
+++ b/lib/SuplaDevice/examples/DHT/DHT.ino
@@ -14,28 +14,25 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-#include
#include
#include
// Choose proper network interface for your card:
-// Arduino Mega with EthernetShield W5100:
-#include
-// Ethernet MAC address
-uint8_t mac[6] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05};
-Supla::EthernetShield ethernet(mac);
-//
-// Arduino Mega with ENC28J60:
-// #include
-// Supla::ENC28J60 ethernet(mac);
-//
-// ESP8266 based board:
-// #include
-// Supla::ESPWifi wifi("your_wifi_ssid", "your_wifi_password");
-//
-// ESP32 based board:
-// #include
-// Supla::ESP32Wifi wifi("your_wifi_ssid", "your_wifi_password");
+#ifdef ARDUINO_ARCH_AVR
+ // Arduino Mega with EthernetShield W5100:
+ #include
+ // Ethernet MAC address
+ uint8_t mac[6] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05};
+ Supla::EthernetShield ethernet(mac);
+
+ // Arduino Mega with ENC28J60:
+ // #include
+ // Supla::ENC28J60 ethernet(mac);
+#elif defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
+ // ESP8266 and ESP32 based board:
+ #include
+ Supla::ESPWifi wifi("your_wifi_ssid", "your_wifi_password");
+#endif
/*
* This example requires DHT sensor library installed.
@@ -49,7 +46,7 @@ Supla::EthernetShield ethernet(mac);
void setup() {
- Serial.begin(9600);
+ Serial.begin(115200);
// Replace the falowing GUID with value that you can retrieve from https://www.supla.org/arduino/get-guid
char GUID[SUPLA_GUID_SIZE] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
diff --git a/lib/SuplaDevice/examples/DallasTemperature/DallasTemperature.ino b/lib/SuplaDevice/examples/DallasTemperature/DallasTemperature.ino
index f10308df..81eb8fbc 100644
--- a/lib/SuplaDevice/examples/DallasTemperature/DallasTemperature.ino
+++ b/lib/SuplaDevice/examples/DallasTemperature/DallasTemperature.ino
@@ -14,7 +14,6 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-#include
#include
/*
@@ -26,27 +25,25 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
// Choose proper network interface for your card:
-// Arduino Mega with EthernetShield W5100:
-#include
-// Ethernet MAC address
-uint8_t mac[6] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05};
-Supla::EthernetShield ethernet(mac);
-//
-// Arduino Mega with ENC28J60:
-// #include
-// Supla::ENC28J60 ethernet(mac);
-//
-// ESP8266 based board:
-// #include
-// Supla::ESPWifi wifi("your_wifi_ssid", "your_wifi_password");
-//
-// ESP32 based board:
-// #include
-// Supla::ESP32Wifi wifi("your_wifi_ssid", "your_wifi_password");
+#ifdef ARDUINO_ARCH_AVR
+ // Arduino Mega with EthernetShield W5100:
+ #include
+ // Ethernet MAC address
+ uint8_t mac[6] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05};
+ Supla::EthernetShield ethernet(mac);
+
+ // Arduino Mega with ENC28J60:
+ // #include
+ // Supla::ENC28J60 ethernet(mac);
+#elif defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
+ // ESP8266 and ESP32 based board:
+ #include
+ Supla::ESPWifi wifi("your_wifi_ssid", "your_wifi_password");
+#endif
void setup() {
- Serial.begin(9600);
+ Serial.begin(115200);
// Replace the falowing GUID with value that you can retrieve from https://www.supla.org/arduino/get-guid
char GUID[SUPLA_GUID_SIZE] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
diff --git a/lib/SuplaDevice/examples/Fronius/Fronius.ino b/lib/SuplaDevice/examples/Fronius/Fronius.ino
index 98b3b7ad..27cc0e75 100644
--- a/lib/SuplaDevice/examples/Fronius/Fronius.ino
+++ b/lib/SuplaDevice/examples/Fronius/Fronius.ino
@@ -14,28 +14,25 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-#include
#include
#include
// Choose proper network interface for your card:
-// Arduino Mega with EthernetShield W5100:
-#include
-// Ethernet MAC address
-uint8_t mac[6] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05};
-Supla::EthernetShield ethernet(mac);
-//
-// Arduino Mega with ENC28J60:
-// #include
-// Supla::ENC28J60 ethernet(mac);
-//
-// ESP8266 based board:
-// #include
-// Supla::ESPWifi wifi("your_wifi_ssid", "your_wifi_password");
-//
-// ESP32 based board:
-// #include
-// Supla::ESP32Wifi wifi("your_wifi_ssid", "your_wifi_password");
+#ifdef ARDUINO_ARCH_AVR
+ // Arduino Mega with EthernetShield W5100:
+ #include
+ // Ethernet MAC address
+ uint8_t mac[6] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05};
+ Supla::EthernetShield ethernet(mac);
+
+ // Arduino Mega with ENC28J60:
+ // #include
+ // Supla::ENC28J60 ethernet(mac);
+#elif defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
+ // ESP8266 and ESP32 based board:
+ #include
+ Supla::ESPWifi wifi("your_wifi_ssid", "your_wifi_password");
+#endif
void setup() {
diff --git a/lib/SuplaDevice/examples/GarageParkingAssistLight/GarageParkingAssistLight.ino b/lib/SuplaDevice/examples/GarageParkingAssistLight/GarageParkingAssistLight.ino
new file mode 100644
index 00000000..76c4e2d8
--- /dev/null
+++ b/lib/SuplaDevice/examples/GarageParkingAssistLight/GarageParkingAssistLight.ino
@@ -0,0 +1,94 @@
+/*
+Copyright (C) AC SOFTWARE SP. Z O.O.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+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 General Public License for more details.
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include
+
+// Add include to HC_SR04 sensor
+#include
+#include
+#include
+
+// Choose proper network interface for your card:
+#ifdef ARDUINO_ARCH_AVR
+ // Arduino Mega with EthernetShield W5100:
+ #include
+ // Ethernet MAC address
+ uint8_t mac[6] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05};
+ Supla::EthernetShield ethernet(mac);
+
+ // Arduino Mega with ENC28J60:
+ // #include
+ // Supla::ENC28J60 ethernet(mac);
+#elif defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
+ // ESP8266 and ESP32 based board:
+ #include
+ Supla::ESPWifi wifi("your_wifi_ssid", "your_wifi_password");
+#endif
+
+void setup() {
+
+ Serial.begin(115200);
+
+ // Replace the falowing GUID with value that you can retrieve from https://www.supla.org/arduino/get-guid
+ char GUID[SUPLA_GUID_SIZE] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+
+ // Replace the following AUTHKEY with value that you can retrieve from: https://www.supla.org/arduino/get-authkey
+ char AUTHKEY[SUPLA_AUTHKEY_SIZE] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+
+ /*
+ * Having your device already registered at cloud.supla.org,
+ * you want to change CHANNEL sequence or remove any of them,
+ * then you must also remove the device itself from cloud.supla.org.
+ * Otherwise you will get "Channel conflict!" error.
+ */
+
+
+ auto distance = new Supla::Sensor::HC_SR04(12,13);//(trigPin, echoPin)
+
+ auto redLight = new Supla::Control::Relay(22);
+ auto orangeLight = new Supla::Control::Relay(23);
+ auto greenLight = new Supla::Control::Relay(24);
+
+ distance->addAction(Supla::TURN_ON, redLight, OnLess(0.40));
+ distance->addAction(Supla::TURN_ON, orangeLight, OnBetween(0.40, 0.80));
+ distance->addAction(Supla::TURN_ON, greenLight, OnBetween(0.80, 1.50));
+
+ distance->addAction(Supla::TURN_OFF, orangeLight, OnLess(0.35));
+ distance->addAction(Supla::TURN_OFF, greenLight, OnLess(0.75));
+
+ distance->addAction(Supla::TURN_OFF, redLight, OnGreater(0.45));
+ distance->addAction(Supla::TURN_OFF, orangeLight, OnGreater(0.85));
+ distance->addAction(Supla::TURN_OFF, greenLight, OnGreater(1.55));
+
+ /*
+ * SuplaDevice Initialization.
+ * Server address is available at https://cloud.supla.org
+ * If you do not have an account, you can create it at https://cloud.supla.org/account/create
+ * SUPLA and SUPLA CLOUD are free of charge
+ *
+ */
+
+ SuplaDevice.begin(GUID, // Global Unique Identifier
+ "svr1.supla.org", // SUPLA server address
+ "email@address", // Email address used to login to Supla Cloud
+ AUTHKEY); // Authorization key
+
+}
+
+void loop() {
+ SuplaDevice.iterate();
+}
+
diff --git a/lib/SuplaDevice/examples/HC_SR04_Distance_sensor/HC_SR04_Distance_sensor.ino b/lib/SuplaDevice/examples/HC_SR04_Distance_sensor/HC_SR04_Distance_sensor.ino
index 2de1ac58..0bb45c39 100644
--- a/lib/SuplaDevice/examples/HC_SR04_Distance_sensor/HC_SR04_Distance_sensor.ino
+++ b/lib/SuplaDevice/examples/HC_SR04_Distance_sensor/HC_SR04_Distance_sensor.ino
@@ -14,7 +14,6 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-#include
#include
// Add include to HC_SR04 sensor
@@ -22,27 +21,25 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
// Choose proper network interface for your card:
-// Arduino Mega with EthernetShield W5100:
-#include
-// Ethernet MAC address
-uint8_t mac[6] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05};
-Supla::EthernetShield ethernet(mac);
-//
-// Arduino Mega with ENC28J60:
-// #include
-// Supla::ENC28J60 ethernet(mac);
-//
-// ESP8266 based board:
-// #include
-// Supla::ESPWifi wifi("your_wifi_ssid", "your_wifi_password");
-//
-// ESP32 based board:
-// #include
-// Supla::ESP32Wifi wifi("your_wifi_ssid", "your_wifi_password");
+#ifdef ARDUINO_ARCH_AVR
+ // Arduino Mega with EthernetShield W5100:
+ #include
+ // Ethernet MAC address
+ uint8_t mac[6] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05};
+ Supla::EthernetShield ethernet(mac);
+
+ // Arduino Mega with ENC28J60:
+ // #include
+ // Supla::ENC28J60 ethernet(mac);
+#elif defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
+ // ESP8266 and ESP32 based board:
+ #include
+ Supla::ESPWifi wifi("your_wifi_ssid", "your_wifi_password");
+#endif
void setup() {
- Serial.begin(9600);
+ Serial.begin(115200);
// Replace the falowing GUID with value that you can retrieve from https://www.supla.org/arduino/get-guid
char GUID[SUPLA_GUID_SIZE] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
@@ -63,7 +60,7 @@ void setup() {
/*
* SuplaDevice Initialization.
- * Server address, LocationID and LocationPassword are available at https://cloud.supla.org
+ * Server address is available at https://cloud.supla.org
* If you do not have an account, you can create it at https://cloud.supla.org/account/create
* SUPLA and SUPLA CLOUD are free of charge
*
diff --git a/lib/SuplaDevice/examples/HC_SR04_Distance_sensor_extended/HC_SR04_Distance_sensor_extended.ino b/lib/SuplaDevice/examples/HC_SR04_Distance_sensor_extended/HC_SR04_Distance_sensor_extended.ino
new file mode 100644
index 00000000..eb0d8503
--- /dev/null
+++ b/lib/SuplaDevice/examples/HC_SR04_Distance_sensor_extended/HC_SR04_Distance_sensor_extended.ino
@@ -0,0 +1,85 @@
+/*
+Copyright (C) AC SOFTWARE SP. Z O.O.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+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 General Public License for more details.
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include
+
+// Add include to HC_SR04 sensor
+#include
+
+// Choose proper network interface for your card:
+#ifdef ARDUINO_ARCH_AVR
+ // Arduino Mega with EthernetShield W5100:
+ #include
+ // Ethernet MAC address
+ uint8_t mac[6] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05};
+ Supla::EthernetShield ethernet(mac);
+
+ // Arduino Mega with ENC28J60:
+ // #include
+ // Supla::ENC28J60 ethernet(mac);
+#elif defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
+ // ESP8266 and ESP32 based board:
+ #include
+ Supla::ESPWifi wifi("your_wifi_ssid", "your_wifi_password");
+#endif
+
+int8_t trigPin = 13;
+int8_t echoPin = 12;
+int16_t minSensorRead = 5; //minimum sensor reading distance in centimeters
+int16_t maxSensorRead = 55; //maximum sensor reading distance in centimeters
+int16_t minAppReading = 50; //minimum distance shown by the App in centimeters when sensor read <= min_sensor_read
+int16_t maxAppReading = 0; //maximum distance shown by the App in centimeters when sensor read >= max_sensor_read
+
+void setup() {
+
+ Serial.begin(115200);
+
+ // Replace the falowing GUID with value that you can retrieve from https://www.supla.org/arduino/get-guid
+ char GUID[SUPLA_GUID_SIZE] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+
+ // Replace the following AUTHKEY with value that you can retrieve from: https://www.supla.org/arduino/get-authkey
+ char AUTHKEY[SUPLA_AUTHKEY_SIZE] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+
+ /*
+ * Having your device already registered at cloud.supla.org,
+ * you want to change CHANNEL sequence or remove any of them,
+ * then you must also remove the device itself from cloud.supla.org.
+ * Otherwise you will get "Channel conflict!" error.
+ */
+
+ new Supla::Sensor::HC_SR04(trigPin,echoPin, minSensorRead, maxSensorRead, minAppReading, maxAppReading);
+
+ // Supla::Sensor::HC_SR04(trigPin, echoPin) // sends sensor reading to cloud unchanged
+
+
+ /*
+ * SuplaDevice Initialization.
+ * Server address is available at https://cloud.supla.org
+ * If you do not have an account, you can create it at https://cloud.supla.org/account/create
+ * SUPLA and SUPLA CLOUD are free of charge
+ *
+ */
+
+ SuplaDevice.begin(GUID, // Global Unique Identifier
+ "svrX.supla.org", // SUPLA server address
+ "email@address", // Email address used to login to Supla Cloud
+ AUTHKEY); // Authorization key
+
+}
+
+void loop() {
+ SuplaDevice.iterate();
+}
diff --git a/lib/SuplaDevice/examples/ImpulseCounter/ImpulseCounter.ino b/lib/SuplaDevice/examples/ImpulseCounter/ImpulseCounter.ino
index 5035b970..e2949220 100644
--- a/lib/SuplaDevice/examples/ImpulseCounter/ImpulseCounter.ino
+++ b/lib/SuplaDevice/examples/ImpulseCounter/ImpulseCounter.ino
@@ -14,9 +14,11 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-#include
#include
#include
+// Remove below line if you don't want to have internal LED blinking on each impulse
+#include
+#include
// Choose where Supla should store counter data in persistant memory
// We recommend to use external FRAM memory
@@ -26,29 +28,26 @@ Supla::Eeprom eeprom(STORAGE_OFFSET);
// #include
// Supla::FramSpi fram(STORAGE_OFFSET);
-
// Choose proper network interface for your card:
-// Arduino Mega with EthernetShield W5100:
-#include
-// Ethernet MAC address
-uint8_t mac[6] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05};
-Supla::EthernetShield ethernet(mac);
-//
-// Arduino Mega with ENC28J60:
-// #include
-// Supla::ENC28J60 ethernet(mac);
-//
-// ESP8266 based board:
-// #include
-// Supla::ESPWifi wifi("your_wifi_ssid", "your_wifi_password");
-//
-// ESP32 based board:
-// #include
-// Supla::ESP32Wifi wifi("your_wifi_ssid", "your_wifi_password");
+#ifdef ARDUINO_ARCH_AVR
+ // Arduino Mega with EthernetShield W5100:
+ #include
+ // Ethernet MAC address
+ uint8_t mac[6] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05};
+ Supla::EthernetShield ethernet(mac);
+
+ // Arduino Mega with ENC28J60:
+ // #include
+ // Supla::ENC28J60 ethernet(mac);
+#elif defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
+ // ESP8266 and ESP32 based board:
+ #include
+ Supla::ESPWifi wifi("your_wifi_ssid", "your_wifi_password");
+#endif
void setup() {
- Serial.begin(9600);
+ Serial.begin(115200);
// Replace the falowing GUID with value that you can retrieve from https://www.supla.org/arduino/get-guid
char GUID[SUPLA_GUID_SIZE] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
@@ -64,11 +63,21 @@ void setup() {
*/
// CHANNEL0 - Impulse Counter on pin 34, counting raising edge (from LOW to HIGH), no pullup on pin, and 10 ms debounce timeout
- new Supla::Sensor::ImpulseCounter(34, true, false, 10);
+ auto ic1 = new Supla::Sensor::ImpulseCounter(34, true, false, 10);
// CHANNEL1 - Impulse Counter on pin 35, counting falling edge (from HIGH to LOW), with pullup on pin, and 50 ms debounce timeout
- new Supla::Sensor::ImpulseCounter(35, false, true, 50);
+ auto ic2 = new Supla::Sensor::ImpulseCounter(35, false, true, 50);
+ // Configuring internal LED to notify each change of impulse counter
+ auto led1 = new Supla::Control::InternalPinOutput(24); // LED on pin 24
+ auto led2 = new Supla::Control::InternalPinOutput(25); // LED on pin 25
+
+ // LED1 will blink (100 ms) on each change of ic1
+ led1->setDurationMs(100);
+ ic1->addAction(Supla::TURN_ON, led1, Supla::ON_CHANGE);
+
+ // LED2 will toggle it's state on each change of ic2
+ ic2->addAction(Supla::TOGGLE, led2, Supla::ON_CHANGE);
/*
* Server address is available at https://cloud.supla.org
diff --git a/lib/SuplaDevice/examples/Pzem_V_2/Pzem_V_2.ino b/lib/SuplaDevice/examples/Pzem_V_2/Pzem_V_2.ino
index e03d4aa9..0b8c4918 100644
--- a/lib/SuplaDevice/examples/Pzem_V_2/Pzem_V_2.ino
+++ b/lib/SuplaDevice/examples/Pzem_V_2/Pzem_V_2.ino
@@ -13,24 +13,32 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
- // this example will work only on esp8266 and esp32 boards. On Arduino mega it will not fly.
+
//dependence: Arduino communication library for Peacefair PZEM-004T Energy monitor https://github.com/olehs/PZEM004T
-#include
#include
#include
-// ESP8266 based board:
-#include
-Supla::ESPWifi wifi("your_wifi_ssid", "your_wifi_password");
-//
-// ESP32 based board:
-// #include
-// Supla::ESP32Wifi wifi("your_wifi_ssid", "your_wifi_password");
+// Choose proper network interface for your card:
+#ifdef ARDUINO_ARCH_AVR
+ // Arduino Mega with EthernetShield W5100:
+ #include
+ // Ethernet MAC address
+ uint8_t mac[6] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05};
+ Supla::EthernetShield ethernet(mac);
+
+ // Arduino Mega with ENC28J60:
+ // #include
+ // Supla::ENC28J60 ethernet(mac);
+#elif defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
+ // ESP8266 and ESP32 based board:
+ #include
+ Supla::ESPWifi wifi("your_wifi_ssid", "your_wifi_password");
+#endif
void setup() {
- Serial.begin(9600);
+ Serial.begin(115200);
// Replace the falowing GUID with value that you can retrieve from https://www.supla.org/arduino/get-guid
char GUID[SUPLA_GUID_SIZE] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
diff --git a/lib/SuplaDevice/examples/Pzem_V_3/Pzem_V_3.ino b/lib/SuplaDevice/examples/Pzem_V_3/Pzem_V_3.ino
index fd435453..85fe0bb6 100644
--- a/lib/SuplaDevice/examples/Pzem_V_3/Pzem_V_3.ino
+++ b/lib/SuplaDevice/examples/Pzem_V_3/Pzem_V_3.ino
@@ -13,56 +13,66 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
- // this example will work only on esp8266 and esp32 boards. On Arduino mega it will not fly.
- //dependence: Arduino library for the Updated PZEM-004T v3.0 Power and Energy meter https://github.com/mandulaj/PZEM-004T-v30
-#include
+// dependence: Arduino library for the Updated PZEM-004T v3.0 Power and Energy
+// meter https://github.com/mandulaj/PZEM-004T-v30
+
#include
#include
-// ESP8266 based board:
+// Choose proper network interface for your card:
+#ifdef ARDUINO_ARCH_AVR
+// Arduino Mega with EthernetShield W5100:
+#include
+// Ethernet MAC address
+uint8_t mac[6] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05};
+Supla::EthernetShield ethernet(mac);
+
+// Arduino Mega with ENC28J60:
+// #include
+// Supla::ENC28J60 ethernet(mac);
+#elif defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
+// ESP8266 and ESP32 based board:
#include
Supla::ESPWifi wifi("your_wifi_ssid", "your_wifi_password");
-//
-// ESP32 based board:
-// #include
-// Supla::ESP32Wifi wifi("your_wifi_ssid", "your_wifi_password");
+#endif
void setup() {
+ Serial.begin(115200);
- Serial.begin(9600);
-
- // Replace the falowing GUID with value that you can retrieve from https://www.supla.org/arduino/get-guid
- char GUID[SUPLA_GUID_SIZE] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
-
- // Replace the following AUTHKEY with value that you can retrieve from: https://www.supla.org/arduino/get-authkey
- char AUTHKEY[SUPLA_AUTHKEY_SIZE] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+ // Replace the falowing GUID with value that you can retrieve from
+ // https://www.supla.org/arduino/get-guid
+ char GUID[SUPLA_GUID_SIZE] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
- /*
- * Having your device already registered at cloud.supla.org,
- * you want to change CHANNEL sequence or remove any of them,
- * then you must also remove the device itself from cloud.supla.org.
- * Otherwise you will get "Channel conflict!" error.
- */
-
- new Supla::Sensor::PZEMv3(5, 4); // (RX,TX)
+ // Replace the following AUTHKEY with value that you can retrieve from:
+ // https://www.supla.org/arduino/get-authkey
+ char AUTHKEY[SUPLA_AUTHKEY_SIZE] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ /*
+ * Having your device already registered at cloud.supla.org,
+ * you want to change CHANNEL sequence or remove any of them,
+ * then you must also remove the device itself from cloud.supla.org.
+ * Otherwise you will get "Channel conflict!" error.
+ */
- /*
- * SuplaDevice Initialization.
- * Server address, is available at https://cloud.supla.org
- * If you do not have an account, you can create it at https://cloud.supla.org/account/create
- * SUPLA and SUPLA CLOUD are free of charge
- *
- */
+ new Supla::Sensor::PZEMv3(5, 4); // (RX,TX)
- SuplaDevice.begin(GUID, // Global Unique Identifier
- "svr1.supla.org", // SUPLA server address
- "email@address", // Email address used to login to Supla Cloud
- AUTHKEY); // Authorization key
+ /*
+ * SuplaDevice Initialization.
+ * Server address, is available at https://cloud.supla.org
+ * If you do not have an account, you can create it at
+ * https://cloud.supla.org/account/create SUPLA and SUPLA CLOUD are free of
+ * charge
+ *
+ */
+ SuplaDevice.begin(
+ GUID, // Global Unique Identifier
+ "svr1.supla.org", // SUPLA server address
+ "email@address", // Email address used to login to Supla Cloud
+ AUTHKEY); // Authorization key
}
void loop() {
- SuplaDevice.iterate();
+ SuplaDevice.iterate();
}
diff --git a/lib/SuplaDevice/examples/RGBW/RGBW.ino b/lib/SuplaDevice/examples/RGBW/RGBW.ino
index 994fd701..fb446e08 100644
--- a/lib/SuplaDevice/examples/RGBW/RGBW.ino
+++ b/lib/SuplaDevice/examples/RGBW/RGBW.ino
@@ -14,28 +14,25 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-#include
#include
#include
// Choose proper network interface for your card:
-// Arduino Mega with EthernetShield W5100:
-#include
-// Ethernet MAC address
-uint8_t mac[6] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05};
-Supla::EthernetShield ethernet(mac);
-//
-// Arduino Mega with ENC28J60:
-// #include
-// Supla::ENC28J60 ethernet(mac);
-//
-// ESP8266 based board:
-// #include
-// Supla::ESPWifi wifi("your_wifi_ssid", "your_wifi_password");
-//
-// ESP32 based board:
-// #include
-// Supla::ESP32Wifi wifi("your_wifi_ssid", "your_wifi_password");
+#ifdef ARDUINO_ARCH_AVR
+ // Arduino Mega with EthernetShield W5100:
+ #include
+ // Ethernet MAC address
+ uint8_t mac[6] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05};
+ Supla::EthernetShield ethernet(mac);
+
+ // Arduino Mega with ENC28J60:
+ // #include
+ // Supla::ENC28J60 ethernet(mac);
+#elif defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
+ // ESP8266 and ESP32 based board:
+ #include
+ Supla::ESPWifi wifi("your_wifi_ssid", "your_wifi_password");
+#endif
/*
* Youtube: https://youtu.be/FE9tqzTjmA4
@@ -83,7 +80,7 @@ class RgbwLeds : public Supla::Control::RGBWBase {
};
void setup() {
- Serial.begin(9600);
+ Serial.begin(115200);
// Replace the falowing GUID with value that you can retrieve from https://www.supla.org/arduino/get-guid
char GUID[SUPLA_GUID_SIZE] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
diff --git a/lib/SuplaDevice/examples/RollerShutter/RollerShutter.ino b/lib/SuplaDevice/examples/RollerShutter/RollerShutter.ino
index 9747b4e6..777b47bd 100644
--- a/lib/SuplaDevice/examples/RollerShutter/RollerShutter.ino
+++ b/lib/SuplaDevice/examples/RollerShutter/RollerShutter.ino
@@ -14,10 +14,10 @@
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-#include
#include
#include
#include
+#include
// Choose where Supla should store roller shutter data in persistant memory
// We recommend to use external FRAM memory
@@ -27,30 +27,26 @@ Supla::Eeprom eeprom(STORAGE_OFFSET);
// #include
// Supla::FramSpi fram(STORAGE_OFFSET);
-
// Choose proper network interface for your card:
-// Arduino Mega with EthernetShield W5100:
-#include
-// Ethernet MAC address
-uint8_t mac[6] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05};
-Supla::EthernetShield ethernet(mac);
-//
-// Arduino Mega with ENC28J60:
-// #include
-// Supla::ENC28J60 ethernet(mac);
-//
-// ESP8266 based board:
-// #include
-// Supla::ESPWifi wifi("your_wifi_ssid", "your_wifi_password");
-//
-// ESP32 based board:
-// #include
-// Supla::ESP32Wifi wifi("your_wifi_ssid", "your_wifi_password");
+#ifdef ARDUINO_ARCH_AVR
+ // Arduino Mega with EthernetShield W5100:
+ #include
+ // Ethernet MAC address
+ uint8_t mac[6] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05};
+ Supla::EthernetShield ethernet(mac);
+ // Arduino Mega with ENC28J60:
+ // #include
+ // Supla::ENC28J60 ethernet(mac);
+#elif defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
+ // ESP8266 and ESP32 based board:
+ #include
+ Supla::ESPWifi wifi("your_wifi_ssid", "your_wifi_password");
+#endif
void setup() {
- Serial.begin(9600);
+ Serial.begin(115200);
// Replace the falowing GUID with value that you can retrieve from https://www.supla.org/arduino/get-guid
char GUID[SUPLA_GUID_SIZE] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
@@ -69,6 +65,12 @@ void setup() {
Supla::Control::Button *buttonOpen = new Supla::Control::Button(28, true, true);
Supla::Control::Button *buttonClose = new Supla::Control::Button(29, true, true);
+ // Add two LEDs to inform about roller shutter relay status
+ // If inverted value is required, please add third parameter with true value
+ new Supla::Control::PinStatusLed(30, 24); // pin 30 status to be informed on pin 24
+ new Supla::Control::PinStatusLed(31, 25); // pin 31 status to be informed on pin 25
+
+
buttonOpen->addAction(Supla::OPEN_OR_STOP, *rs, Supla::ON_PRESS);
buttonClose->addAction(Supla::CLOSE_OR_STOP, *rs, Supla::ON_PRESS);
diff --git a/lib/SuplaDevice/examples/SequenceButton/SequenceButton.ino b/lib/SuplaDevice/examples/SequenceButton/SequenceButton.ino
new file mode 100644
index 00000000..75f81134
--- /dev/null
+++ b/lib/SuplaDevice/examples/SequenceButton/SequenceButton.ino
@@ -0,0 +1,89 @@
+/*
+ Copyright (C) AC SOFTWARE SP. Z O.O.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ 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 General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include
+#include
+#include
+
+// Choose proper network interface for your card:
+#ifdef ARDUINO_ARCH_AVR
+ // Arduino Mega with EthernetShield W5100:
+ #include
+ // Ethernet MAC address
+ uint8_t mac[6] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05};
+ Supla::EthernetShield ethernet(mac);
+
+ // Arduino Mega with ENC28J60:
+ // #include
+ // Supla::ENC28J60 ethernet(mac);
+#elif defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
+ // ESP8266 and ESP32 based board:
+ #include
+ Supla::ESPWifi wifi("your_wifi_ssid", "your_wifi_password");
+#endif
+
+
+void setup() {
+
+ Serial.begin(115200);
+
+ // Replace the falowing GUID with value that you can retrieve from https://www.supla.org/arduino/get-guid
+ char GUID[SUPLA_GUID_SIZE] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+
+ // Replace the following AUTHKEY with value that you can retrieve from: https://www.supla.org/arduino/get-authkey
+ char AUTHKEY[SUPLA_AUTHKEY_SIZE] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+
+ /*
+ * Having your device already registered at cloud.supla.org,
+ * you want to change CHANNEL sequence or remove any of them,
+ * then you must also remove the device itself from cloud.supla.org.
+ * Otherwise you will get "Channel conflict!" error.
+ */
+
+ auto secretRelay = new Supla::Control::Relay(30, false); // Low level trigger relay on pin 30
+ auto alarmRelay = new Supla::Control::Relay(31, false); // Low level trigger relay on pin 31
+ auto seqButton = new Supla::Control::SequenceButton(28, true, true); // Button on pin 28 with internal pullUp
+ // and LOW is considered as "pressed" state
+
+ // Sequence of lenghts [ms] of button being presset, released, pressed, released, etc.
+ // Aplication will print on Serial recorded sequence, so use it to record your rhythm and put it here
+ uint16_t sequence[30] = {90, 590, 90, 140, 90, 290, 90, 230, 90, 140, 90};
+
+ seqButton->setSequence(sequence);
+ seqButton->setMargin(0.5); // we allow +- 50% deviation of state length compared to matching sequence
+
+ // Button will trigger secretRelay when correct rhythm will be detected or alarmRelay otherwise
+ seqButton->addAction(Supla::TURN_ON, secretRelay, Supla::ON_SEQUENCE_MATCH);
+ seqButton->addAction(Supla::TURN_ON, alarmRelay, Supla::ON_SEQUENCE_DOESNT_MATCH);
+
+ /*
+ * SuplaDevice Initialization.
+ * Server address is available at https://cloud.supla.org
+ * If you do not have an account, you can create it at https://cloud.supla.org/account/create
+ * SUPLA and SUPLA CLOUD are free of charge
+ *
+ */
+
+ SuplaDevice.begin(GUID, // Global Unique Identifier
+ "svr1.supla.org", // SUPLA server address
+ "email@address", // Email address used to login to Supla Cloud
+ AUTHKEY); // Authorization key
+
+}
+
+void loop() {
+ SuplaDevice.iterate();
+}
diff --git a/lib/SuplaDevice/extras/test/CMakeLists.txt b/lib/SuplaDevice/extras/test/CMakeLists.txt
new file mode 100644
index 00000000..107bf4d8
--- /dev/null
+++ b/lib/SuplaDevice/extras/test/CMakeLists.txt
@@ -0,0 +1,60 @@
+cmake_minimum_required(VERSION 3.11)
+
+project(supladevice)
+
+enable_testing()
+
+set(CMAKE_CXX_STANDARD 14)
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
+set(CMAKE_BUILD_TYPE Debug)
+
+include_directories(../../src)
+include_directories(doubles)
+
+add_subdirectory(../../src/ build)
+
+mark_as_advanced(
+BUILD_GMOCK
+BUILD_GTEST
+)
+
+include(FetchContent)
+
+FetchContent_Declare(
+ googletest
+ GIT_REPOSITORY https://github.com/google/googletest.git
+ GIT_TAG release-1.10.0
+ )
+
+FetchContent_GetProperties(googletest)
+if(NOT googletest_POPULATED)
+ FetchContent_Populate(googletest)
+ add_subdirectory(${googletest_SOURCE_DIR} ${googletest_BINARY_DIR})
+endif()
+
+file(GLOB TEST_SRC
+ UptimeTests/*.cpp
+ ChannelTests/*cpp
+ IoTests/*.cpp
+ ElementTests/*.cpp
+ LocalActionTests/*.cpp
+ SensorTests/*.cpp
+ ChannelElementTests/*.cpp
+ InternalPinOutputTests/*.cpp
+ PinStatusLedTests/*.cpp
+ ConditionTests/*.cpp
+ )
+
+file(GLOB DOUBLE_SRC doubles/*.cpp)
+
+add_executable(supladevicetests ${TEST_SRC} ${DOUBLE_SRC})
+
+target_link_libraries(supladevicetests
+ gmock
+ gtest
+ gtest_main
+ supladevicelib
+ )
+
+add_test(NAME supladevicetests
+ COMMAND supladevicetests)
diff --git a/lib/SuplaDevice/extras/test/ChannelElementTests/channel_element_tests.cpp b/lib/SuplaDevice/extras/test/ChannelElementTests/channel_element_tests.cpp
new file mode 100644
index 00000000..19e731df
--- /dev/null
+++ b/lib/SuplaDevice/extras/test/ChannelElementTests/channel_element_tests.cpp
@@ -0,0 +1,81 @@
+/*
+ Copyright (C) AC SOFTWARE SP. Z O.O.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ 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 General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+class ActionHandlerMock : public Supla::ActionHandler {
+ public:
+ MOCK_METHOD(void, handleAction, (int, int), (override));
+};
+
+
+TEST(ChannelElementTests, ActionDelegationToChannel) {
+ ASSERT_EQ(Supla::LocalAction::getClientListPtr(), nullptr);
+ Supla::ChannelElement element;
+
+ ActionHandlerMock mock1;
+ ActionHandlerMock mock2;
+
+ int action1 = 11;
+
+ EXPECT_CALL(mock1, handleAction(Supla::ON_TURN_ON, action1)).Times(2);
+ EXPECT_CALL(mock2, handleAction(Supla::ON_TURN_OFF, action1)).Times(2);
+
+ element.addAction(action1, mock1, Supla::ON_TURN_ON);
+ element.addAction(action1, &mock2, Supla::ON_TURN_OFF);
+
+ element.getChannel()->setNewValue(false);
+ element.getChannel()->setNewValue(true);
+ element.getChannel()->setNewValue(true);
+
+ element.getChannel()->setNewValue(false);
+ element.getChannel()->setNewValue(true);
+ element.getChannel()->setNewValue(false);
+ element.getChannel()->setNewValue(false);
+}
+
+TEST(ChannelElementTests, ActionDelegationToConditions) {
+ ASSERT_EQ(Supla::LocalAction::getClientListPtr(), nullptr);
+
+ ActionHandlerMock mock1;
+ ActionHandlerMock mock2;
+
+ int action1 = 11;
+
+ EXPECT_CALL(mock1, handleAction(Supla::ON_CHANGE, action1)).Times(1);
+ EXPECT_CALL(mock2, handleAction(Supla::ON_CHANGE, action1)).Times(1);
+
+ Supla::ChannelElement element;
+ auto channel = element.getChannel();
+ channel->setType(SUPLA_CHANNELTYPE_DISTANCESENSOR);
+
+ element.addAction(action1, mock1, OnLess(50));
+ element.addAction(action1, &mock2, OnLess(30));
+
+ channel->setNewValue(60);
+ channel->setNewValue(50);
+ channel->setNewValue(45);
+ channel->setNewValue(25);
+}
+
+
diff --git a/lib/SuplaDevice/extras/test/ChannelTests/channel_extended_tests.cpp b/lib/SuplaDevice/extras/test/ChannelTests/channel_extended_tests.cpp
new file mode 100644
index 00000000..57296822
--- /dev/null
+++ b/lib/SuplaDevice/extras/test/ChannelTests/channel_extended_tests.cpp
@@ -0,0 +1,128 @@
+/*
+ Copyright (C) AC SOFTWARE SP. Z O.O.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ 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 General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+class ActionHandlerMock : public Supla::ActionHandler {
+ public:
+ MOCK_METHOD(void, handleAction, (int, int), (override));
+};
+
+
+using ::testing::_;
+using ::testing::ElementsAreArray;
+using ::testing::Args;
+using ::testing::ElementsAre;
+
+
+TEST(ChannelExtendedTests, ExtendedChannelMethods) {
+ Supla::ChannelExtended extChannel;
+
+ EXPECT_TRUE(extChannel.isExtended());
+ EXPECT_NE(nullptr, extChannel.getExtValue() );
+
+}
+
+TEST(ChannelExtendedTests, SetNewValueOnExtChannel) {
+ int number = 0;
+ Supla::ChannelExtended extChannel;
+ TElectricityMeter_ExtendedValue_V2 emVal = {};
+ TElectricityMeter_Value expectedValue = {};
+
+ emVal.m_count = 1;
+ emVal.measured_values |= EM_VAR_FORWARD_ACTIVE_ENERGY;
+ emVal.total_forward_active_energy[0] = 1000;
+ emVal.total_forward_active_energy[1] = 2000;
+ emVal.total_forward_active_energy[2] = 4000;
+
+ expectedValue.total_forward_active_energy = (1000 + 2000 + 4000) / 1000;
+
+ extChannel.setNewValue(emVal);
+ EXPECT_TRUE(0 == memcmp(Supla::Channel::reg_dev.channels[number].value, &expectedValue, sizeof(expectedValue)));
+ EXPECT_TRUE(extChannel.isUpdateReady());
+ extChannel.clearUpdateReady();
+
+ emVal.measured_values |= EM_VAR_VOLTAGE;
+ emVal.m[0].voltage[0] = 10;
+ emVal.m[0].voltage[1] = 0;
+ emVal.m[0].voltage[2] = 0;
+
+ expectedValue.flags = 0;
+ expectedValue.flags |= EM_VALUE_FLAG_PHASE1_ON;
+
+ extChannel.setNewValue(emVal);
+ EXPECT_TRUE(0 == memcmp(Supla::Channel::reg_dev.channels[number].value, &expectedValue, sizeof(expectedValue)));
+ EXPECT_TRUE(extChannel.isUpdateReady());
+ extChannel.clearUpdateReady();
+
+ emVal.m[0].voltage[0] = 0;
+ emVal.m[0].voltage[1] = 20;
+ emVal.m[0].voltage[2] = 0;
+
+ expectedValue.flags = 0;
+ expectedValue.flags |= EM_VALUE_FLAG_PHASE2_ON;
+
+ extChannel.setNewValue(emVal);
+ EXPECT_TRUE(0 == memcmp(Supla::Channel::reg_dev.channels[number].value, &expectedValue, sizeof(expectedValue)));
+ EXPECT_TRUE(extChannel.isUpdateReady());
+ extChannel.clearUpdateReady();
+
+
+ emVal.m[0].voltage[0] = 0;
+ emVal.m[0].voltage[1] = 0;
+ emVal.m[0].voltage[2] = 300;
+
+ expectedValue.flags = 0;
+ expectedValue.flags |= EM_VALUE_FLAG_PHASE3_ON;
+
+ extChannel.setNewValue(emVal);
+ EXPECT_TRUE(0 == memcmp(Supla::Channel::reg_dev.channels[number].value, &expectedValue, sizeof(expectedValue)));
+ EXPECT_TRUE(extChannel.isUpdateReady());
+ extChannel.clearUpdateReady();
+
+
+ emVal.m[0].voltage[0] = 10;
+ emVal.m[0].voltage[1] = 0;
+ emVal.m[0].voltage[2] = 540;
+
+ expectedValue.flags = 0;
+ expectedValue.flags |= EM_VALUE_FLAG_PHASE1_ON | EM_VALUE_FLAG_PHASE3_ON;
+
+ extChannel.setNewValue(emVal);
+ EXPECT_TRUE(0 == memcmp(Supla::Channel::reg_dev.channels[number].value, &expectedValue, sizeof(expectedValue)));
+ EXPECT_TRUE(extChannel.isUpdateReady());
+ extChannel.clearUpdateReady();
+
+ emVal.m[0].voltage[0] = 10;
+ emVal.m[0].voltage[1] = 230;
+ emVal.m[0].voltage[2] = 540;
+
+ expectedValue.flags = 0;
+ expectedValue.flags |= EM_VALUE_FLAG_PHASE1_ON | EM_VALUE_FLAG_PHASE3_ON | EM_VALUE_FLAG_PHASE2_ON;
+
+ extChannel.setNewValue(emVal);
+ EXPECT_TRUE(0 == memcmp(Supla::Channel::reg_dev.channels[number].value, &expectedValue, sizeof(expectedValue)));
+ EXPECT_TRUE(extChannel.isUpdateReady());
+ extChannel.clearUpdateReady();
+}
diff --git a/lib/SuplaDevice/extras/test/ChannelTests/channel_tests.cpp b/lib/SuplaDevice/extras/test/ChannelTests/channel_tests.cpp
new file mode 100644
index 00000000..09008e7a
--- /dev/null
+++ b/lib/SuplaDevice/extras/test/ChannelTests/channel_tests.cpp
@@ -0,0 +1,483 @@
+/*
+ Copyright (C) AC SOFTWARE SP. Z O.O.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ 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 General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+
+class ActionHandlerMock : public Supla::ActionHandler {
+ public:
+ MOCK_METHOD(void, handleAction, (int, int), (override));
+};
+
+
+using ::testing::_;
+using ::testing::ElementsAreArray;
+using ::testing::Args;
+using ::testing::ElementsAre;
+
+TEST(ChannelTests, ChannelMethods) {
+ Supla::Channel first;
+ Supla::Channel second;
+
+ EXPECT_EQ(first.getChannelNumber(), 0);
+ EXPECT_EQ(second.getChannelNumber(), 1);
+
+ EXPECT_EQ(first.isExtended(), false);
+ EXPECT_EQ(first.isUpdateReady(), false);
+ EXPECT_EQ(first.getChannelType(), 0);
+ EXPECT_EQ(first.getExtValue(), nullptr);
+
+ int number = first.getChannelNumber();
+ char emptyArray[SUPLA_CHANNELVALUE_SIZE] = {};
+ EXPECT_EQ(number, Supla::Channel::reg_dev.channels[number].Number);
+ EXPECT_EQ(Supla::Channel::reg_dev.channels[number].Type, 0);
+ EXPECT_EQ(Supla::Channel::reg_dev.channels[number].FuncList, 0);
+ EXPECT_EQ(Supla::Channel::reg_dev.channels[number].Default, 0);
+ EXPECT_EQ(Supla::Channel::reg_dev.channels[number].Flags, SUPLA_CHANNEL_FLAG_CHANNELSTATE);
+ EXPECT_TRUE(0 == memcmp(Supla::Channel::reg_dev.channels[number].value, emptyArray, SUPLA_CHANNELVALUE_SIZE));
+
+ first.setType(10);
+ EXPECT_EQ(first.getChannelType(), 10);
+ EXPECT_EQ(Supla::Channel::reg_dev.channels[number].Type, 10);
+
+ first.setDefault(14);
+ EXPECT_EQ(Supla::Channel::reg_dev.channels[number].Default, 14);
+
+ first.setFlag(2);
+ EXPECT_EQ(Supla::Channel::reg_dev.channels[number].Flags, SUPLA_CHANNEL_FLAG_CHANNELSTATE | 2);
+
+ first.setFlag(4);
+ EXPECT_EQ(Supla::Channel::reg_dev.channels[number].Flags, SUPLA_CHANNEL_FLAG_CHANNELSTATE | 2 | 4);
+
+ first.unsetFlag(2);
+ EXPECT_EQ(Supla::Channel::reg_dev.channels[number].Flags, SUPLA_CHANNEL_FLAG_CHANNELSTATE | 4);
+
+ first.unsetFlag(SUPLA_CHANNEL_FLAG_CHANNELSTATE);
+ EXPECT_EQ(Supla::Channel::reg_dev.channels[number].Flags, 4);
+
+ first.setFuncList(11);
+ EXPECT_EQ(Supla::Channel::reg_dev.channels[number].FuncList, 11);
+
+}
+
+TEST(ChannelTests, SetNewValue) {
+ Supla::Channel channel;
+ int number = channel.getChannelNumber();
+ char emptyArray[SUPLA_CHANNELVALUE_SIZE] = {};
+
+ EXPECT_TRUE(0 == memcmp(Supla::Channel::reg_dev.channels[number].value, emptyArray, SUPLA_CHANNELVALUE_SIZE));
+ EXPECT_FALSE(channel.isUpdateReady());
+
+ char array[SUPLA_CHANNELVALUE_SIZE] = {0, 1, 2, 3, 4, 5, 6, 7};
+ channel.setNewValue(array);
+ EXPECT_TRUE(0 == memcmp(Supla::Channel::reg_dev.channels[number].value, array, SUPLA_CHANNELVALUE_SIZE));
+ EXPECT_TRUE(channel.isUpdateReady());
+
+ channel.clearUpdateReady();
+ EXPECT_FALSE(channel.isUpdateReady());
+
+ channel.setNewValue(array);
+ EXPECT_TRUE(0 == memcmp(Supla::Channel::reg_dev.channels[number].value, array, SUPLA_CHANNELVALUE_SIZE));
+ EXPECT_FALSE(channel.isUpdateReady());
+
+ array[4] = 15;
+ channel.setNewValue(array);
+ EXPECT_TRUE(0 == memcmp(Supla::Channel::reg_dev.channels[number].value, array, SUPLA_CHANNELVALUE_SIZE));
+ EXPECT_TRUE(channel.isUpdateReady());
+
+ ASSERT_EQ(sizeof(double), 8);
+ double temp = 3.1415;
+ channel.setNewValue(temp);
+ EXPECT_TRUE(0 == memcmp(Supla::Channel::reg_dev.channels[number].value, &temp, SUPLA_CHANNELVALUE_SIZE));
+ EXPECT_TRUE(channel.isUpdateReady());
+ channel.clearUpdateReady();
+
+ char arrayBool[SUPLA_CHANNELVALUE_SIZE] = {};
+ arrayBool[0] = true;
+ channel.setNewValue(true);
+ EXPECT_TRUE(0 == memcmp(Supla::Channel::reg_dev.channels[number].value, arrayBool, SUPLA_CHANNELVALUE_SIZE));
+ EXPECT_TRUE(channel.isUpdateReady());
+ channel.clearUpdateReady();
+
+ channel.setNewValue(false);
+ arrayBool[0] = false;
+ EXPECT_TRUE(0 == memcmp(Supla::Channel::reg_dev.channels[number].value, arrayBool, SUPLA_CHANNELVALUE_SIZE));
+ EXPECT_TRUE(channel.isUpdateReady());
+ channel.clearUpdateReady();
+
+ int value = 1234;
+ ASSERT_EQ(sizeof(int), 4);
+ channel.setNewValue(value);
+ EXPECT_TRUE(0 == memcmp(Supla::Channel::reg_dev.channels[number].value, &value, sizeof(int)));
+ EXPECT_TRUE(channel.isUpdateReady());
+ channel.clearUpdateReady();
+
+ _supla_int64_t value64 = 124346;
+ ASSERT_EQ(sizeof(value64), 8);
+ channel.setNewValue(value64);
+ EXPECT_TRUE(0 == memcmp(Supla::Channel::reg_dev.channels[number].value, &value64, sizeof(value64)));
+ EXPECT_TRUE(channel.isUpdateReady());
+ channel.clearUpdateReady();
+
+ double humi = 95.2234123;
+ temp = 23.443322;
+
+ int expectedTemp = temp * 1000;
+ int expectedHumi = humi * 1000;
+
+ channel.setNewValue(temp, humi);
+ EXPECT_TRUE(0 == memcmp(Supla::Channel::reg_dev.channels[number].value, &expectedTemp, sizeof(expectedTemp)));
+ EXPECT_TRUE(0 == memcmp(&(Supla::Channel::reg_dev.channels[number].value[4]), &expectedHumi, sizeof(expectedHumi)));
+ EXPECT_TRUE(channel.isUpdateReady());
+ channel.clearUpdateReady();
+
+ // RGBW channel setting
+ channel.setNewValue(1, 2, 3, 4, 5);
+ char rgbwArray[SUPLA_CHANNELVALUE_SIZE] = {5, 4, 3, 2, 1, 0, 0, 0};
+ EXPECT_TRUE(0 == memcmp(Supla::Channel::reg_dev.channels[number].value, rgbwArray, SUPLA_CHANNELVALUE_SIZE));
+ EXPECT_TRUE(channel.isUpdateReady());
+ channel.clearUpdateReady();
+
+ TElectricityMeter_ExtendedValue_V2 emVal = {};
+ TElectricityMeter_Value expectedValue = {};
+
+ emVal.m_count = 1;
+ emVal.measured_values |= EM_VAR_FORWARD_ACTIVE_ENERGY;
+ emVal.total_forward_active_energy[0] = 1000;
+ emVal.total_forward_active_energy[1] = 2000;
+ emVal.total_forward_active_energy[2] = 4000;
+
+ expectedValue.total_forward_active_energy = (1000 + 2000 + 4000) / 1000;
+
+ channel.setNewValue(emVal);
+ EXPECT_TRUE(0 == memcmp(Supla::Channel::reg_dev.channels[number].value, &expectedValue, sizeof(expectedValue)));
+ EXPECT_TRUE(channel.isUpdateReady());
+ channel.clearUpdateReady();
+
+ emVal.measured_values |= EM_VAR_VOLTAGE;
+ emVal.m[0].voltage[0] = 10;
+ emVal.m[0].voltage[1] = 0;
+ emVal.m[0].voltage[2] = 0;
+
+ expectedValue.flags = 0;
+ expectedValue.flags |= EM_VALUE_FLAG_PHASE1_ON;
+
+ channel.setNewValue(emVal);
+ EXPECT_TRUE(0 == memcmp(Supla::Channel::reg_dev.channels[number].value, &expectedValue, sizeof(expectedValue)));
+ EXPECT_TRUE(channel.isUpdateReady());
+ channel.clearUpdateReady();
+
+ emVal.m[0].voltage[0] = 0;
+ emVal.m[0].voltage[1] = 20;
+ emVal.m[0].voltage[2] = 0;
+
+ expectedValue.flags = 0;
+ expectedValue.flags |= EM_VALUE_FLAG_PHASE2_ON;
+
+ channel.setNewValue(emVal);
+ EXPECT_TRUE(0 == memcmp(Supla::Channel::reg_dev.channels[number].value, &expectedValue, sizeof(expectedValue)));
+ EXPECT_TRUE(channel.isUpdateReady());
+ channel.clearUpdateReady();
+
+
+ emVal.m[0].voltage[0] = 0;
+ emVal.m[0].voltage[1] = 0;
+ emVal.m[0].voltage[2] = 300;
+
+ expectedValue.flags = 0;
+ expectedValue.flags |= EM_VALUE_FLAG_PHASE3_ON;
+
+ channel.setNewValue(emVal);
+ EXPECT_TRUE(0 == memcmp(Supla::Channel::reg_dev.channels[number].value, &expectedValue, sizeof(expectedValue)));
+ EXPECT_TRUE(channel.isUpdateReady());
+ channel.clearUpdateReady();
+
+
+ emVal.m[0].voltage[0] = 10;
+ emVal.m[0].voltage[1] = 0;
+ emVal.m[0].voltage[2] = 540;
+
+ expectedValue.flags = 0;
+ expectedValue.flags |= EM_VALUE_FLAG_PHASE1_ON | EM_VALUE_FLAG_PHASE3_ON;
+
+ channel.setNewValue(emVal);
+ EXPECT_TRUE(0 == memcmp(Supla::Channel::reg_dev.channels[number].value, &expectedValue, sizeof(expectedValue)));
+ EXPECT_TRUE(channel.isUpdateReady());
+ channel.clearUpdateReady();
+
+ emVal.m[0].voltage[0] = 10;
+ emVal.m[0].voltage[1] = 230;
+ emVal.m[0].voltage[2] = 540;
+
+ expectedValue.flags = 0;
+ expectedValue.flags |= EM_VALUE_FLAG_PHASE1_ON | EM_VALUE_FLAG_PHASE3_ON | EM_VALUE_FLAG_PHASE2_ON;
+
+ channel.setNewValue(emVal);
+ EXPECT_TRUE(0 == memcmp(Supla::Channel::reg_dev.channels[number].value, &expectedValue, sizeof(expectedValue)));
+ EXPECT_TRUE(channel.isUpdateReady());
+ channel.clearUpdateReady();
+}
+
+TEST(ChannelTests, ChannelValueGetters) {
+ Supla::Channel channel;
+
+ EXPECT_DOUBLE_EQ(channel.getValueDouble(), 0);
+
+ double pi = 3.1415;
+ channel.setNewValue(pi);
+ EXPECT_DOUBLE_EQ(channel.getValueDouble(), pi);
+
+ double e = 2.71828;
+ channel.setNewValue(pi, e);
+ EXPECT_NEAR(channel.getValueDoubleFirst(), pi, 0.001);
+ EXPECT_NEAR(channel.getValueDoubleSecond(), e, 0.001);
+
+ int valueInt = 2021;
+ channel.setNewValue(valueInt);
+ EXPECT_EQ(channel.getValueInt32(), valueInt);
+
+ _supla_int64_t valueInt64 = 202013012021000;
+ channel.setNewValue(valueInt64);
+ EXPECT_EQ(channel.getValueInt64(), valueInt64);
+
+ channel.setNewValue(true);
+ EXPECT_TRUE(channel.getValueBool());
+
+ channel.setNewValue(false);
+ EXPECT_FALSE(channel.getValueBool());
+
+ uint8_t red = 10, green = 20, blue = 30, colorBright = 50, bright = 90;
+ channel.setNewValue(red, green, blue, colorBright, bright);
+ EXPECT_EQ(channel.getValueRed(), red);
+ EXPECT_EQ(channel.getValueGreen(), green);
+ EXPECT_EQ(channel.getValueBlue(), blue);
+ EXPECT_EQ(channel.getValueColorBrightness(), colorBright);
+ EXPECT_EQ(channel.getValueBrightness(), bright);
+}
+
+TEST(ChannelTests, SendUpdateTest) {
+ Supla::Channel channel;
+ ::testing::InSequence seq;
+ SrpcMock srpc;
+
+ const char emptyArray[SUPLA_CHANNELVALUE_SIZE] = {};
+ char array[SUPLA_CHANNELVALUE_SIZE] = {};
+ array[0] = 1;
+
+ EXPECT_CALL(srpc, valueChanged(nullptr, 0, ElementsAreArray(emptyArray)));
+ EXPECT_CALL(srpc, valueChanged(nullptr, 0, ElementsAreArray(array)));
+
+ EXPECT_FALSE(channel.isUpdateReady());
+ channel.sendUpdate(nullptr);
+ channel.setNewValue(true);
+ EXPECT_TRUE(channel.isUpdateReady());
+ channel.sendUpdate(nullptr);
+ EXPECT_FALSE(channel.isUpdateReady());
+}
+
+TEST(ChannelTests, BoolChannelWithLocalActions) {
+ Supla::Channel ch1;
+
+ ::testing::InSequence seq;
+ ActionHandlerMock mock1;
+ ActionHandlerMock mock2;
+ SrpcMock srpc;
+
+ int action1 = 11;
+ int action2 = 12;
+ int action3 = 13;
+
+ EXPECT_CALL(mock1, handleAction(Supla::ON_TURN_ON, action1));
+ EXPECT_CALL(mock1, handleAction(Supla::ON_TURN_OFF, action2));
+ EXPECT_CALL(mock1, handleAction(Supla::ON_TURN_ON, action1));
+ EXPECT_CALL(mock1, handleAction(Supla::ON_CHANGE, action3));
+ EXPECT_CALL(mock2, handleAction).Times(0);
+
+
+ ch1.addAction(action1, mock1, Supla::ON_TURN_ON);
+ ch1.addAction(action2, mock1, Supla::ON_TURN_OFF);
+
+ ch1.setNewValue(true);
+ ch1.setNewValue(false);
+ ch1.setNewValue(false); // nothing should be called on mocks
+ ch1.setNewValue(false); // nothing should be called on mocks
+
+ ch1.addAction(action3, mock1, Supla::ON_CHANGE);
+ ch1.setNewValue(true);
+ ch1.setNewValue(true); // nothing should be called on mocks
+ ch1.setNewValue(true); // nothing should be called on mocks
+
+}
+
+TEST(ChannelTests, Int32ChannelWithLocalActions) {
+ Supla::Channel ch1;
+
+ ::testing::InSequence seq;
+ ActionHandlerMock mock1;
+ ActionHandlerMock mock2;
+ SrpcMock srpc;
+
+ int action1 = 11;
+ int action2 = 12;
+ int action3 = 13;
+
+ EXPECT_CALL(mock1, handleAction(Supla::ON_CHANGE, action1));
+ EXPECT_CALL(mock1, handleAction(Supla::ON_CHANGE, action1));
+ EXPECT_CALL(mock1, handleAction(Supla::ON_CHANGE, action1));
+ EXPECT_CALL(mock2, handleAction).Times(0);
+
+ ch1.addAction(action1, mock1, Supla::ON_CHANGE);
+
+ _supla_int_t value = 15;
+
+ ch1.setNewValue(value);
+ ch1.setNewValue(value);
+
+ value++;
+ ch1.setNewValue(value);
+
+ value++;
+ ch1.setNewValue(value);
+ ch1.setNewValue(value);
+ ch1.setNewValue(value);
+}
+
+TEST(ChannelTests, Int64ChannelWithLocalActions) {
+ Supla::Channel ch1;
+
+ ::testing::InSequence seq;
+ ActionHandlerMock mock1;
+ ActionHandlerMock mock2;
+ SrpcMock srpc;
+
+ int action1 = 11;
+ int action2 = 12;
+ int action3 = 13;
+
+ EXPECT_CALL(mock1, handleAction(Supla::ON_CHANGE, action1));
+ EXPECT_CALL(mock1, handleAction(Supla::ON_CHANGE, action1));
+ EXPECT_CALL(mock1, handleAction(Supla::ON_CHANGE, action1));
+ EXPECT_CALL(mock2, handleAction).Times(0);
+
+ ch1.addAction(action1, mock1, Supla::ON_CHANGE);
+
+ _supla_int64_t value = 15;
+
+ ch1.setNewValue(value);
+ ch1.setNewValue(value);
+
+ value++;
+ ch1.setNewValue(value);
+
+ value++;
+ ch1.setNewValue(value);
+ ch1.setNewValue(value);
+ ch1.setNewValue(value);
+}
+
+TEST(ChannelTests, DoubleChannelWithLocalActions) {
+ Supla::Channel ch1;
+
+ ::testing::InSequence seq;
+ ActionHandlerMock mock1;
+ ActionHandlerMock mock2;
+ SrpcMock srpc;
+
+ int action1 = 11;
+
+ EXPECT_CALL(mock1, handleAction(Supla::ON_CHANGE, action1));
+ EXPECT_CALL(mock1, handleAction(Supla::ON_CHANGE, action1));
+ EXPECT_CALL(mock1, handleAction(Supla::ON_CHANGE, action1));
+ EXPECT_CALL(mock2, handleAction).Times(0);
+
+ ch1.addAction(action1, mock1, Supla::ON_CHANGE);
+
+ double value = 3.1415;
+
+ ch1.setNewValue(value);
+ ch1.setNewValue(value);
+
+ value += 1.2;
+ ch1.setNewValue(value);
+
+ value += 1.2;
+ ch1.setNewValue(value);
+ ch1.setNewValue(value);
+ ch1.setNewValue(value);
+}
+
+TEST(ChannelTests, DoubleFloatChannelWithLocalActions) {
+ Supla::Channel ch1;
+
+ ::testing::InSequence seq;
+ ActionHandlerMock mock1;
+ ActionHandlerMock mock2;
+ SrpcMock srpc;
+
+ int action1 = 11;
+
+ EXPECT_CALL(mock1, handleAction(Supla::ON_CHANGE, action1));
+ EXPECT_CALL(mock1, handleAction(Supla::ON_CHANGE, action1));
+ EXPECT_CALL(mock1, handleAction(Supla::ON_CHANGE, action1));
+ EXPECT_CALL(mock2, handleAction).Times(0);
+
+ ch1.addAction(action1, mock1, Supla::ON_CHANGE);
+
+ float value1 = 3.1415;
+ float value2 = 2.5;
+
+ ch1.setNewValue(value1, value2);
+ ch1.setNewValue(value1, value2);
+
+ value1 += 1.2;
+ ch1.setNewValue(value1, value2);
+
+ value2 += 1.2;
+ ch1.setNewValue(value1, value2);
+ ch1.setNewValue(value1, value2);
+ ch1.setNewValue(value1, value2);
+}
+
+TEST(ChannelTests, RgbwChannelWithLocalActions) {
+ Supla::Channel ch1;
+
+ ::testing::InSequence seq;
+ ActionHandlerMock mock1;
+ ActionHandlerMock mock2;
+ SrpcMock srpc;
+
+ int action1 = 11;
+
+ EXPECT_CALL(mock1, handleAction(Supla::ON_CHANGE, action1));
+ EXPECT_CALL(mock1, handleAction(Supla::ON_CHANGE, action1));
+ EXPECT_CALL(mock1, handleAction(Supla::ON_CHANGE, action1));
+ EXPECT_CALL(mock2, handleAction).Times(0);
+
+ ch1.addAction(action1, mock1, Supla::ON_CHANGE);
+
+ ch1.setNewValue(10, 20, 30, 90, 80);
+ ch1.setNewValue(10, 20, 30, 90, 80);
+
+ ch1.setNewValue(10, 21, 30, 90, 80);
+ ch1.setNewValue(10, 20, 30, 90, 81);
+ ch1.setNewValue(10, 20, 30, 90, 81);
+}
diff --git a/lib/SuplaDevice/extras/test/ConditionTests/on_between_eq_tests.cpp b/lib/SuplaDevice/extras/test/ConditionTests/on_between_eq_tests.cpp
new file mode 100644
index 00000000..f3287a2b
--- /dev/null
+++ b/lib/SuplaDevice/extras/test/ConditionTests/on_between_eq_tests.cpp
@@ -0,0 +1,43 @@
+/*
+ Copyright (C) AC SOFTWARE SP. Z O.O.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ 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 General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include
+
+#include
+
+TEST(OnBetweenEqTests, OnBetweenEqConditionTests) {
+ auto cond = OnBetweenEq(20, 30);
+
+ EXPECT_FALSE(cond->checkConditionFor(5));
+ EXPECT_FALSE(cond->checkConditionFor(15));
+
+ EXPECT_TRUE(cond->checkConditionFor(20));
+ EXPECT_FALSE(cond->checkConditionFor(20.001));
+ EXPECT_FALSE(cond->checkConditionFor(25));
+
+ EXPECT_FALSE(cond->checkConditionFor(5));
+ EXPECT_FALSE(cond->checkConditionFor(5));
+ EXPECT_FALSE(cond->checkConditionFor(5));
+
+ EXPECT_FALSE(cond->checkConditionFor(50));
+ EXPECT_TRUE(cond->checkConditionFor(30));
+ EXPECT_FALSE(cond->checkConditionFor(5));
+
+ EXPECT_TRUE(cond->checkConditionFor(24));
+}
+
+
+
diff --git a/lib/SuplaDevice/extras/test/ConditionTests/on_between_tests.cpp b/lib/SuplaDevice/extras/test/ConditionTests/on_between_tests.cpp
new file mode 100644
index 00000000..63314db8
--- /dev/null
+++ b/lib/SuplaDevice/extras/test/ConditionTests/on_between_tests.cpp
@@ -0,0 +1,41 @@
+/*
+ Copyright (C) AC SOFTWARE SP. Z O.O.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ 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 General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include
+
+#include
+
+TEST(OnBetweenTests, OnBetweenConditionTests) {
+ auto cond = OnBetween(20, 30);
+
+ EXPECT_FALSE(cond->checkConditionFor(5));
+ EXPECT_FALSE(cond->checkConditionFor(15));
+
+ EXPECT_FALSE(cond->checkConditionFor(20));
+ EXPECT_TRUE(cond->checkConditionFor(20.001));
+ EXPECT_FALSE(cond->checkConditionFor(25));
+
+ EXPECT_FALSE(cond->checkConditionFor(5));
+ EXPECT_FALSE(cond->checkConditionFor(5));
+ EXPECT_FALSE(cond->checkConditionFor(5));
+
+ EXPECT_FALSE(cond->checkConditionFor(50));
+ EXPECT_TRUE(cond->checkConditionFor(29));
+ EXPECT_FALSE(cond->checkConditionFor(5));
+
+}
+
+
diff --git a/lib/SuplaDevice/extras/test/ConditionTests/on_equal_tests.cpp b/lib/SuplaDevice/extras/test/ConditionTests/on_equal_tests.cpp
new file mode 100644
index 00000000..c48cc0ed
--- /dev/null
+++ b/lib/SuplaDevice/extras/test/ConditionTests/on_equal_tests.cpp
@@ -0,0 +1,39 @@
+/*
+ Copyright (C) AC SOFTWARE SP. Z O.O.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ 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 General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include
+
+#include
+
+TEST(OnEqualTests, OnEqualConditionTests) {
+ auto cond = OnEqual(3.1415);
+
+ EXPECT_FALSE(cond->checkConditionFor(5));
+ EXPECT_FALSE(cond->checkConditionFor(15));
+
+ EXPECT_TRUE(cond->checkConditionFor(3.1415));
+ EXPECT_FALSE(cond->checkConditionFor(20.001));
+ EXPECT_FALSE(cond->checkConditionFor(25));
+
+ EXPECT_FALSE(cond->checkConditionFor(5));
+ EXPECT_FALSE(cond->checkConditionFor(5));
+ EXPECT_FALSE(cond->checkConditionFor(5));
+
+ EXPECT_FALSE(cond->checkConditionFor(50));
+ EXPECT_TRUE(cond->checkConditionFor(3.1415));
+ EXPECT_FALSE(cond->checkConditionFor(5));
+
+}
diff --git a/lib/SuplaDevice/extras/test/ConditionTests/on_greater_eq_tests.cpp b/lib/SuplaDevice/extras/test/ConditionTests/on_greater_eq_tests.cpp
new file mode 100644
index 00000000..5022c061
--- /dev/null
+++ b/lib/SuplaDevice/extras/test/ConditionTests/on_greater_eq_tests.cpp
@@ -0,0 +1,39 @@
+/*
+ Copyright (C) AC SOFTWARE SP. Z O.O.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ 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 General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include
+
+#include
+
+TEST(OnGreaterEqTests, OnGreaterEqConditionTests) {
+ auto cond = OnGreaterEq(20);
+
+ EXPECT_FALSE(cond->checkConditionFor(5));
+ EXPECT_FALSE(cond->checkConditionFor(15));
+
+ EXPECT_TRUE(cond->checkConditionFor(20));
+ EXPECT_FALSE(cond->checkConditionFor(20.001));
+ EXPECT_FALSE(cond->checkConditionFor(25));
+
+ EXPECT_FALSE(cond->checkConditionFor(5));
+ EXPECT_FALSE(cond->checkConditionFor(5));
+ EXPECT_FALSE(cond->checkConditionFor(5));
+
+ EXPECT_TRUE(cond->checkConditionFor(50));
+ EXPECT_FALSE(cond->checkConditionFor(5));
+
+}
+
diff --git a/lib/SuplaDevice/extras/test/ConditionTests/on_greater_tests.cpp b/lib/SuplaDevice/extras/test/ConditionTests/on_greater_tests.cpp
new file mode 100644
index 00000000..c51459ab
--- /dev/null
+++ b/lib/SuplaDevice/extras/test/ConditionTests/on_greater_tests.cpp
@@ -0,0 +1,38 @@
+/*
+ Copyright (C) AC SOFTWARE SP. Z O.O.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ 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 General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include
+
+#include
+
+TEST(OnGreaterTests, OnGreaterConditionTests) {
+ auto cond = OnGreater(20);
+
+ EXPECT_FALSE(cond->checkConditionFor(5));
+ EXPECT_FALSE(cond->checkConditionFor(15));
+
+ EXPECT_FALSE(cond->checkConditionFor(20));
+ EXPECT_TRUE(cond->checkConditionFor(20.001));
+ EXPECT_FALSE(cond->checkConditionFor(25));
+
+ EXPECT_FALSE(cond->checkConditionFor(5));
+ EXPECT_FALSE(cond->checkConditionFor(5));
+ EXPECT_FALSE(cond->checkConditionFor(5));
+
+ EXPECT_TRUE(cond->checkConditionFor(50));
+ EXPECT_FALSE(cond->checkConditionFor(5));
+
+}
diff --git a/lib/SuplaDevice/extras/test/ConditionTests/on_less_eq_tests.cpp b/lib/SuplaDevice/extras/test/ConditionTests/on_less_eq_tests.cpp
new file mode 100644
index 00000000..f9de0634
--- /dev/null
+++ b/lib/SuplaDevice/extras/test/ConditionTests/on_less_eq_tests.cpp
@@ -0,0 +1,43 @@
+/*
+ Copyright (C) AC SOFTWARE SP. Z O.O.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ 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 General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include
+
+#include
+
+TEST(OnEqualEqTests, OnLessEqConditionTests) {
+ auto cond = OnLessEq(10);
+
+ EXPECT_TRUE(cond->checkConditionFor(5));
+ EXPECT_FALSE(cond->checkConditionFor(15));
+
+ EXPECT_TRUE(cond->checkConditionFor(10));
+ EXPECT_FALSE(cond->checkConditionFor(9.9999));
+
+ // "On" conditions should fire actions only on transition to meet condition.
+ EXPECT_FALSE(cond->checkConditionFor(5));
+ EXPECT_FALSE(cond->checkConditionFor(5));
+ EXPECT_FALSE(cond->checkConditionFor(5));
+
+ // Going back above threshold value, should reset expectation and it should return
+ // true on next call with met condition
+ EXPECT_FALSE(cond->checkConditionFor(50));
+ EXPECT_TRUE(cond->checkConditionFor(5));
+
+}
+
+
+
diff --git a/lib/SuplaDevice/extras/test/ConditionTests/on_less_tests.cpp b/lib/SuplaDevice/extras/test/ConditionTests/on_less_tests.cpp
new file mode 100644
index 00000000..aee77b1b
--- /dev/null
+++ b/lib/SuplaDevice/extras/test/ConditionTests/on_less_tests.cpp
@@ -0,0 +1,336 @@
+/*
+ Copyright (C) AC SOFTWARE SP. Z O.O.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ 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 General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+
+class ActionHandlerMock : public Supla::ActionHandler {
+ public:
+ MOCK_METHOD(void, handleAction, (int, int), (override));
+};
+
+
+using ::testing::_;
+using ::testing::ElementsAreArray;
+using ::testing::Args;
+using ::testing::ElementsAre;
+
+TEST(ConditionTests, handleActionTestsForDouble) {
+ ActionHandlerMock ahMock;
+ const int action1 = 15;
+ const int action2 = 16;
+ const int action3 = 17;
+
+ EXPECT_CALL(ahMock, handleAction(Supla::ON_CHANGE, action1)).Times(4);
+ EXPECT_CALL(ahMock, handleAction(Supla::ON_CHANGE, action3)).Times(4);
+
+ Supla::ChannelElement channelElement;
+ auto channel = channelElement.getChannel();
+
+ auto cond = OnLess(15.1);
+ cond->setSource(channelElement);
+ cond->setClient(ahMock);
+
+
+ // DISTANCE sensor use int type on channel value
+ channel->setType(SUPLA_CHANNELTYPE_WINDSENSOR);
+
+ channel->setNewValue(0.0);
+ // channel should be initialized to 0, so condition should be met
+ cond->handleAction(Supla::ON_CHANGE, action1);
+
+ channel->setNewValue(100.0);
+
+ // 100 is not less than 15.1, so nothing should happen
+ cond->handleAction(Supla::ON_CHANGE, action2);
+
+ channel->setNewValue(15.0);
+ // 15 is less than 15.1
+ cond->handleAction(Supla::ON_CHANGE, action3);
+
+ // nothing should happen
+ channel->setNewValue(25.0);
+ cond->handleAction(Supla::ON_CHANGE, action1);
+
+ // PRESSURE sensor use int type on channel value
+ channel->setType(SUPLA_CHANNELTYPE_PRESSURESENSOR);
+
+ channel->setNewValue(0.0);
+ // channel should be initialized to 0, so condition should be met
+ cond->handleAction(Supla::ON_CHANGE, action1);
+
+ channel->setNewValue(100.0);
+
+ // 100 is not less than 15.1, so nothing should happen
+ cond->handleAction(Supla::ON_CHANGE, action2);
+
+ channel->setNewValue(15.0);
+ // 15 is less than 15.1
+ cond->handleAction(Supla::ON_CHANGE, action3);
+
+ // nothing should happen
+ channel->setNewValue(25.0);
+ cond->handleAction(Supla::ON_CHANGE, action1);
+
+ // RAIN sensor use int type on channel value
+ channel->setType(SUPLA_CHANNELTYPE_RAINSENSOR);
+
+ channel->setNewValue(0.0);
+ // channel should be initialized to 0, so condition should be met
+ cond->handleAction(Supla::ON_CHANGE, action1);
+
+ channel->setNewValue(100.0);
+
+ // 100 is not less than 15.1, so nothing should happen
+ cond->handleAction(Supla::ON_CHANGE, action2);
+
+ channel->setNewValue(15.0);
+ // 15 is less than 15.1
+ cond->handleAction(Supla::ON_CHANGE, action3);
+
+ // nothing should happen
+ channel->setNewValue(25.0);
+ cond->handleAction(Supla::ON_CHANGE, action1);
+
+
+ // WEIGHT sensor use int type on channel value
+ channel->setType(SUPLA_CHANNELTYPE_WEIGHTSENSOR);
+
+ channel->setNewValue(0.0);
+ // channel should be initialized to 0, so condition should be met
+ cond->handleAction(Supla::ON_CHANGE, action1);
+
+ channel->setNewValue(100.0);
+
+ // 100 is not less than 15.1, so nothing should happen
+ cond->handleAction(Supla::ON_CHANGE, action2);
+
+ channel->setNewValue(15.0);
+ // 15 is less than 15.1
+ cond->handleAction(Supla::ON_CHANGE, action3);
+
+}
+
+TEST(ConditionTests, handleActionTestsForInt64) {
+ ActionHandlerMock ahMock;
+ const int action1 = 15;
+ const int action2 = 16;
+ const int action3 = 17;
+
+ EXPECT_CALL(ahMock, handleAction(Supla::ON_CHANGE, action1));
+ EXPECT_CALL(ahMock, handleAction(Supla::ON_CHANGE, action3));
+
+ Supla::ChannelElement channelElement;
+ auto channel = channelElement.getChannel();
+
+ auto cond = OnLess(15.1);
+ cond->setSource(channelElement);
+ cond->setClient(ahMock);
+
+ // DISTANCE sensor use int type on channel value
+ channel->setType(SUPLA_CHANNELTYPE_IMPULSE_COUNTER);
+
+ // channel should be initialized to 0, so condition should be met
+ cond->handleAction(Supla::ON_CHANGE, action1);
+
+ _supla_int64_t newValue = 10000344422234;
+ channel->setNewValue(newValue);
+
+ // newValue is not less than 15.1, so nothing should happen
+ cond->handleAction(Supla::ON_CHANGE, action2);
+
+ newValue = 2;
+ channel->setNewValue(newValue);
+ // newValue is less than 15.1
+ cond->handleAction(Supla::ON_CHANGE, action3);
+}
+
+TEST(ConditionTests, handleActionTestsForDouble2) {
+ ActionHandlerMock ahMock;
+ const int action1 = 15;
+ const int action2 = 16;
+ const int action3 = 17;
+
+ EXPECT_CALL(ahMock, handleAction(Supla::ON_CHANGE, action1));
+ EXPECT_CALL(ahMock, handleAction(Supla::ON_CHANGE, action3));
+
+ Supla::ChannelElement channelElement;
+ auto channel = channelElement.getChannel();
+
+ auto cond = OnLess(15.1);
+ cond->setSource(channelElement);
+ cond->setClient(ahMock);
+
+ channel->setType(SUPLA_CHANNELTYPE_THERMOMETER);
+
+ // channel should be initialized to 0, so condition should be met
+ cond->handleAction(Supla::ON_CHANGE, action1);
+
+ channel->setNewValue(15.1);
+
+ // 15.1 is not less than 15.1, so nothing should happen
+ cond->handleAction(Supla::ON_CHANGE, action2);
+
+ channel->setNewValue(15.01);
+ cond->handleAction(Supla::ON_CHANGE, action3);
+
+ // DISTANCE sensor use double type on channel value
+ channel->setType(SUPLA_CHANNELTYPE_DISTANCESENSOR);
+
+ channel->setNewValue(100);
+
+ // 100 is not less than 15.1, so nothing should happen
+ cond->handleAction(Supla::ON_CHANGE, action2);
+
+ channel->setNewValue(15);
+ // 15 is less than 15.1
+ cond->handleAction(Supla::ON_CHANGE, action3);
+
+ // nothing should happen
+ channel->setNewValue(25);
+ cond->handleAction(Supla::ON_CHANGE, action1);
+}
+
+TEST(ConditionTests, handleActionTestsForNotSupportedChannel) {
+ ActionHandlerMock ahMock;
+ const int action1 = 15;
+ const int action2 = 16;
+ const int action3 = 17;
+
+ EXPECT_CALL(ahMock, handleAction).Times(0);
+
+ Supla::ChannelElement channelElement;
+ auto channel = channelElement.getChannel();
+
+ auto cond = OnLess(15.1);
+ cond->setSource(channelElement);
+ cond->setClient(ahMock);
+
+ // this channel type is not used in library. DS18B20 uses standard THERMOMETER channel
+ channel->setType(SUPLA_CHANNELTYPE_THERMOMETERDS18B20);
+
+ cond->handleAction(Supla::ON_CHANGE, action1);
+
+ channel->setNewValue(15.1);
+
+ cond->handleAction(Supla::ON_CHANGE, action2);
+
+ channel->setNewValue(15.01);
+ cond->handleAction(Supla::ON_CHANGE, action3);
+}
+
+TEST(ConditionTests, handleActionTestsForFirstDouble) {
+ ActionHandlerMock ahMock;
+ const int action1 = 15;
+ const int action2 = 16;
+ const int action3 = 17;
+
+ EXPECT_CALL(ahMock, handleAction(Supla::ON_CHANGE, action1));
+ EXPECT_CALL(ahMock, handleAction(Supla::ON_CHANGE, action3));
+
+ Supla::ChannelElement channelElement;
+ auto channel = channelElement.getChannel();
+
+ auto cond = OnLess(15.1);
+ cond->setSource(channelElement);
+ cond->setClient(ahMock);
+
+ channel->setType(SUPLA_CHANNELTYPE_HUMIDITYANDTEMPSENSOR);
+
+ // channel should be initialized to 0, so condition should be met
+ cond->handleAction(Supla::ON_CHANGE, action1);
+
+ channel->setNewValue(15.1, 10.5);
+
+ // nothing should happen
+ cond->handleAction(Supla::ON_CHANGE, action2);
+
+ channel->setNewValue(15.1, 100.5);
+
+ // nothing should happen
+ cond->handleAction(Supla::ON_CHANGE, action2);
+
+
+ // ahMock should be called
+ channel->setNewValue(15.01, 25.1);
+ cond->handleAction(Supla::ON_CHANGE, action3);
+}
+
+TEST(ConditionTests, handleActionTestsForSecondDouble) {
+ ActionHandlerMock ahMock;
+ const int action1 = 15;
+ const int action2 = 16;
+ const int action3 = 17;
+
+ EXPECT_CALL(ahMock, handleAction(Supla::ON_CHANGE, action1));
+ EXPECT_CALL(ahMock, handleAction(Supla::ON_CHANGE, action3));
+
+ Supla::ChannelElement channelElement;
+ auto channel = channelElement.getChannel();
+
+ // second parameter indicates that we should check alternative channel value (pressure/second float)
+ auto cond = OnLess(15.1, true);
+ cond->setSource(channelElement);
+ cond->setClient(ahMock);
+
+ channel->setType(SUPLA_CHANNELTYPE_HUMIDITYANDTEMPSENSOR);
+
+ // channel should be initialized to 0, so condition should be met
+ cond->handleAction(Supla::ON_CHANGE, action1);
+
+ channel->setNewValue(0.1, 15.1);
+
+ // nothing should happen
+ cond->handleAction(Supla::ON_CHANGE, action2);
+
+ channel->setNewValue(15.1, 100.5);
+
+ // nothing should happen
+ cond->handleAction(Supla::ON_CHANGE, action2);
+
+
+ // ahMock should be called
+ channel->setNewValue(16.01, 5.1);
+ cond->handleAction(Supla::ON_CHANGE, action3);
+}
+
+TEST(OnLessTests, OnLessConditionTests) {
+ auto cond = OnLess(10);
+
+ EXPECT_TRUE(cond->checkConditionFor(5));
+ EXPECT_FALSE(cond->checkConditionFor(15));
+ EXPECT_FALSE(cond->checkConditionFor(10));
+ EXPECT_TRUE(cond->checkConditionFor(9.9999));
+
+ // "On" conditions should fire actions only on transition to meet condition.
+ EXPECT_FALSE(cond->checkConditionFor(5));
+ EXPECT_FALSE(cond->checkConditionFor(5));
+ EXPECT_FALSE(cond->checkConditionFor(5));
+
+ // Going back above threshold value, should reset expectation and it should return
+ // true on next call with met condition
+ EXPECT_FALSE(cond->checkConditionFor(50));
+ EXPECT_TRUE(cond->checkConditionFor(5));
+
+}
+
+
diff --git a/lib/SuplaDevice/extras/test/ElementTests/element_tests.cpp b/lib/SuplaDevice/extras/test/ElementTests/element_tests.cpp
new file mode 100644
index 00000000..8526dc0a
--- /dev/null
+++ b/lib/SuplaDevice/extras/test/ElementTests/element_tests.cpp
@@ -0,0 +1,180 @@
+/*
+ Copyright (C) AC SOFTWARE SP. Z O.O.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ 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 General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include
+
+#include
+#include
+#include
+#include
+
+using ::testing::Return;
+using ::testing::ElementsAreArray;
+
+class ElementWithChannel : public Supla::Element {
+ public:
+ Supla::Channel *getChannel() {
+ return &channel;
+ }
+ Supla::Channel channel;
+};
+
+TEST(ElementTests, ElementEmptyListTests) {
+ EXPECT_EQ(Supla::Element::begin(), nullptr);
+ EXPECT_EQ(Supla::Element::last(), nullptr);
+ EXPECT_EQ(Supla::Element::getElementByChannelNumber(0), nullptr);
+ EXPECT_EQ(Supla::Element::getElementByChannelNumber(-1), nullptr);
+ EXPECT_EQ(Supla::Element::getElementByChannelNumber(10), nullptr);
+}
+
+TEST(ElementTests, ElementListAdding) {
+ auto el1 = new Supla::Element;
+
+ EXPECT_EQ(Supla::Element::begin(), el1);
+ EXPECT_EQ(Supla::Element::last(), el1);
+
+ EXPECT_EQ(Supla::Element::getElementByChannelNumber(0), nullptr);
+ // Element without channel number acts as channel with -1 number
+ EXPECT_EQ(Supla::Element::getElementByChannelNumber(-1), el1);
+ EXPECT_EQ(Supla::Element::getElementByChannelNumber(10), nullptr);
+
+ auto el2 = new Supla::Element;
+ EXPECT_EQ(Supla::Element::begin(), el1);
+ EXPECT_EQ(Supla::Element::last(), el2);
+
+ EXPECT_EQ(Supla::Element::getElementByChannelNumber(0), nullptr);
+ // Element without channel number acts as channel with -1 number
+ EXPECT_EQ(Supla::Element::getElementByChannelNumber(-1), el1);
+ EXPECT_EQ(Supla::Element::getElementByChannelNumber(10), nullptr);
+
+ auto el3 = new Supla::Element;
+ EXPECT_EQ(Supla::Element::begin(), el1);
+ EXPECT_EQ(Supla::Element::last(), el3);
+
+ delete el2;
+
+ EXPECT_EQ(Supla::Element::begin(), el1);
+ EXPECT_EQ(Supla::Element::last(), el3);
+
+ el2 = new Supla::Element;
+ EXPECT_EQ(Supla::Element::begin(), el1);
+ EXPECT_EQ(Supla::Element::last(), el2);
+
+ delete el1;
+ EXPECT_EQ(Supla::Element::begin(), el3);
+ EXPECT_EQ(Supla::Element::last(), el2);
+
+ el1 = new Supla::Element;
+ EXPECT_EQ(Supla::Element::begin(), el3);
+ EXPECT_EQ(Supla::Element::last(), el1);
+
+ delete el1;
+ EXPECT_EQ(Supla::Element::begin(), el3);
+ EXPECT_EQ(Supla::Element::last(), el2);
+
+ delete el2;
+ delete el3;
+
+ EXPECT_EQ(Supla::Element::begin(), nullptr);
+ EXPECT_EQ(Supla::Element::last(), nullptr);
+
+}
+
+TEST(ElementTests, NoChannelElementMethods) {
+ Supla::Element el1;
+
+ // those methods are empty, so just call to make sure that they do nothing and don't crash
+ el1.onInit();
+ el1.onLoadState();
+ el1.onSaveState();
+ el1.iterateAlways();
+ el1.onTimer();
+ el1.onFastTimer();
+
+ TDSC_ChannelState channelState;
+ el1.handleGetChannelState(channelState);
+
+ EXPECT_EQ(el1.getChannelNumber(), -1);
+ EXPECT_EQ(el1.getChannel(), nullptr);
+ EXPECT_EQ(el1.getSecondaryChannel(), nullptr);
+ EXPECT_EQ(&(el1.disableChannelState()), &el1);
+ EXPECT_EQ(el1.next(), nullptr);
+
+ EXPECT_EQ(el1.iterateConnected(nullptr), true);
+ EXPECT_EQ(el1.iterateConnected(&el1), true);
+ EXPECT_EQ(el1.handleNewValueFromServer(nullptr), -1);
+ EXPECT_EQ(el1.handleCalcfgFromServer(nullptr), SUPLA_CALCFG_RESULT_NOT_SUPPORTED);
+}
+
+TEST(ElementTests, ChannelElementMethods) {
+ ElementWithChannel el1;
+ TimeInterfaceMock time;
+ SrpcMock srpc;
+
+ // those methods are empty, so just call to make sure that they do nothing and don't crash
+ el1.onInit();
+ el1.onLoadState();
+ el1.onSaveState();
+ el1.iterateAlways();
+ el1.onTimer();
+ el1.onFastTimer();
+
+ TDSC_ChannelState channelState;
+ el1.handleGetChannelState(channelState);
+
+ EXPECT_EQ(el1.getChannelNumber(), 0);
+ EXPECT_EQ(el1.getChannel(), &(el1.channel));
+ EXPECT_EQ(el1.getSecondaryChannel(), nullptr);
+ EXPECT_EQ(&(el1.disableChannelState()), &el1);
+ EXPECT_EQ(el1.next(), nullptr);
+
+ EXPECT_FALSE(el1.channel.isUpdateReady());
+ EXPECT_EQ(el1.iterateConnected(nullptr), true);
+ EXPECT_EQ(el1.iterateConnected(&el1), true);
+ EXPECT_EQ(el1.handleNewValueFromServer(nullptr), -1);
+ EXPECT_EQ(el1.handleCalcfgFromServer(nullptr), SUPLA_CALCFG_RESULT_NOT_SUPPORTED);
+
+ EXPECT_FALSE(el1.channel.isUpdateReady());
+ el1.channel.setNewValue(true);
+ EXPECT_TRUE(el1.channel.isUpdateReady());
+
+ EXPECT_CALL(time, millis)
+ .WillOnce(Return(0)) // #1 first call after value changed to true
+ .WillOnce(Return(200)) // #2 two calls after value changed to true and 100 ms passed
+ .WillOnce(Return(200)) // #2
+ .WillOnce(Return(250)) // #3 value changed, however not enough time passed
+ .WillOnce(Return(250)) // #4 value changed, however not enough time passed
+ .WillOnce(Return(400)) // #5 two calls after value changed and another >100 ms passed
+ .WillOnce(Return(400));
+
+ char array0[SUPLA_CHANNELVALUE_SIZE] = {};
+ char array1[SUPLA_CHANNELVALUE_SIZE] = {};
+ array1[0] = 1;
+ EXPECT_CALL(srpc, valueChanged(nullptr, 0, ElementsAreArray(array1))); // value at #2
+ EXPECT_CALL(srpc, valueChanged(nullptr, 0, ElementsAreArray(array0))); // value at #5
+
+
+ EXPECT_EQ(el1.iterateConnected(nullptr), true); // #1
+ EXPECT_EQ(el1.iterateConnected(nullptr), false); // #2
+
+ el1.channel.setNewValue(false);
+ EXPECT_EQ(el1.iterateConnected(nullptr), true); // #3
+ EXPECT_EQ(el1.iterateConnected(nullptr), true); // #4
+ EXPECT_EQ(el1.iterateConnected(nullptr), false); // #5
+}
+
+
+
diff --git a/lib/SuplaDevice/extras/test/InternalPinOutputTests/internal_pin_output_tests.cpp b/lib/SuplaDevice/extras/test/InternalPinOutputTests/internal_pin_output_tests.cpp
new file mode 100644
index 00000000..fe661d4d
--- /dev/null
+++ b/lib/SuplaDevice/extras/test/InternalPinOutputTests/internal_pin_output_tests.cpp
@@ -0,0 +1,353 @@
+/*
+ Copyright (C) AC SOFTWARE SP. Z O.O.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ 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 General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+using ::testing::Return;
+
+class ActionHandlerMock : public Supla::ActionHandler {
+ public:
+ MOCK_METHOD(void, handleAction, (int, int), (override));
+};
+
+TEST(InternalPinOutputTests, BasicMethodsTests) {
+ const int pin = 5;
+ const int pin2 = 6;
+ DigitalInterfaceMock ioMock;
+ TimeInterfaceMock timeMock;
+
+ EXPECT_CALL(timeMock, millis).WillRepeatedly(Return(0));
+
+ ::testing::InSequence seq;
+
+ EXPECT_CALL(ioMock, digitalWrite(pin, LOW)).Times(1);
+ EXPECT_CALL(ioMock, pinMode(pin, OUTPUT)).Times(1);
+
+ EXPECT_CALL(ioMock, digitalWrite(pin2, HIGH)).Times(1);
+ EXPECT_CALL(ioMock, pinMode(pin2, OUTPUT)).Times(1);
+
+ EXPECT_CALL(ioMock, digitalRead(pin)).WillOnce(Return(LOW));
+ EXPECT_CALL(ioMock, digitalRead(pin2)).WillOnce(Return(HIGH));
+
+ EXPECT_CALL(ioMock, digitalWrite(pin, HIGH)).Times(1);
+
+ EXPECT_CALL(ioMock, digitalWrite(pin2, LOW)).Times(1);
+
+ EXPECT_CALL(ioMock, digitalWrite(pin, LOW)).Times(1);
+
+ EXPECT_CALL(ioMock, digitalRead(pin)).WillOnce(Return(LOW));
+ EXPECT_CALL(ioMock, digitalWrite(pin, HIGH)).Times(1);
+
+ Supla::Control::InternalPinOutput ipo(pin);
+ Supla::Control::InternalPinOutput ipo2(pin2, false);
+
+
+ EXPECT_EQ(ipo.pinOnValue(), HIGH);
+ EXPECT_EQ(ipo.pinOffValue(), LOW);
+
+ EXPECT_EQ(ipo2.pinOnValue(), LOW);
+ EXPECT_EQ(ipo2.pinOffValue(), HIGH);
+
+ ipo.onInit();
+ ipo2.onInit();
+
+ EXPECT_EQ(ipo.isOn(), false);
+ EXPECT_EQ(ipo2.isOn(), false);
+
+ ipo.turnOn();
+ ipo2.turnOn();
+
+ ipo.turnOff();
+
+ ipo.toggle();
+}
+
+TEST(InternalPinOutputTests, DefaultInitialState) {
+ const int pin = 5;
+ const int pin2 = 6;
+ DigitalInterfaceMock ioMock;
+ TimeInterfaceMock timeMock;
+
+ EXPECT_CALL(timeMock, millis).WillRepeatedly(Return(0));
+
+ ::testing::InSequence seq;
+
+ EXPECT_CALL(ioMock, digitalWrite(pin, HIGH)).Times(1);
+ EXPECT_CALL(ioMock, pinMode(pin, OUTPUT)).Times(1);
+
+ EXPECT_CALL(ioMock, digitalWrite(pin2, HIGH)).Times(1);
+ EXPECT_CALL(ioMock, pinMode(pin2, OUTPUT)).Times(1);
+
+ Supla::Control::InternalPinOutput ipo(pin);
+ Supla::Control::InternalPinOutput ipo2(pin2, false);
+
+ ipo.setDefaultStateOn();
+ ipo2.setDefaultStateOff();
+
+ ipo.onInit();
+ ipo2.onInit();
+
+}
+
+TEST(InternalPinOutputTests, TurnOnWithIterations) {
+ const int pin = 5;
+ DigitalInterfaceMock ioMock;
+ TimeInterfaceMock timeMock;
+
+
+ ::testing::InSequence seq;
+
+ EXPECT_CALL(timeMock, millis).WillOnce(Return(0));
+ EXPECT_CALL(ioMock, digitalWrite(pin, LOW)).Times(1);
+ EXPECT_CALL(ioMock, pinMode(pin, OUTPUT)).Times(1);
+
+ EXPECT_CALL(timeMock, millis).WillOnce(Return(0));
+ EXPECT_CALL(ioMock, digitalWrite(pin, HIGH)).Times(1);
+
+
+ Supla::Control::InternalPinOutput ipo(pin);
+
+ ipo.onInit();
+
+ ipo.iterateAlways();
+ ipo.iterateAlways();
+
+ ipo.turnOn();
+ ipo.iterateAlways();
+ ipo.iterateAlways();
+}
+
+TEST(InternalPinOutputTests, TurnOnWithDuration) {
+ const int pin = 5;
+ DigitalInterfaceMock ioMock;
+ TimeInterfaceMock timeMock;
+
+
+ ::testing::InSequence seq;
+
+ EXPECT_CALL(timeMock, millis).WillOnce(Return(0));
+ EXPECT_CALL(ioMock, digitalWrite(pin, LOW)).Times(1);
+ EXPECT_CALL(ioMock, pinMode(pin, OUTPUT)).Times(1);
+
+ EXPECT_CALL(timeMock, millis).WillOnce(Return(0));
+ EXPECT_CALL(ioMock, digitalWrite(pin, HIGH)).Times(1);
+
+ EXPECT_CALL(timeMock, millis).WillOnce(Return(0));
+ EXPECT_CALL(timeMock, millis).WillOnce(Return(100));
+ EXPECT_CALL(timeMock, millis).WillOnce(Return(200));
+ EXPECT_CALL(timeMock, millis).WillOnce(Return(201));
+
+ EXPECT_CALL(ioMock, digitalRead(pin)).WillOnce(Return(HIGH));
+ EXPECT_CALL(timeMock, millis).WillOnce(Return(201));
+ EXPECT_CALL(ioMock, digitalWrite(pin, LOW)).Times(1);
+
+
+ Supla::Control::InternalPinOutput ipo(pin);
+
+ ipo.onInit();
+
+ ipo.iterateAlways();
+ ipo.iterateAlways();
+
+ ipo.turnOn(200);
+ ipo.iterateAlways(); // time 0
+ ipo.iterateAlways(); // time 100
+ ipo.iterateAlways(); // time 200
+ ipo.iterateAlways(); // time 201
+
+ ipo.iterateAlways();
+ ipo.iterateAlways();
+ ipo.iterateAlways();
+}
+
+TEST(InternalPinOutputTests, TurnOffWithDuration) {
+ const int pin = 5;
+ DigitalInterfaceMock ioMock;
+ TimeInterfaceMock timeMock;
+
+
+ ::testing::InSequence seq;
+
+ EXPECT_CALL(timeMock, millis).WillOnce(Return(0));
+ EXPECT_CALL(ioMock, digitalWrite(pin, LOW)).Times(1);
+ EXPECT_CALL(ioMock, pinMode(pin, OUTPUT)).Times(1);
+
+ EXPECT_CALL(timeMock, millis).WillOnce(Return(0));
+ EXPECT_CALL(ioMock, digitalWrite(pin, LOW)).Times(1);
+
+ EXPECT_CALL(timeMock, millis).WillOnce(Return(0));
+ EXPECT_CALL(timeMock, millis).WillOnce(Return(100));
+ EXPECT_CALL(timeMock, millis).WillOnce(Return(200));
+ EXPECT_CALL(timeMock, millis).WillOnce(Return(201));
+
+ EXPECT_CALL(ioMock, digitalRead(pin)).WillOnce(Return(LOW));
+ EXPECT_CALL(timeMock, millis).WillOnce(Return(201));
+ EXPECT_CALL(ioMock, digitalWrite(pin, HIGH)).Times(1);
+
+ Supla::Control::InternalPinOutput ipo(pin);
+
+ ipo.onInit();
+
+ ipo.iterateAlways();
+ ipo.iterateAlways();
+
+ ipo.turnOff(200);
+ ipo.iterateAlways(); // time 0
+ ipo.iterateAlways(); // time 100
+ ipo.iterateAlways(); // time 200
+ ipo.iterateAlways(); // time 201
+
+ ipo.iterateAlways();
+ ipo.iterateAlways();
+ ipo.iterateAlways();
+}
+
+
+TEST(InternalPinOutputTests, TurnOnWithStoredDuration) {
+ const int pin = 5;
+ DigitalInterfaceMock ioMock;
+ TimeInterfaceMock timeMock;
+
+
+ ::testing::InSequence seq;
+
+ EXPECT_CALL(timeMock, millis).WillOnce(Return(0));
+ EXPECT_CALL(ioMock, digitalWrite(pin, LOW)).Times(1);
+ EXPECT_CALL(ioMock, pinMode(pin, OUTPUT)).Times(1);
+
+ EXPECT_CALL(timeMock, millis).WillOnce(Return(0));
+ EXPECT_CALL(ioMock, digitalWrite(pin, HIGH)).Times(1);
+
+ EXPECT_CALL(timeMock, millis).WillOnce(Return(0));
+ EXPECT_CALL(timeMock, millis).WillOnce(Return(100));
+ EXPECT_CALL(timeMock, millis).WillOnce(Return(200));
+ EXPECT_CALL(timeMock, millis).WillOnce(Return(201));
+
+ EXPECT_CALL(ioMock, digitalRead(pin)).WillOnce(Return(HIGH));
+ EXPECT_CALL(timeMock, millis).WillOnce(Return(201));
+ EXPECT_CALL(ioMock, digitalWrite(pin, LOW)).Times(1);
+
+ EXPECT_CALL(timeMock, millis).WillOnce(Return(300));
+ EXPECT_CALL(ioMock, digitalWrite(pin, HIGH)).Times(1);
+ EXPECT_CALL(timeMock, millis).WillOnce(Return(400));
+ EXPECT_CALL(timeMock, millis).WillOnce(Return(600));
+ EXPECT_CALL(ioMock, digitalRead(pin)).WillOnce(Return(HIGH));
+ EXPECT_CALL(timeMock, millis).WillOnce(Return(600));
+ EXPECT_CALL(ioMock, digitalWrite(pin, LOW)).Times(1);
+
+ Supla::Control::InternalPinOutput ipo(pin);
+
+ ipo.onInit();
+
+ ipo.iterateAlways();
+ ipo.iterateAlways();
+
+ ipo.setDurationMs(200);
+
+ ipo.turnOn();
+ ipo.iterateAlways(); // time 0
+ ipo.iterateAlways(); // time 100
+ ipo.iterateAlways(); // time 200
+ ipo.iterateAlways(); // time 201
+
+ ipo.iterateAlways();
+ ipo.iterateAlways();
+ ipo.iterateAlways();
+
+ ipo.turnOn();
+ ipo.iterateAlways();
+ ipo.iterateAlways();
+ ipo.iterateAlways();
+}
+
+TEST(InternalPinOutputTests, HandleActionTests) {
+ const int pin = 5;
+ DigitalInterfaceMock ioMock;
+ TimeInterfaceMock timeMock;
+
+ EXPECT_CALL(timeMock, millis).WillRepeatedly(Return(0));
+
+ ::testing::InSequence seq;
+
+ EXPECT_CALL(ioMock, digitalWrite(pin, LOW)).Times(1); // onInit
+ EXPECT_CALL(ioMock, pinMode(pin, OUTPUT)).Times(1);
+
+ EXPECT_CALL(ioMock, digitalWrite(pin, HIGH)).Times(1); // Turn on
+
+ EXPECT_CALL(ioMock, digitalWrite(pin, LOW)).Times(1); // Turn off
+
+ EXPECT_CALL(ioMock, digitalRead(pin)).WillOnce(Return(LOW)); // Toggle
+ EXPECT_CALL(ioMock, digitalWrite(pin, HIGH)).Times(1);
+
+ Supla::Control::InternalPinOutput ipo(pin);
+
+ ipo.onInit();
+
+ ipo.iterateAlways();
+ ipo.iterateAlways();
+
+ ipo.handleAction(0, Supla::TURN_ON);
+
+ ipo.iterateAlways();
+ ipo.handleAction(0, Supla::TURN_OFF);
+
+ ipo.iterateAlways();
+ ipo.handleAction(0, Supla::TOGGLE);
+ ipo.iterateAlways();
+}
+
+TEST(InternalPinOutputTests, TurnOnWithAction) {
+ const int pin = 5;
+ DigitalInterfaceMock ioMock;
+ TimeInterfaceMock timeMock;
+ ActionHandlerMock ahMock;
+
+
+ ::testing::InSequence seq;
+
+ EXPECT_CALL(timeMock, millis).WillOnce(Return(0));
+ EXPECT_CALL(ahMock, handleAction(Supla::ON_TURN_OFF, Supla::TURN_OFF));
+ EXPECT_CALL(ahMock, handleAction(Supla::ON_CHANGE, 33));
+ EXPECT_CALL(ioMock, digitalWrite(pin, LOW)).Times(1);
+ EXPECT_CALL(ioMock, pinMode(pin, OUTPUT)).Times(1);
+
+ EXPECT_CALL(timeMock, millis).WillOnce(Return(0));
+ EXPECT_CALL(ahMock, handleAction(Supla::ON_TURN_ON, Supla::TURN_ON));
+ EXPECT_CALL(ahMock, handleAction(Supla::ON_CHANGE, 33));
+ EXPECT_CALL(ioMock, digitalWrite(pin, HIGH)).Times(1);
+
+
+ Supla::Control::InternalPinOutput ipo(pin);
+ ipo.addAction(Supla::TURN_ON, ahMock, Supla::ON_TURN_ON);
+ ipo.addAction(Supla::TURN_OFF, ahMock, Supla::ON_TURN_OFF);
+ ipo.addAction(33, ahMock, Supla::ON_CHANGE);
+
+ ipo.onInit();
+
+ ipo.iterateAlways();
+ ipo.iterateAlways();
+
+ ipo.turnOn();
+ ipo.iterateAlways();
+ ipo.iterateAlways();
+}
+
diff --git a/lib/SuplaDevice/extras/test/IoTests/io_tests.cpp b/lib/SuplaDevice/extras/test/IoTests/io_tests.cpp
new file mode 100644
index 00000000..0c9fc938
--- /dev/null
+++ b/lib/SuplaDevice/extras/test/IoTests/io_tests.cpp
@@ -0,0 +1,146 @@
+/*
+ Copyright (C) AC SOFTWARE SP. Z O.O.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ 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 General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include
+#include
+#include
+
+using ::testing::Return;
+
+class CustomIoMock : public Supla::Io {
+ public:
+ MOCK_METHOD(
+ void, customPinMode, (int channelNumber, uint8_t pin, uint8_t mode));
+ MOCK_METHOD(int, customDigitalRead, (int channelNumber, uint8_t pin));
+ MOCK_METHOD(
+ void, customDigitalWrite, (int channelNumber, uint8_t pin, uint8_t val));
+};
+
+TEST(IoTests, PinMode) {
+ DigitalInterfaceMock ioMock;
+ ::testing::InSequence seq;
+
+ EXPECT_CALL(ioMock, pinMode(3, INPUT));
+ EXPECT_CALL(ioMock, pinMode(0, OUTPUT));
+ EXPECT_CALL(ioMock, pinMode(3, INPUT_PULLUP));
+
+ Supla::Io::pinMode(3, INPUT);
+ Supla::Io::pinMode(0, OUTPUT);
+ Supla::Io::pinMode(3, INPUT_PULLUP);
+}
+
+TEST(IoTests, PinModeWithChannelNumber) {
+ DigitalInterfaceMock ioMock;
+ ::testing::InSequence seq;
+
+ EXPECT_CALL(ioMock, pinMode(3, INPUT));
+ EXPECT_CALL(ioMock, pinMode(0, OUTPUT));
+ EXPECT_CALL(ioMock, pinMode(3, INPUT_PULLUP));
+
+ Supla::Io::pinMode(10, 3, INPUT);
+ Supla::Io::pinMode(11, 0, OUTPUT);
+ Supla::Io::pinMode(12, 3, INPUT_PULLUP);
+}
+
+TEST(IoTests, DigitalWrite) {
+ DigitalInterfaceMock ioMock;
+ ::testing::InSequence seq;
+
+ EXPECT_CALL(ioMock, digitalWrite(3, HIGH));
+ EXPECT_CALL(ioMock, digitalWrite(3, LOW));
+ EXPECT_CALL(ioMock, digitalWrite(99, LOW));
+
+ Supla::Io::digitalWrite(3, HIGH);
+ Supla::Io::digitalWrite(3, LOW);
+ Supla::Io::digitalWrite(99, LOW);
+}
+
+TEST(IoTests, DigitalWriteWithChannel) {
+ DigitalInterfaceMock ioMock;
+ ::testing::InSequence seq;
+
+ EXPECT_CALL(ioMock, digitalWrite(3, HIGH));
+ EXPECT_CALL(ioMock, digitalWrite(3, LOW));
+ EXPECT_CALL(ioMock, digitalWrite(99, LOW));
+
+ Supla::Io::digitalWrite(3, HIGH);
+ Supla::Io::digitalWrite(3, LOW);
+ Supla::Io::digitalWrite(99, LOW);
+}
+
+TEST(IoTests, DigitalRead) {
+ DigitalInterfaceMock ioMock;
+
+ EXPECT_CALL(ioMock, digitalRead(3))
+ .WillOnce(Return(LOW))
+ .WillOnce(Return(HIGH))
+ .WillOnce(Return(LOW));
+
+ EXPECT_EQ(Supla::Io::digitalRead(3), LOW);
+ EXPECT_EQ(Supla::Io::digitalRead(3), HIGH);
+ EXPECT_EQ(Supla::Io::digitalRead(3), LOW);
+}
+
+TEST(IoTests, DigitalReadWithChannel) {
+ DigitalInterfaceMock ioMock;
+
+ EXPECT_CALL(ioMock, digitalRead(3))
+ .WillOnce(Return(LOW))
+ .WillOnce(Return(HIGH))
+ .WillOnce(Return(LOW));
+
+ EXPECT_EQ(Supla::Io::digitalRead(100, 3), LOW);
+ EXPECT_EQ(Supla::Io::digitalRead(100, 3), HIGH);
+ EXPECT_EQ(Supla::Io::digitalRead(-1, 3), LOW);
+}
+
+TEST(IoTest, OperationsWithCustomIoInteface) {
+ DigitalInterfaceMock hwInterfaceMock;
+ CustomIoMock ioMock;
+
+ EXPECT_CALL(hwInterfaceMock, pinMode).Times(0);
+ EXPECT_CALL(hwInterfaceMock, digitalWrite).Times(0);
+ EXPECT_CALL(hwInterfaceMock, digitalRead).Times(0);
+
+ EXPECT_CALL(ioMock, customPinMode(-1, 12, INPUT));
+ EXPECT_CALL(ioMock, customDigitalRead(-1, 11))
+ .WillOnce(Return(HIGH));
+ EXPECT_CALL(ioMock, customDigitalWrite(-1, 13, HIGH));
+
+ Supla::Io::pinMode(12, INPUT);
+ EXPECT_EQ(Supla::Io::digitalRead(11), HIGH);
+ Supla::Io::digitalWrite(13, HIGH);
+
+}
+TEST(IoTest, OperationsWithCustomIoIntefaceWithChannel) {
+ DigitalInterfaceMock hwInterfaceMock;
+ CustomIoMock ioMock;
+
+ // Custom io interface should not call arduino's methods
+ EXPECT_CALL(hwInterfaceMock, pinMode).Times(0);
+ EXPECT_CALL(hwInterfaceMock, digitalWrite).Times(0);
+ EXPECT_CALL(hwInterfaceMock, digitalRead).Times(0);
+
+ EXPECT_CALL(ioMock, customPinMode(6, 12, INPUT));
+ EXPECT_CALL(ioMock, customDigitalRead(6, 11))
+ .WillOnce(Return(HIGH));
+ EXPECT_CALL(ioMock, customDigitalWrite(6, 13, HIGH));
+
+ Supla::Io::pinMode(6, 12, INPUT);
+ EXPECT_EQ(Supla::Io::digitalRead(6, 11), HIGH);
+ Supla::Io::digitalWrite(6, 13, HIGH);
+
+}
diff --git a/lib/SuplaDevice/extras/test/LocalActionTests/local_action_tests.cpp b/lib/SuplaDevice/extras/test/LocalActionTests/local_action_tests.cpp
new file mode 100644
index 00000000..bbd03614
--- /dev/null
+++ b/lib/SuplaDevice/extras/test/LocalActionTests/local_action_tests.cpp
@@ -0,0 +1,177 @@
+/*
+ Copyright (C) AC SOFTWARE SP. Z O.O.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ 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 General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include
+#include
+#include
+
+class ActionHandlerMock : public Supla::ActionHandler {
+ public:
+ MOCK_METHOD(void, handleAction, (int, int), (override));
+};
+
+TEST(LocalActionTests, TwoItemsTests) {
+ auto b1 = new Supla::LocalAction;
+ auto b2 = new Supla::LocalAction;
+ ActionHandlerMock mock1;
+ ActionHandlerMock mock2;
+
+ int action1 = 1;
+ int action2 = 2;
+ int action3 = 3;
+ int action4 = 4;
+ int action5 = 5;
+ int event1 = 11;
+ int event2 = 12;
+ int event3 = 13;
+
+ EXPECT_CALL(mock1, handleAction(event1, action1));
+ EXPECT_CALL(mock1, handleAction(event1, action3));
+ EXPECT_CALL(mock2, handleAction(event3, action1));
+ EXPECT_CALL(mock1, handleAction(event2, action2));
+ EXPECT_CALL(mock1, handleAction(event2, action4));
+ EXPECT_CALL(mock1, handleAction(event2, action5));
+ EXPECT_CALL(mock2, handleAction(event1, action1));
+ EXPECT_CALL(mock2, handleAction(event2, action2));
+
+ b1->addAction(action1, mock1, event1);
+ b1->addAction(action2, mock1, event2);
+ b1->addAction(action3, mock1, event1);
+ b1->addAction(action4, mock1, event2);
+ b1->addAction(action5, mock1, event2);
+ b1->addAction(action1, mock2, event3);
+ b2->addAction(action1, mock2, event1);
+ b2->addAction(action2, mock2, event2);
+ b1->runAction(event1);
+ b1->runAction(event3);
+ b1->runAction(event2);
+
+ b2->runAction(event1);
+
+ delete b1;
+
+ b2->runAction(event2);
+
+ delete b2;
+}
+
+TEST(LocalActionTests, FourItemsTestsNoCalls) {
+ auto b1 = new Supla::LocalAction;
+ auto b2 = new Supla::LocalAction;
+ auto b3 = new Supla::LocalAction;
+ auto b4 = new Supla::LocalAction;
+ ActionHandlerMock mock1;
+ ActionHandlerMock mock2;
+ ActionHandlerMock mock3;
+ ActionHandlerMock mock4;
+
+ EXPECT_CALL(mock1, handleAction).Times(0);
+ EXPECT_CALL(mock2, handleAction).Times(0);
+ EXPECT_CALL(mock3, handleAction).Times(0);
+ EXPECT_CALL(mock4, handleAction).Times(0);
+
+ int action1 = 1;
+ int action2 = 2;
+ int action3 = 3;
+ int action4 = 4;
+ int action5 = 5;
+ int event1 = 11;
+ int event2 = 12;
+ int event3 = 13;
+ int event4 = 14;
+
+ b4->addAction(action4, mock4, event4);
+ b3->addAction(action3, mock3, event3);
+ b1->addAction(action1, mock1, event1);
+ b2->addAction(action2, mock2, event2);
+
+ b1->runAction(event2);
+ b1->runAction(event3);
+ b1->runAction(event4);
+
+ b2->runAction(event1);
+ b2->runAction(event3);
+ b2->runAction(event4);
+
+ b3->runAction(event1);
+ b3->runAction(event2);
+ b3->runAction(event4);
+
+ b4->runAction(event1);
+ b4->runAction(event2);
+ b4->runAction(event3);
+
+ delete b1;
+ delete b2;
+ delete b3;
+ delete b4;
+}
+
+TEST(LocalActionTests, FourItemsTestsWithCalls) {
+ auto b1 = new Supla::LocalAction;
+ auto b2 = new Supla::LocalAction;
+ auto b3 = new Supla::LocalAction;
+ auto b4 = new Supla::LocalAction;
+ ActionHandlerMock mock1;
+ ActionHandlerMock mock2;
+ ActionHandlerMock mock3;
+ ActionHandlerMock mock4;
+
+ int action1 = 1;
+ int action2 = 2;
+ int action3 = 3;
+ int action4 = 4;
+ int action5 = 5;
+ int event1 = 11;
+ int event2 = 12;
+ int event3 = 13;
+ int event4 = 14;
+
+ EXPECT_CALL(mock1, handleAction(event1, action1));
+ EXPECT_CALL(mock2, handleAction(event2, action2));
+ EXPECT_CALL(mock3, handleAction(event3, action3));
+ EXPECT_CALL(mock4, handleAction(event4, action4));
+
+ b4->addAction(action4, mock4, event4);
+ b3->addAction(action3, mock3, event3);
+ b1->addAction(action1, mock1, event1);
+ b2->addAction(action2, mock2, event2);
+
+ b1->runAction(event1);
+ b1->runAction(event2);
+ b1->runAction(event3);
+ b1->runAction(event4);
+
+ b2->runAction(event1);
+ b2->runAction(event2);
+ b2->runAction(event3);
+ b2->runAction(event4);
+
+ b3->runAction(event3);
+ b3->runAction(event1);
+ b3->runAction(event2);
+ b3->runAction(event4);
+
+ b4->runAction(event1);
+ b4->runAction(event2);
+ b4->runAction(event3);
+ b4->runAction(event4);
+
+ delete b1;
+ delete b2;
+ delete b3;
+ delete b4;
+}
diff --git a/lib/SuplaDevice/extras/test/PinStatusLedTests/pin_status_led_tests.cpp b/lib/SuplaDevice/extras/test/PinStatusLedTests/pin_status_led_tests.cpp
new file mode 100644
index 00000000..c9118731
--- /dev/null
+++ b/lib/SuplaDevice/extras/test/PinStatusLedTests/pin_status_led_tests.cpp
@@ -0,0 +1,103 @@
+/*
+ Copyright (C) AC SOFTWARE SP. Z O.O.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ 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 General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include
+#include
+
+#include
+#include
+
+
+using ::testing::Return;
+
+TEST(PinStatusLedTest, ReplicationTest) {
+ EXPECT_EQ(DigitalInterface::instance, nullptr);
+
+ DigitalInterfaceMock ioMock;
+ TimeInterfaceMock timeMock;
+
+
+ ::testing::InSequence seq;
+
+ EXPECT_CALL(ioMock, digitalRead(1)).WillOnce(Return(LOW));
+ EXPECT_CALL(ioMock, digitalRead(2)).WillOnce(Return(LOW));
+// EXPECT_CALL(ioMock, digitalWrite(2, LOW)).Times(1);
+ EXPECT_CALL(ioMock, pinMode(2, OUTPUT)).Times(1);
+
+ EXPECT_CALL(ioMock, digitalRead(1)).WillOnce(Return(LOW));
+ EXPECT_CALL(ioMock, digitalRead(2)).WillOnce(Return(LOW));
+// EXPECT_CALL(ioMock, digitalWrite(2, LOW)).Times(1);
+
+ EXPECT_CALL(ioMock, digitalRead(1)).WillOnce(Return(HIGH));
+ EXPECT_CALL(ioMock, digitalRead(2)).WillOnce(Return(LOW));
+ EXPECT_CALL(ioMock, digitalWrite(2, HIGH)).Times(1);
+
+ EXPECT_CALL(ioMock, digitalRead(1)).WillOnce(Return(LOW));
+ EXPECT_CALL(ioMock, digitalRead(2)).WillOnce(Return(HIGH));
+ EXPECT_CALL(ioMock, digitalWrite(2, LOW)).Times(1);
+
+ Supla::Control::PinStatusLed led(1, 2);
+ led.onInit();
+ led.iterateAlways(); // LOW->LOW
+ led.iterateAlways(); // HIGH->HIGH
+ led.iterateAlways(); // LOW->LOW
+
+}
+
+TEST(PinStatusLedTest, ReplicationTestWithInvertedLogic) {
+ EXPECT_EQ(DigitalInterface::instance, nullptr);
+
+ DigitalInterfaceMock ioMock;
+ TimeInterfaceMock timeMock;
+
+
+ ::testing::InSequence seq;
+
+ EXPECT_CALL(ioMock, digitalRead(1)).WillOnce(Return(LOW)); // onInit
+ EXPECT_CALL(ioMock, digitalRead(2)).WillOnce(Return(LOW));
+ EXPECT_CALL(ioMock, digitalWrite(2, HIGH)).Times(1);
+ EXPECT_CALL(ioMock, pinMode(2, OUTPUT)).Times(1);
+
+ EXPECT_CALL(ioMock, digitalRead(1)).WillOnce(Return(LOW)); // iterateAlways
+ EXPECT_CALL(ioMock, digitalRead(2)).WillOnce(Return(HIGH));
+// EXPECT_CALL(ioMock, digitalWrite(2, HIGH)).Times(1);
+
+ EXPECT_CALL(ioMock, digitalRead(1)).WillOnce(Return(HIGH));
+ EXPECT_CALL(ioMock, digitalRead(2)).WillOnce(Return(HIGH));
+ EXPECT_CALL(ioMock, digitalWrite(2, LOW)).Times(1);
+
+ EXPECT_CALL(ioMock, digitalRead(1)).WillOnce(Return(LOW));
+ EXPECT_CALL(ioMock, digitalRead(2)).WillOnce(Return(LOW));
+ EXPECT_CALL(ioMock, digitalWrite(2, HIGH)).Times(1);
+
+ EXPECT_CALL(ioMock, digitalRead(1)).WillOnce(Return(LOW)); // disable inverted logic
+ EXPECT_CALL(ioMock, digitalRead(2)).WillOnce(Return(HIGH));
+ EXPECT_CALL(ioMock, digitalWrite(2, LOW)).Times(1);
+
+ EXPECT_CALL(ioMock, digitalRead(1)).WillOnce(Return(LOW));
+ EXPECT_CALL(ioMock, digitalRead(2)).WillOnce(Return(LOW));
+// EXPECT_CALL(ioMock, digitalWrite(2, HIGH)).Times(1);
+
+ Supla::Control::PinStatusLed led(1, 2, true);
+ led.onInit();
+ led.iterateAlways(); // LOW->HIGH
+ led.iterateAlways(); // HIGH->LOW
+ led.iterateAlways(); // LOW->HIGH
+
+ led.setInvertedLogic(false); // LOW->LOW
+ led.iterateAlways(); // HIGH->HIGH
+
+}
diff --git a/lib/SuplaDevice/extras/test/SensorTests/thermometer_tests.cpp b/lib/SuplaDevice/extras/test/SensorTests/thermometer_tests.cpp
new file mode 100644
index 00000000..cea47588
--- /dev/null
+++ b/lib/SuplaDevice/extras/test/SensorTests/thermometer_tests.cpp
@@ -0,0 +1,24 @@
+/*
+ Copyright (C) AC SOFTWARE SP. Z O.O.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ 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 General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include
+#include
+#include
+
+TEST(ThermometerTests, BasicTest) {
+ EXPECT_TRUE(true);
+}
+
diff --git a/lib/SuplaDevice/extras/test/UptimeTests/uptime_tests.cpp b/lib/SuplaDevice/extras/test/UptimeTests/uptime_tests.cpp
new file mode 100644
index 00000000..59241f9b
--- /dev/null
+++ b/lib/SuplaDevice/extras/test/UptimeTests/uptime_tests.cpp
@@ -0,0 +1,76 @@
+/*
+ Copyright (C) AC SOFTWARE SP. Z O.O.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ 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 General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include
+#include
+
+TEST(UptimeTests, LastResetCauseSetAndGet) {
+ Supla::Uptime uptime;
+ EXPECT_EQ(uptime.getUptime(), 0);
+ EXPECT_EQ(uptime.getConnectionUptime(), 0);
+ EXPECT_EQ(uptime.getLastResetCause(), SUPLA_LASTCONNECTIONRESETCAUSE_UNKNOWN);
+
+ // setter should not work unless first resetConnectionUptime is called
+ uptime.setConnectionLostCause(SUPLA_LASTCONNECTIONRESETCAUSE_WIFI_CONNECTION_LOST);
+ EXPECT_EQ(uptime.getUptime(), 0);
+ EXPECT_EQ(uptime.getConnectionUptime(), 0);
+ EXPECT_EQ(uptime.getLastResetCause(), SUPLA_LASTCONNECTIONRESETCAUSE_UNKNOWN);
+
+ uptime.resetConnectionUptime();
+ uptime.setConnectionLostCause(SUPLA_LASTCONNECTIONRESETCAUSE_WIFI_CONNECTION_LOST);
+ EXPECT_EQ(uptime.getUptime(), 0);
+ EXPECT_EQ(uptime.getConnectionUptime(), 0);
+ EXPECT_EQ(uptime.getLastResetCause(), SUPLA_LASTCONNECTIONRESETCAUSE_WIFI_CONNECTION_LOST);
+}
+
+TEST(UptimeTests, IterateShouldIncreaseUptimeCounters) {
+ Supla::Uptime uptime;
+ unsigned long millis = 0;
+
+ EXPECT_EQ(uptime.getUptime(), 0);
+ EXPECT_EQ(uptime.getConnectionUptime(), 0);
+ EXPECT_EQ(uptime.getLastResetCause(), SUPLA_LASTCONNECTIONRESETCAUSE_UNKNOWN);
+
+ millis += 999;
+ uptime.iterate(millis);
+ EXPECT_EQ(uptime.getUptime(), 0);
+ EXPECT_EQ(uptime.getConnectionUptime(), 0);
+ EXPECT_EQ(uptime.getLastResetCause(), SUPLA_LASTCONNECTIONRESETCAUSE_UNKNOWN);
+
+ millis += 1500;
+ uptime.iterate(millis);
+ EXPECT_EQ(uptime.getUptime(), 2);
+ EXPECT_EQ(uptime.getConnectionUptime(), 2);
+ EXPECT_EQ(uptime.getLastResetCause(), SUPLA_LASTCONNECTIONRESETCAUSE_UNKNOWN);
+
+ millis += 20000;
+ uptime.iterate(millis);
+ EXPECT_EQ(uptime.getUptime(), 22);
+ EXPECT_EQ(uptime.getConnectionUptime(), 22);
+ EXPECT_EQ(uptime.getLastResetCause(), SUPLA_LASTCONNECTIONRESETCAUSE_UNKNOWN);
+
+ uptime.resetConnectionUptime();
+ EXPECT_EQ(uptime.getUptime(), 22);
+ EXPECT_EQ(uptime.getConnectionUptime(), 0);
+ EXPECT_EQ(uptime.getLastResetCause(), SUPLA_LASTCONNECTIONRESETCAUSE_UNKNOWN);
+
+ millis += 2500;
+ uptime.iterate(millis);
+ EXPECT_EQ(uptime.getUptime(), 24);
+ EXPECT_EQ(uptime.getConnectionUptime(), 2);
+ EXPECT_EQ(uptime.getLastResetCause(), SUPLA_LASTCONNECTIONRESETCAUSE_UNKNOWN);
+}
+
diff --git a/lib/SuplaDevice/extras/test/doubles/Arduino.h b/lib/SuplaDevice/extras/test/doubles/Arduino.h
new file mode 100644
index 00000000..518485d2
--- /dev/null
+++ b/lib/SuplaDevice/extras/test/doubles/Arduino.h
@@ -0,0 +1,115 @@
+#ifndef _test_double_arduino_h
+#define _test_double_arduino_h
+
+#include
+
+#include
+
+typedef std::string String;
+
+#define LSBFIRST 0
+#define INPUT 0
+#define INPUT_PULLUP 2
+#define OUTPUT 1
+#define HIGH 1
+#define LOW 0
+
+void digitalWrite(uint8_t pin, uint8_t val);
+int digitalRead(uint8_t pin);
+void pinMode(uint8_t pin, uint8_t mode);
+unsigned long millis();
+
+
+class SerialStub {
+ public:
+ SerialStub() {
+ }
+
+ virtual ~SerialStub() {
+ }
+
+ int printf(const char *format, ...) {
+ return 0;
+ }
+ int print(const String &) {
+ return 0;
+ }
+
+ int print(const char[]) {
+ return 0;
+ }
+
+ int print(char) {
+ return 0;
+ }
+
+ int print(unsigned char) {
+ return 0;
+ }
+
+ int print(int) {
+ return 0;
+ }
+
+ int print(unsigned int) {
+ return 0;
+ }
+
+ int print(long) {
+ return 0;
+ }
+
+ int print(unsigned long) {
+ return 0;
+ }
+
+ int print(double) {
+ return 0;
+ }
+
+
+ int println(const String &s) {
+ return 0;
+ }
+
+ int println(const char[]) {
+ return 0;
+ }
+
+ int println(char) {
+ return 0;
+ }
+
+ int println(unsigned char) {
+ return 0;
+ }
+
+ int println(int) {
+ return 0;
+ }
+
+ int println(unsigned int) {
+ return 0;
+ }
+
+ int println(long) {
+ return 0;
+ }
+
+ int println(unsigned long) {
+ return 0;
+ }
+
+ int println(double) {
+ return 0;
+ }
+
+ int println(void) {
+ return 0;
+ }
+
+};
+
+extern SerialStub Serial;
+
+#endif
diff --git a/lib/SuplaDevice/extras/test/doubles/arduino_mock.cpp b/lib/SuplaDevice/extras/test/doubles/arduino_mock.cpp
new file mode 100644
index 00000000..f64576a2
--- /dev/null
+++ b/lib/SuplaDevice/extras/test/doubles/arduino_mock.cpp
@@ -0,0 +1,60 @@
+/*
+ Copyright (C) AC SOFTWARE SP. Z O.O.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ 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 General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+
+#include "Arduino.h"
+#include
+#include "arduino_mock.h"
+
+SerialStub Serial;
+
+DigitalInterface::DigitalInterface() {
+ instance = this;
+}
+
+DigitalInterface::~DigitalInterface() {
+ instance = nullptr;
+}
+
+DigitalInterface *DigitalInterface::instance = nullptr;
+
+TimeInterface::TimeInterface() {
+ instance = this;
+}
+
+TimeInterface::~TimeInterface() {
+ instance = nullptr;
+}
+
+TimeInterface *TimeInterface::instance = nullptr;
+
+void digitalWrite(uint8_t pin, uint8_t val) {
+ DigitalInterface::instance->digitalWrite(pin, val);
+}
+
+int digitalRead(uint8_t pin) {
+ return DigitalInterface::instance->digitalRead(pin);
+}
+
+void pinMode(uint8_t pin, uint8_t mode) {
+ DigitalInterface::instance->pinMode(pin, mode);
+}
+
+unsigned long millis() {
+ return TimeInterface::instance->millis();
+}
+
+
diff --git a/lib/SuplaDevice/extras/test/doubles/arduino_mock.h b/lib/SuplaDevice/extras/test/doubles/arduino_mock.h
new file mode 100644
index 00000000..8daf5a1e
--- /dev/null
+++ b/lib/SuplaDevice/extras/test/doubles/arduino_mock.h
@@ -0,0 +1,57 @@
+/*
+ Copyright (C) AC SOFTWARE SP. Z O.O.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ 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 General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#ifndef _arduino_mock_h
+#define _arduino_mock_h
+
+#include "Arduino.h"
+#include
+
+class DigitalInterface {
+ public:
+ DigitalInterface();
+ virtual ~DigitalInterface();
+ virtual void digitalWrite(uint8_t, uint8_t) = 0;
+ virtual int digitalRead(uint8_t) = 0;
+ virtual void pinMode(uint8_t, uint8_t) = 0;
+
+ static DigitalInterface *instance;
+};
+
+class TimeInterface {
+ public:
+ TimeInterface();
+ virtual ~TimeInterface();
+ virtual unsigned long millis() = 0;
+
+ static TimeInterface *instance;
+};
+
+
+class DigitalInterfaceMock : public DigitalInterface {
+ public:
+ MOCK_METHOD(void, digitalWrite, (uint8_t, uint8_t), (override));
+ MOCK_METHOD(int, digitalRead, (uint8_t), (override));
+ MOCK_METHOD(void, pinMode, (uint8_t, uint8_t), (override));
+
+};
+
+class TimeInterfaceMock : public TimeInterface {
+ public:
+ MOCK_METHOD(unsigned long, millis, (), (override));
+};
+
+#endif
diff --git a/lib/SuplaDevice/extras/test/doubles/log.cpp b/lib/SuplaDevice/extras/test/doubles/log.cpp
new file mode 100644
index 00000000..e117cc36
--- /dev/null
+++ b/lib/SuplaDevice/extras/test/doubles/log.cpp
@@ -0,0 +1,22 @@
+/*
+ Copyright (C) AC SOFTWARE SP. Z O.O.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ 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 General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include
+
+void supla_log(int __pri, const char *__fmt, ...) {
+ return;
+}
+
diff --git a/lib/SuplaDevice/extras/test/doubles/srpc.cpp b/lib/SuplaDevice/extras/test/doubles/srpc.cpp
new file mode 100644
index 00000000..5ac9386a
--- /dev/null
+++ b/lib/SuplaDevice/extras/test/doubles/srpc.cpp
@@ -0,0 +1,29 @@
+/*
+ Copyright (C) AC SOFTWARE SP. Z O.O.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ 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 General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include
+
+_supla_int_t SRPC_ICACHE_FLASH srpc_ds_async_channel_extendedvalue_changed(
+ void *_srpc, unsigned char channel_number,
+ TSuplaChannelExtendedValue *value) {
+ return 0;
+}
+
+_supla_int_t SRPC_ICACHE_FLASH srpc_ds_async_channel_value_changed(
+ void *_srpc, unsigned char channel_number, char *value) {
+ return 0;
+}
+
diff --git a/lib/SuplaDevice/extras/test/doubles/srpc_mock.cpp b/lib/SuplaDevice/extras/test/doubles/srpc_mock.cpp
new file mode 100644
index 00000000..46d5e16c
--- /dev/null
+++ b/lib/SuplaDevice/extras/test/doubles/srpc_mock.cpp
@@ -0,0 +1,42 @@
+/*
+ Copyright (C) AC SOFTWARE SP. Z O.O.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ 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 General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include
+#include "srpc_mock.h"
+
+_supla_int_t SRPC_ICACHE_FLASH srpc_ds_async_channel_extendedvalue_changed(
+ void *_srpc, unsigned char channel_number,
+ TSuplaChannelExtendedValue *value) {
+ return 0;
+}
+
+_supla_int_t SRPC_ICACHE_FLASH srpc_ds_async_channel_value_changed(
+ void *_srpc, unsigned char channel_number, char *value) {
+ std::vector vec(value, value + 8);
+ return SrpcInterface::instance->valueChanged(_srpc, channel_number, vec);
+}
+
+SrpcInterface::SrpcInterface() {
+ instance = this;
+}
+
+SrpcInterface::~SrpcInterface() {
+ instance = nullptr;
+}
+
+SrpcInterface *SrpcInterface::instance = nullptr;
+
+
diff --git a/lib/SuplaDevice/extras/test/doubles/srpc_mock.h b/lib/SuplaDevice/extras/test/doubles/srpc_mock.h
new file mode 100644
index 00000000..1c7d677c
--- /dev/null
+++ b/lib/SuplaDevice/extras/test/doubles/srpc_mock.h
@@ -0,0 +1,39 @@
+/*
+ Copyright (C) AC SOFTWARE SP. Z O.O.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ 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 General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#ifndef _srpc_mock_h
+#define _srpc_mock_h
+
+#include
+#include
+#include
+
+class SrpcInterface {
+ public:
+ SrpcInterface();
+ virtual ~SrpcInterface();
+
+ virtual _supla_int_t valueChanged(void *srpc, unsigned char channelNumber, std::vector value) = 0;
+
+ static SrpcInterface *instance;
+};
+
+class SrpcMock : public SrpcInterface {
+ public:
+ MOCK_METHOD(_supla_int_t, valueChanged, (void *, unsigned char, std::vector), (override));
+};
+
+#endif
diff --git a/lib/SuplaDevice/library.properties b/lib/SuplaDevice/library.properties
index a1277c9e..87d96835 100644
--- a/lib/SuplaDevice/library.properties
+++ b/lib/SuplaDevice/library.properties
@@ -1,12 +1,11 @@
name=SuplaDevice
-author=Przemyslaw Zygmunt
-email=Przemyslaw Zygmunt
+author=AC SOFTWARE SP. Z O.O.
maintainer=Krzysztof Lewandowski
-sentence=Library enables you to connect the device to SUPLA system.
-paragraph=The Library supports Ethernet modules based on ENC28J60 and the popular Ethernet Shield based on W5100. Regarding the ENC28J60 chip, additional UIPEthernet library must be installed. WiFi interface on ESP8266 based devices is also supported.
-url=https://www.supla.org
+sentence=Library enables you to connect the device to the SUPLA automation system.
+paragraph=It provides easy interface for adding various sensors, relays, buttons, roller shutters, etc. that can be controlled via SUPLA Cloud and application on mobile device.
+url=https://github.com/SUPLA/arduino
architectures=avr,esp32,esp8266
-version=2.3
+version=2.3.2
dependencies=
core-dependencies=arduino (>=1.5.0)
category=Communication
diff --git a/lib/SuplaDevice/readme.md b/lib/SuplaDevice/readme.md
new file mode 100644
index 00000000..a80f3eca
--- /dev/null
+++ b/lib/SuplaDevice/readme.md
@@ -0,0 +1,248 @@
+# SUPLA project
+
+[SUPLA](https://www.supla.org) is an open source project for home automation.
+
+# SuplaDevice library for Arduino IDE
+
+SuplaDevice is a library for [Arduino IDE](https://www.arduino.cc/en/main/software) that allows to implement devices working with [Supla](https://www.supla.org).
+
+## Library installation
+
+There are few options how to install library in Arduino IDE. Here is one example:
+1. Download SuplaDevice repository as a zip file (click green "Code" button on github repository)
+2. Extract downloaded zip file
+3. Copy whole SuplaDevice subfolder to a location where Arduino keeps libraries (in Arduino IDE open File->Preferences and there is a sketch location folder - libraries are kept in "libraries" subfolder)
+4. You should be able to open SuplaDevice exmaples in Arduino IDE
+
+## Hardware requirements
+
+### Arduino Mega
+SuplaDevice works with Arduino Mega boards. Currently Arduino Uno is not supported because of RAM limitations. It should work on other Arduino boards with at least 8 kB of RAM.
+Following network interfaces are supported:
+* Ethernet Shield with W5100 chipset
+* ENC28J60 (not recommended - see Supported hardware section)
+
+Warning: WiFi shields are currently not supported
+
+### ESP8266
+ESP8266 boards are supported. Network connection is done via internal WiFi. Tested with ESP8266 boards 2.6.3.
+Most probably it will work with other ESP8266 compatible boards.
+
+### ESP32
+Experimental support for ESP32 boards is provided. Some issues seen with reconnection to WiFi router which requires further analysis.
+
+## Installation
+
+Before you start, you will need to:
+1. install Arduino IDE,
+2. install support for your board
+3. install driver for your USB to serial converter device (it can be external device, or build in on your board)
+4. make sure that communication over serial interface with your board is working (i.e. check some example Arduino application)
+5. download and install this librarary by copying SuplaDevice folder into your Arduino library folder
+
+Steps 1-4 are standard Arudino IDE setup procedures not related to SuplaDevice library. You can find many tutorials on Internet with detailed instructions. Tutorials doesn't have to be related in any way with Supla.
+
+After step 5 you should see Supla example applications in Arduino IDE examples. Select one and have fun! Example file requires adjustments before you compile them and upload to your board. Please read all comments in example and make proper adjustments.
+
+## Usage
+
+### Network interfaces
+Supported network interfaces for Arduino Mega:
+* Ethernet Shield - with W5100 chipset. Include `` and add `Supla::EthernetShield ethernet;` as a global variable.
+* ENC28J60 - it requires additional UIPEthenet library (https://github.com/ntruchsess/arduino_uip). Include `` and
+add `Supla::ENC28J60 ethernet;` as a global variable. Warning: network initialization on this library is blocking. In case of missing ENC28J60 board
+or some other problem with network, program will stuck on initialization and will not work until connection is properly esablished.
+Second warning: UIPEthernet library is consuming few hundred of bytes of RAM memory more, compared to standard Ethernet library.
+
+Supported network interface for ESP8266:
+* There is a native WiFi controller. Include `` and add `Supla::ESPWifi wifi(ssid, password);` as a global variable and provide SSID and password in constructor.
+Warning: by default connection with Supla server is encrypted. Default settings of SSL consumes big amount of RAM.
+To disable SSL connection, use:
+ `wifi.enableSSL(false);`
+
+
+
+SSL certificate verification.
+If you specify Supla's server certificate thumbprint there will be additional verification proceeded. Please use this method to configure fingerprint for validation:
+ `wifi.setServersCertFingerprint("9ba818295ec60652f8221500e15288d7a611177");'
+
+
+
+Supported network interface for ESP32:
+* There is a native WiFi controller. Include `` and add `Supla::ESP32Wifi wifi(ssid, password);` as a global variable and provide SSID and password in constructor.
+
+### Exmaples
+
+Each example can run on Arduino Mega, ESP8266, or ESP32 board - unless mentioned otherwise in comments. Please read comments in example files and uncomment proper library for your network interface.
+
+SuplaSomfy - this example is not updated yet.
+
+### Folder structure
+
+* `supla-common` - Supla protocol definitions and structures. There are also methods to handle low level communication with Supla server, like message coding, decoding, sending and receiving. Those files are common with `supla-core` and the same code is run on multiple Supla platforms and services
+* `supla/network` - implementation of network interfaces for supported boards
+* `supla/sensor` - implementation of Supla sensor channels (thermometers, open/close sensors, etc.)
+* `supla/control` - implementation of Supla control channels (various combinations of relays, buttons, action triggers)
+* `supla/clock` - time services used in library (i.e. RTC)
+* `supla` - all common classes are defined in main `supla` folder. You can find there classes that create framework on which all other components work.
+
+Some functions from above folders have dependencies to external libraries. Please check documentation included in header files.
+
+### How does it work?
+
+Everything that is visible in Supla (in Cloud, on API, mobile application) is called "channel". Supla channels are used to control relays, read temperature, check if garage door is open.
+
+SuplaDevice implements support for channels in `Channel` and `ChannelExtended` classes. Instances of those classes are part of objects called `Element` which are building blocks for any SuplaDevice application.
+
+All sensors, relays, buttons objects inherits from `Element` class. Each instance of such object will automatically register in SuplaDevice and proper virtual methods will be called by SuplaDevice in a specified way.
+
+All elements have to be constructed before `SuplaDevice.begin()` method is called.
+
+Supla channel number is assigned to each elemement with channel in an order of creation of objects. First channel will get number 0, second 1, etc. Supla server will not accept registration of device when order of channels is changed, or some channel is removed. In such case, you should remove device from Supla Cloud and register it again from scratch.
+
+`Element` class defines follwoing virtual methods that are called by SuplaDevice:
+1. `onInit` - called first within `SuplaDevice.begin()` method. It should initialize your element.
+2. `onLoadState` - called second within `SuplaDevice.begin()` method. It reads configuration data from persistent memory storage.
+3. `onSaveState` - called in `SuplaDevice.iterate()` - it saves state data to persistant storage. It is not called on each iteration. `Storage` class makes sure that storing to memory does not happen to often and time delay between saves depends on implementation.
+3. `iterateAlways` - called on each iteration of `SuplaDevice.iterate()` method, regardless of network/connection status. Be careful - some other methods called in `SuplaDevice.iterate()` method may block program execution for some time (even few seconds) - i.e. trying to establish connection with Supla server is blocking - in case server is not accessible, it will iterfere with `iterateAlways` method. So time critical functions should not be put here.
+4. `iterateConnected` - called on each iterateion of `SuplaDevice.iterate()` method when device is connected and properly registered in Supla server. This method usually checks if there is some new data to be send to server (i.e. new temperature reading) and sends it.
+5. `onTimer` - called every 10 ms after enabling in `SuplaDevice.begin()`
+6. `onFastTimer` - called every 1 ms (0.5 ms in case of Arudino Mega) after enabling in `SuplaDevice.begin()`
+
+## How to migrate programs written in SuplaDevice libraray versions 1.6 and older
+
+For Arduino Mega applications include proper network interface header:
+```
+// Choose proper network interface for your card:
+// Arduino Mega with EthernetShield W5100:
+#include
+// Ethernet MAC address
+uint8_t mac[6] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05};
+Supla::EthernetShield ethernet(mac);
+//
+// Arduino Mega with ENC28J60:
+// #include
+// Supla::ENC28J60 ethernet(mac);
+
+```
+
+For ESP8266 based applications include wifi header and provide WIFI SSID and password:
+```
+// ESP8266 based board:
+#include
+Supla::ESPWifi wifi("your_wifi_ssid", "your_wifi_password");
+```
+
+In case of ESP8266 remove all methods that defined network interface. They were usually added on the bottom of ino file, after end of loop() method, i.e.:
+```
+// Supla.org ethernet layer
+ int supla_arduino_tcp_read(void *buf, int count) {
+...
+SuplaDeviceCallbacks supla_arduino_get_callbacks(void) {
+...
+```
+
+Remove also those lines:
+```
+#define SUPLADEVICE_CPP
+WiFiClient client;
+```
+You may also remove all WIFI related includes from ino file.
+
+Common instruction for all boards:
+
+If you use local IP address, please provide it in constructor of your network inteface class, i.e.:
+```
+Supla::EthernetShield ethernet(mac, localIp);
+```
+
+After that go to SuplaDevice.begin() method. Old code looked like this
+```
+SuplaDevice.begin(GUID, // Global Unique Identifier
+ mac, // Ethernet MAC address
+ "svr1.supla.org", // SUPLA server address
+ locationId, // Location ID
+ locationPassword); // Location Password
+```
+This method requires now different set of parameters:
+```
+ SuplaDevice.begin(GUID, // Global Unique Identifier
+ "svr1.supla.org", // SUPLA server address
+ "mail@address.pl", // Email address
+ AUTHKEY); // Authentication key
+```
+What is different? Well, GUID and Supla server address it the same as previously. MAC address, location ID, location password are removed.
+MAC address was moved to network interface class. Location ID and password were replaced with new authentication method - via email address
+and authentication key. You can generate your authentication key in the same way as GUID (it is actually in exactly the same format):
+```
+// Generate AUTHKEY from https://www.supla.org/arduino/get-authkey
+char AUTHKEY[SUPLA_AUTHKEY_SIZE] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+```
+
+Next change is for custom digitalWrite and digitalRead methods. Those can be used to create virtual digital pins. Instead of adding custom
+callback method that overrides digitalWrite/Read method, you should create a new class which inhertis from Supla::Io base class and define
+your own customDigitalRead/Write methods. Here is short example (you can put this code in ino file, before setup()):
+```
+#include
+
+class MyDigitalRead : public Supla::Io {
+ public:
+ int customDigitalRead(int channelNumber, uint8_t pin) {
+ if (channelNumber == MY_EXTRA_VIRTUAL_CHANNEL) {
+ return someCustomSourceOfData.getValue();
+ } else {
+ return ::digitalRead(pin);
+ }
+ }
+}
+
+MyDigitalRead instanceMyDigitalRead;
+```
+
+All channels from old version of library should be removed and created again in a new format. Please check instructions below how to add each type of channel.
+
+## Supported channels
+### Sensors
+Sensor category is for all elements/channels that reads something and provides data to Supla serwer.
+
+
+### Control
+Control category is for all elements/channels that are used to control something, i.e. relays, buttons, RGBW.
+
+## Supported persistant memory storage
+Storage class is used as an abstraction for different persistant memory devices. Some elements/channels will not work properly without storage and some will have limitted functionalities. I.e. `ImpulseCounter` requires storage to save counter value, so it could be restored after reset, or `RollerShutter` requires storage to keep openin/closing times and current shutter possition. Currently two variants of storage classes are supported.
+### EEPROM/Flash memory
+EEPROM (in case of Arduino Mega) and Flash (in case of ESP) are build into most of boards. Usually writing should be safe for 100 000 write operations (on each bit). So in order to limit those operations, this kind of Storage will save data in longer time periods (every few minutes). Supla will not write data if there is no change.
+```
+#include
+Supla::Eeprom eeprom(SUPLA_STORAGE_OFFSET);
+```
+Offset parameter is optional - use it if you already use saving to EEPROM in your application and you want SuplaDevice to use some other area of memory.
+
+### Adafruit FRAM SPI
+FRAM is recommended for storage in Supla. It allows almost limitless writing cycles and it is very fast memory.
+Currently only Adafruit FRAM SPI is supported.
+```
+#include
+// Hardware SPI
+Supla::FramSpi fram(FRAM_CS, SUPLA_STORAGE_OFFSET);
+```
+or with SW SPI:
+```
+// Software SPI
+Supla::FramSpi fram(SCK_PIN, MISO_PIN, MOSI_PIN, FRAM_CS, SUPLA_STORAGE_OFFSET);
+```
+
+## History
+
+Version 2.3.0
+
+
+## Credits
+
+
+## License
+
+
+Please check it [here](https://github.com/SUPLA/supla-cloud/blob/master/LICENSE).
+
diff --git a/lib/SuplaDevice/src/CMakeLists.txt b/lib/SuplaDevice/src/CMakeLists.txt
new file mode 100644
index 00000000..55931cc9
--- /dev/null
+++ b/lib/SuplaDevice/src/CMakeLists.txt
@@ -0,0 +1,34 @@
+set(SRCS
+ supla/uptime.cpp
+ supla/channel.cpp
+ supla/channel_extended.cpp
+ supla/io.cpp
+ supla/tools.cpp
+ supla/element.cpp
+ supla/local_action.cpp
+ supla/channel_element.cpp
+
+ supla/storage/storage.cpp
+
+ supla/control/internal_pin_output.cpp
+ supla/control/pin_status_led.cpp
+ supla/control/rgbw_base.cpp
+ supla/control/rgb_base.cpp
+ supla/control/dimmer_base.cpp
+ supla/control/rgbw_leds.cpp
+ supla/control/rgb_leds.cpp
+ supla/control/dimmer_leds.cpp
+ supla/control/simple_button.cpp
+
+ supla/condition.cpp
+ supla/conditions/on_less.cpp
+ supla/conditions/on_less_eq.cpp
+ supla/conditions/on_greater.cpp
+ supla/conditions/on_greater_eq.cpp
+ supla/conditions/on_between.cpp
+ supla/conditions/on_between_eq.cpp
+ supla/conditions/on_equal.cpp
+
+)
+
+add_library(supladevicelib SHARED ${SRCS})
diff --git a/lib/SuplaDevice/src/SuplaDevice.cpp b/lib/SuplaDevice/src/SuplaDevice.cpp
index 210a909e..90cf5f43 100644
--- a/lib/SuplaDevice/src/SuplaDevice.cpp
+++ b/lib/SuplaDevice/src/SuplaDevice.cpp
@@ -94,22 +94,27 @@ bool SuplaDeviceClass::begin(unsigned char version) {
// Supla::Storage::LoadDeviceConfig();
// Supla::Storage::LoadElementConfig();
- // Pefrorm dry run of write state to validate stored state section with current
- // device configuration
- Serial.println(F("Validating storage state section with current device configuration"));
+ // Pefrorm dry run of write state to validate stored state section with
+ // current device configuration
+ Serial.println(
+ F("Validating storage state section with current device configuration"));
Supla::Storage::PrepareState(true);
for (auto element = Supla::Element::begin(); element != nullptr;
- element = element->next()) {
+ element = element->next()) {
element->onSaveState();
+ delay(0);
}
// If state storage validation was successful, perform read state
if (Supla::Storage::FinalizeSaveState()) {
- Serial.println(F("Storage state section validation completed. Loading elements state..."));
+ Serial.println(
+ F("Storage state section validation completed. Loading elements "
+ "state..."));
// Iterate all elements and load state
Supla::Storage::PrepareState();
for (auto element = Supla::Element::begin(); element != nullptr;
- element = element->next()) {
+ element = element->next()) {
element->onLoadState();
+ delay(0);
}
}
@@ -117,12 +122,12 @@ bool SuplaDeviceClass::begin(unsigned char version) {
for (auto element = Supla::Element::begin(); element != nullptr;
element = element->next()) {
element->onInit();
+ delay(0);
}
// Enable timers
Supla::initTimers();
-
bool emptyGuidDetected = true;
for (int i = 0; i < SUPLA_GUID_SIZE; i++) {
if (Supla::Channel::reg_dev.GUID[i] != 0) {
@@ -244,6 +249,7 @@ void SuplaDeviceClass::iterate(void) {
for (auto element = Supla::Element::begin(); element != nullptr;
element = element->next()) {
element->iterateAlways();
+ delay(0);
}
// Iterate all elements and saves state
@@ -252,6 +258,7 @@ void SuplaDeviceClass::iterate(void) {
for (auto element = Supla::Element::begin(); element != nullptr;
element = element->next()) {
element->onSaveState();
+ delay(0);
}
Supla::Storage::FinalizeSaveState();
}
@@ -330,7 +337,6 @@ void SuplaDeviceClass::iterate(void) {
if (!srpc_ds_async_registerdevice_e(srpc, &Supla::Channel::reg_dev)) {
supla_log(LOG_DEBUG, "Fatal SRPC failure!");
}
- Supla::Channel::clearAllUpdateReady();
} else if (registered == 1) {
if (Supla::Network::Ping() == false) {
@@ -347,6 +353,7 @@ void SuplaDeviceClass::iterate(void) {
if (!element->iterateConnected(srpc)) {
break;
}
+ delay(0);
}
last_iterate_time = millis();
@@ -502,7 +509,8 @@ void SuplaDeviceClass::setServer(const char *server) {
Supla::Channel::reg_dev.ServerName, server, SUPLA_SERVER_NAME_MAXSIZE);
}
-void SuplaDeviceClass::onGetUserLocaltimeResult(TSDC_UserLocalTimeResult *result) {
+void SuplaDeviceClass::onGetUserLocaltimeResult(
+ TSDC_UserLocalTimeResult *result) {
if (clock) {
clock->parseLocaltimeFromServer(result);
}
@@ -513,7 +521,7 @@ void SuplaDeviceClass::addClock(Supla::Clock *_clock) {
clock = _clock;
}
-Supla::Clock * SuplaDeviceClass::getClock() {
+Supla::Clock *SuplaDeviceClass::getClock() {
return clock;
}
diff --git a/lib/SuplaDevice/src/SuplaDevice.h b/lib/SuplaDevice/src/SuplaDevice.h
index 5c1067fe..0057105c 100644
--- a/lib/SuplaDevice/src/SuplaDevice.h
+++ b/lib/SuplaDevice/src/SuplaDevice.h
@@ -17,8 +17,6 @@
#ifndef SUPLADEVICE_H
#define SUPLADEVICE_H
-#include
-
#include "supla-common/proto.h"
#include "supla/network/network.h"
#include "supla/uptime.h"
diff --git a/lib/SuplaDevice/src/supla-common/IEEE754tools.h b/lib/SuplaDevice/src/supla-common/IEEE754tools.h
index 5a42beec..c38cfbc1 100644
--- a/lib/SuplaDevice/src/supla-common/IEEE754tools.h
+++ b/lib/SuplaDevice/src/supla-common/IEEE754tools.h
@@ -13,13 +13,6 @@
#ifndef IEEE754tools_h
#define IEEE754tools_h
-
-#if defined(ARDUINO) && ARDUINO >= 100
-#include "Arduino.h"
-#else
-#include "WProgram.h"
-#endif
-
// IEEE754 float layout;
struct IEEEfloat
{
diff --git a/lib/SuplaDevice/src/supla/action_handler.h b/lib/SuplaDevice/src/supla/action_handler.h
new file mode 100644
index 00000000..b057371f
--- /dev/null
+++ b/lib/SuplaDevice/src/supla/action_handler.h
@@ -0,0 +1,32 @@
+/*
+ Copyright (C) AC SOFTWARE SP. Z O.O.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ 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 General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#ifndef _action_handler_h
+#define _action_handler_h
+
+namespace Supla {
+class ActionHandler {
+ public:
+ virtual ~ActionHandler() {};
+ virtual void handleAction(int event, int action) = 0;
+ virtual bool deleteClient() {
+ return false;
+ }
+};
+
+};
+
+#endif
diff --git a/lib/SuplaDevice/src/supla/actions.h b/lib/SuplaDevice/src/supla/actions.h
index e44a2647..eac71d00 100644
--- a/lib/SuplaDevice/src/supla/actions.h
+++ b/lib/SuplaDevice/src/supla/actions.h
@@ -17,9 +17,9 @@
#ifndef _actions_h
#define _actions_h
-// Actions are used in triggerable elements. They are grouped by most common
+// Actions are used in ActionHandler elements. They are grouped by most common
// usage, but you should not rely on it. Please check exact supported actions
-// in triggerable element documentation
+// in ActionHandler's element documentation
namespace Supla {
enum Action {
diff --git a/lib/SuplaDevice/src/supla/channel.cpp b/lib/SuplaDevice/src/supla/channel.cpp
index b6c9a658..65a3ea03 100644
--- a/lib/SuplaDevice/src/supla/channel.cpp
+++ b/lib/SuplaDevice/src/supla/channel.cpp
@@ -14,13 +14,15 @@
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
+#include
+
#include "supla/channel.h"
#include "supla-common/log.h"
#include "supla-common/srpc.h"
#include "tools.h"
+#include "events.h"
namespace Supla {
-Channel *Channel::firstPtr = nullptr;
unsigned long Channel::lastCommunicationTimeMs = 0;
TDS_SuplaRegisterDevice_E Channel::reg_dev;
@@ -30,44 +32,20 @@ Channel::Channel() {
channelNumber = -1;
if (reg_dev.channel_count < SUPLA_CHANNELMAXCOUNT) {
channelNumber = reg_dev.channel_count;
+
+ memset(®_dev.channels[channelNumber], 0, sizeof(reg_dev.channels[channelNumber]));
reg_dev.channels[channelNumber].Number = channelNumber;
+
reg_dev.channel_count++;
} else {
// TODO: add status CHANNEL_LIMIT_EXCEEDED
}
- if (firstPtr == nullptr) {
- firstPtr = this;
- } else {
- last()->nextPtr = this;
- }
- nextPtr = nullptr;
setFlag(SUPLA_CHANNEL_FLAG_CHANNELSTATE);
}
-Channel *Channel::begin() {
- return firstPtr;
-}
-
-Channel *Channel::last() {
- Channel *ptr = firstPtr;
- while (ptr && ptr->nextPtr) {
- ptr = ptr->nextPtr;
- }
- return ptr;
-}
-
-int Channel::size() {
- int count = 0;
- Channel *ptr = firstPtr;
- if (ptr) {
- count++;
- }
- while (ptr->nextPtr) {
- count++;
- ptr = ptr->nextPtr;
- }
- return count;
+Channel::~Channel() {
+ reg_dev.channel_count--;
}
void Channel::setNewValue(double dbl) {
@@ -78,19 +56,23 @@ void Channel::setNewValue(double dbl) {
float2DoublePacked(dbl, (uint8_t *)(newValue));
}
if (setNewValue(newValue)) {
- supla_log(LOG_DEBUG, "Channel(%d) value changed to %f", channelNumber, dbl);
+ runAction(ON_CHANGE);
+ runAction(ON_SECONDARY_CHANNEL_CHANGE);
+ supla_log(LOG_DEBUG, "Channel(%d) value changed to %d.%d", channelNumber, static_cast(dbl), static_cast(dbl*100)%100);
}
}
void Channel::setNewValue(double temp, double humi) {
char newValue[SUPLA_CHANNELVALUE_SIZE];
- long t = temp * 1000.00;
- long h = humi * 1000.00;
+ _supla_int_t t = temp * 1000.00;
+ _supla_int_t h = humi * 1000.00;
memcpy(newValue, &t, 4);
memcpy(&(newValue[4]), &h, 4);
if (setNewValue(newValue)) {
+ runAction(ON_CHANGE);
+ runAction(ON_SECONDARY_CHANNEL_CHANGE);
supla_log(LOG_DEBUG,
"Channel(%d) value changed to temp(%f), humi(%f)",
channelNumber,
@@ -106,18 +88,22 @@ void Channel::setNewValue(_supla_int64_t value) {
memcpy(newValue, &value, sizeof(_supla_int64_t));
if (setNewValue(newValue)) {
+ runAction(ON_CHANGE);
+ runAction(ON_SECONDARY_CHANNEL_CHANGE);
supla_log(
LOG_DEBUG, "Channel(%d) value changed to %d", channelNumber, static_cast(value));
}
}
-void Channel::setNewValue(int value) {
+void Channel::setNewValue(_supla_int_t value) {
char newValue[SUPLA_CHANNELVALUE_SIZE];
memset(newValue, 0, SUPLA_CHANNELVALUE_SIZE);
- memcpy(newValue, &value, sizeof(int));
+ memcpy(newValue, &value, sizeof(value));
if (setNewValue(newValue)) {
+ runAction(ON_CHANGE);
+ runAction(ON_SECONDARY_CHANNEL_CHANGE);
supla_log(
LOG_DEBUG, "Channel(%d) value changed to %d", channelNumber, value);
}
@@ -130,6 +116,14 @@ void Channel::setNewValue(bool value) {
newValue[0] = value;
if (setNewValue(newValue)) {
+ if (value) {
+ runAction(Supla::ON_TURN_ON);
+ } else {
+ runAction(Supla::ON_TURN_OFF);
+ }
+ runAction(Supla::ON_CHANGE);
+ runAction(ON_SECONDARY_CHANNEL_CHANGE);
+
supla_log(
LOG_DEBUG, "Channel(%d) value changed to %d", channelNumber, value);
}
@@ -235,18 +229,6 @@ TSuplaChannelExtendedValue *Channel::getExtValue() {
return nullptr;
}
-void Channel::clearAllUpdateReady() {
- for (auto channel = begin(); channel != nullptr; channel = channel->next()) {
- if (!channel->isExtended()) {
- channel->clearUpdateReady();
- }
- }
-}
-
-Channel *Channel::next() {
- return nextPtr;
-}
-
void Channel::setUpdateReady() {
valueChanged = true;
};
@@ -272,6 +254,8 @@ void Channel::setNewValue(uint8_t red,
newValue[3] = green;
newValue[4] = red;
if (setNewValue(newValue)) {
+ runAction(ON_CHANGE);
+ runAction(ON_SECONDARY_CHANNEL_CHANGE);
supla_log(LOG_DEBUG, "Channel(%d) value changed to RGB(%d, %d, %d), colBr(%d), bright(%d)", channelNumber, red, green, blue, colorBrightness, brightness);
}
}
@@ -283,4 +267,66 @@ _supla_int_t Channel::getChannelType() {
return -1;
}
+double Channel::getValueDouble() {
+ double value;
+ if (sizeof(double) == 8) {
+ memcpy(&value, reg_dev.channels[channelNumber].value, 8);
+ } else if (sizeof(double) == 4) {
+ value = doublePacked2float((uint8_t *)(reg_dev.channels[channelNumber].value));
+ }
+
+ return value;
+}
+
+double Channel::getValueDoubleFirst() {
+ _supla_int_t value;
+ memcpy(&value, reg_dev.channels[channelNumber].value, 4);
+
+ return value / 1000.0;
+}
+
+double Channel::getValueDoubleSecond() {
+ _supla_int_t value;
+ memcpy(&value, &(reg_dev.channels[channelNumber].value[4]), 4);
+
+ return value / 1000.0;
+}
+
+_supla_int_t Channel::getValueInt32() {
+ _supla_int_t value;
+ memcpy(&value, reg_dev.channels[channelNumber].value, sizeof(value));
+ return value;
+}
+
+_supla_int64_t Channel::getValueInt64() {
+ _supla_int64_t value;
+ memcpy(&value, reg_dev.channels[channelNumber].value, sizeof(value));
+ return value;
+}
+
+bool Channel::getValueBool() {
+ return reg_dev.channels[channelNumber].value[0];
+}
+
+uint8_t Channel::getValueRed() {
+ return reg_dev.channels[channelNumber].value[4];
+}
+
+uint8_t Channel::getValueGreen() {
+ return reg_dev.channels[channelNumber].value[3];
+}
+
+uint8_t Channel::getValueBlue() {
+ return reg_dev.channels[channelNumber].value[2];
+}
+
+uint8_t Channel::getValueColorBrightness() {
+ return reg_dev.channels[channelNumber].value[1];
+}
+
+uint8_t Channel::getValueBrightness() {
+ return reg_dev.channels[channelNumber].value[0];
+}
+
+
}; // namespace Supla
diff --git a/lib/SuplaDevice/src/supla/channel.h b/lib/SuplaDevice/src/supla/channel.h
index c27b68a5..453d6f88 100644
--- a/lib/SuplaDevice/src/supla/channel.h
+++ b/lib/SuplaDevice/src/supla/channel.h
@@ -19,21 +19,19 @@
#include
-#include "../supla-common/proto.h"
+#include "supla-common/proto.h"
+#include "local_action.h"
namespace Supla {
-class Channel {
+class Channel : public LocalAction {
public:
Channel();
-
- static Channel *begin();
- static Channel *last();
- static int size();
+ ~Channel();
void setNewValue(double dbl);
void setNewValue(double temp, double humi);
- void setNewValue(int value);
+ void setNewValue(_supla_int_t value);
void setNewValue(bool value);
void setNewValue(TElectricityMeter_ExtendedValue_V2 &emValue);
void setNewValue(uint8_t red,
@@ -44,6 +42,18 @@ class Channel {
void setNewValue(_supla_int64_t value);
bool setNewValue(char *newValue);
+ double getValueDouble();
+ double getValueDoubleFirst();
+ double getValueDoubleSecond();
+ _supla_int_t getValueInt32();
+ _supla_int64_t getValueInt64();
+ bool getValueBool();
+ uint8_t getValueRed();
+ uint8_t getValueGreen();
+ uint8_t getValueBlue();
+ uint8_t getValueColorBrightness();
+ uint8_t getValueBrightness();
+
virtual bool isExtended();
bool isUpdateReady();
int getChannelNumber();
@@ -57,8 +67,6 @@ class Channel {
void clearUpdateReady();
void sendUpdate(void *srpc);
virtual TSuplaChannelExtendedValue *getExtValue();
- static void clearAllUpdateReady();
- Channel *next();
static unsigned long lastCommunicationTimeMs;
static TDS_SuplaRegisterDevice_E reg_dev;
@@ -69,8 +77,6 @@ class Channel {
bool valueChanged;
int channelNumber;
- Channel *nextPtr;
- static Channel *firstPtr;
};
}; // namespace Supla
diff --git a/lib/SuplaDevice/src/supla/channel_element.cpp b/lib/SuplaDevice/src/supla/channel_element.cpp
new file mode 100644
index 00000000..f9853a62
--- /dev/null
+++ b/lib/SuplaDevice/src/supla/channel_element.cpp
@@ -0,0 +1,41 @@
+/*
+ Copyright (C) AC SOFTWARE SP. Z O.O.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ 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 General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "channel_element.h"
+#include "events.h"
+
+Supla::Channel *Supla::ChannelElement::getChannel() {
+ return &channel;
+}
+
+void Supla::ChannelElement::addAction(int action, ActionHandler &client, int event) {
+ channel.addAction(action, client, event);
+}
+
+void Supla::ChannelElement::addAction(int action, ActionHandler *client, int event) {
+ addAction(action, *client, event);
+}
+
+void Supla::ChannelElement::addAction(int action, ActionHandler &client, Supla::Condition *condition) {
+ condition->setClient(client);
+ condition->setSource(this);
+ channel.addAction(action, condition, Supla::ON_CHANGE);
+}
+
+void Supla::ChannelElement::addAction(int action, ActionHandler *client, Supla::Condition *condition) {
+ addAction(action, *client, condition);
+}
+
diff --git a/lib/SuplaDevice/src/supla/channel_element.h b/lib/SuplaDevice/src/supla/channel_element.h
new file mode 100644
index 00000000..ae4b0256
--- /dev/null
+++ b/lib/SuplaDevice/src/supla/channel_element.h
@@ -0,0 +1,49 @@
+/*
+ Copyright (C) AC SOFTWARE SP. Z O.O.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ 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 General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#ifndef _channel_element_h
+#define _channel_element_h
+
+#include "element.h"
+#include "channel.h"
+#include "local_action.h"
+#include "action_handler.h"
+#include "condition.h"
+
+namespace Supla {
+
+class Condition;
+
+class ChannelElement : public Element, public LocalAction {
+ public:
+
+ Channel *getChannel();
+
+ // Override local action methods in order to delegate execution to Channel
+ void addAction(int action, ActionHandler &client, int event);
+ void addAction(int action, ActionHandler *client, int event);
+
+ virtual void addAction(int action, ActionHandler &client, Supla::Condition *condition);
+ virtual void addAction(int action, ActionHandler *client, Supla::Condition *condition);
+
+ protected:
+ Channel channel;
+};
+
+};
+
+#endif
+
diff --git a/lib/SuplaDevice/src/supla/condition.cpp b/lib/SuplaDevice/src/supla/condition.cpp
new file mode 100644
index 00000000..b7a04e5a
--- /dev/null
+++ b/lib/SuplaDevice/src/supla/condition.cpp
@@ -0,0 +1,92 @@
+/*
+ Copyright (C) AC SOFTWARE SP. Z O.O.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ 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 General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "condition.h"
+#include "events.h"
+
+Supla::Condition::Condition(double threshold, bool useAlternativeMeasurement)
+ : threshold(threshold),
+ useAlternativeMeasurement(useAlternativeMeasurement),
+ alreadyFired(false) {
+}
+
+Supla::Condition::~Condition() {
+}
+
+void Supla::Condition::handleAction(int event, int action) {
+ if (event == Supla::ON_CHANGE ||
+ event == Supla::ON_SECONDARY_CHANNEL_CHANGE) {
+ int channelType = source->getChannel()->getChannelType();
+ double value = 0;
+ switch (channelType) {
+ case SUPLA_CHANNELTYPE_DISTANCESENSOR:
+ case SUPLA_CHANNELTYPE_THERMOMETER:
+ case SUPLA_CHANNELTYPE_WINDSENSOR:
+ case SUPLA_CHANNELTYPE_PRESSURESENSOR:
+ case SUPLA_CHANNELTYPE_RAINSENSOR:
+ case SUPLA_CHANNELTYPE_WEIGHTSENSOR:
+ value = source->getChannel()->getValueDouble();
+ break;
+ case SUPLA_CHANNELTYPE_IMPULSE_COUNTER:
+ value = source->getChannel()->getValueInt64();
+ break;
+ case SUPLA_CHANNELTYPE_HUMIDITYANDTEMPSENSOR:
+ value = useAlternativeMeasurement
+ ? source->getChannel()->getValueDoubleSecond()
+ : source->getChannel()->getValueDoubleFirst();
+ break;
+ default:
+ return;
+ }
+ if (checkConditionFor(value)) {
+ client->handleAction(event, action);
+ }
+ }
+}
+
+// Condition objects will be deleted during ActionHandlerClient list cleanup
+bool Supla::Condition::deleteClient() {
+ return true;
+}
+
+bool Supla::Condition::checkConditionFor(double val) {
+ if (!alreadyFired && condition(val)) {
+ alreadyFired = true;
+ return true;
+ }
+ if (alreadyFired) {
+ if (!condition(val)) {
+ alreadyFired = false;
+ }
+ }
+ return false;
+}
+
+void Supla::Condition::setSource(Supla::ChannelElement *src) {
+ source = src;
+}
+
+void Supla::Condition::setClient(Supla::ActionHandler *clientPtr) {
+ client = clientPtr;
+}
+
+void Supla::Condition::setSource(Supla::ChannelElement &src) {
+ setSource(&src);
+}
+
+void Supla::Condition::setClient(Supla::ActionHandler &clientPtr) {
+ setClient(&clientPtr);
+}
diff --git a/lib/SuplaDevice/src/supla/condition.h b/lib/SuplaDevice/src/supla/condition.h
new file mode 100644
index 00000000..d5d31f90
--- /dev/null
+++ b/lib/SuplaDevice/src/supla/condition.h
@@ -0,0 +1,62 @@
+/*
+ Copyright (C) AC SOFTWARE SP. Z O.O.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ 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 General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#ifndef _condition_h
+#define _condition_h
+
+#include "action_handler.h"
+#include "channel_element.h"
+
+
+namespace Supla {
+
+class ChannelElement;
+
+class Condition : public ActionHandler {
+ public:
+ Condition(double threshold, bool useAlternativeMeasurement);
+ virtual ~Condition();
+ void setSource(ChannelElement *src);
+ void setClient(ActionHandler *clientPtr);
+ void setSource(ChannelElement &src);
+ void setClient(ActionHandler &clientPtr);
+
+ void handleAction(int event, int action);
+ bool deleteClient();
+ virtual bool checkConditionFor(double val);
+
+ protected:
+ virtual bool condition(double val) = 0;
+
+ double threshold;
+ bool alreadyFired;
+ bool useAlternativeMeasurement;
+ Supla::ChannelElement *source;
+ Supla::ActionHandler *client;
+
+};
+
+};
+
+Supla::Condition *OnLess(double threshold, bool useAlternativeMeasurement = false);
+Supla::Condition *OnLessEq(double threshold, bool useAlternativeMeasurement = false);
+Supla::Condition *OnGreater(double threshold, bool useAlternativeMeasurement = false);
+Supla::Condition *OnGreaterEq(double threshold, bool useAlternativeMeasurement = false);
+Supla::Condition *OnBetween(double threshold1, double threshold2, bool useAlternativeMeasurement = false);
+Supla::Condition *OnBetweenEq(double threshold1, double threshold2, bool useAlternativeMeasurement = false);
+Supla::Condition *OnEqual(double threshold, bool useAlternativeMeasurement = false);
+
+#endif
diff --git a/lib/SuplaDevice/src/supla/conditions/on_between.cpp b/lib/SuplaDevice/src/supla/conditions/on_between.cpp
new file mode 100644
index 00000000..9a1ef83e
--- /dev/null
+++ b/lib/SuplaDevice/src/supla/conditions/on_between.cpp
@@ -0,0 +1,38 @@
+/*
+ Copyright (C) AC SOFTWARE SP. Z O.O.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ 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 General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "../condition.h"
+
+class OnBetweenCond : public Supla::Condition {
+ public:
+ OnBetweenCond(double threshold1, double threshold2, bool useAlternativeMeasurement)
+ : Supla::Condition(threshold1, useAlternativeMeasurement), threshold2(threshold2) {
+ }
+
+ bool condition(double val) {
+ return val > threshold && val < threshold2;
+ }
+
+ double threshold2;
+};
+
+
+Supla::Condition *OnBetween(double threshold1, double threshold2, bool useAlternativeMeasurement) {
+ return new OnBetweenCond(threshold1, threshold2, useAlternativeMeasurement);
+}
+
+
+
diff --git a/lib/SuplaDevice/src/supla/conditions/on_between_eq.cpp b/lib/SuplaDevice/src/supla/conditions/on_between_eq.cpp
new file mode 100644
index 00000000..8e535db1
--- /dev/null
+++ b/lib/SuplaDevice/src/supla/conditions/on_between_eq.cpp
@@ -0,0 +1,39 @@
+/*
+ Copyright (C) AC SOFTWARE SP. Z O.O.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ 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 General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "../condition.h"
+
+class OnBetweenEqCond : public Supla::Condition {
+ public:
+ OnBetweenEqCond(double threshold1, double threshold2, bool useAlternativeMeasurement)
+ : Supla::Condition(threshold1, useAlternativeMeasurement), threshold2(threshold2) {
+ }
+
+ bool condition(double val) {
+ return val >= threshold && val <= threshold2;
+ }
+
+ double threshold2;
+};
+
+
+Supla::Condition *OnBetweenEq(double threshold1, double threshold2, bool useAlternativeMeasurement) {
+ return new OnBetweenEqCond(threshold1, threshold2, useAlternativeMeasurement);
+}
+
+
+
+
diff --git a/lib/SuplaDevice/src/supla/conditions/on_equal.cpp b/lib/SuplaDevice/src/supla/conditions/on_equal.cpp
new file mode 100644
index 00000000..1d7e6d25
--- /dev/null
+++ b/lib/SuplaDevice/src/supla/conditions/on_equal.cpp
@@ -0,0 +1,36 @@
+/*
+ Copyright (C) AC SOFTWARE SP. Z O.O.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ 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 General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "../condition.h"
+
+class OnEqualCond : public Supla::Condition {
+ public:
+ OnEqualCond(double threshold, bool useAlternativeMeasurement)
+ : Supla::Condition(threshold, useAlternativeMeasurement) {
+ }
+
+ bool condition(double val) {
+ return val == threshold;
+ }
+};
+
+
+Supla::Condition *OnEqual(double threshold, bool useAlternativeMeasurement) {
+ return new OnEqualCond(threshold, useAlternativeMeasurement);
+}
+
+
+
diff --git a/lib/SuplaDevice/src/supla/conditions/on_greater.cpp b/lib/SuplaDevice/src/supla/conditions/on_greater.cpp
new file mode 100644
index 00000000..675a667f
--- /dev/null
+++ b/lib/SuplaDevice/src/supla/conditions/on_greater.cpp
@@ -0,0 +1,36 @@
+/*
+ Copyright (C) AC SOFTWARE SP. Z O.O.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ 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 General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "../condition.h"
+
+class OnGreaterCond : public Supla::Condition {
+ public:
+ OnGreaterCond(double threshold, bool useAlternativeMeasurement)
+ : Supla::Condition(threshold, useAlternativeMeasurement) {
+ }
+
+ bool condition(double val) {
+ return val > threshold;
+ }
+};
+
+
+Supla::Condition *OnGreater(double threshold, bool useAlternativeMeasurement) {
+ return new OnGreaterCond(threshold, useAlternativeMeasurement);
+}
+
+
+
diff --git a/lib/SuplaDevice/src/supla/conditions/on_greater_eq.cpp b/lib/SuplaDevice/src/supla/conditions/on_greater_eq.cpp
new file mode 100644
index 00000000..37aaf920
--- /dev/null
+++ b/lib/SuplaDevice/src/supla/conditions/on_greater_eq.cpp
@@ -0,0 +1,36 @@
+/*
+ Copyright (C) AC SOFTWARE SP. Z O.O.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ 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 General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "../condition.h"
+
+class OnGreaterEqCond : public Supla::Condition {
+ public:
+ OnGreaterEqCond(double threshold, bool useAlternativeMeasurement)
+ : Supla::Condition(threshold, useAlternativeMeasurement) {
+ }
+
+ bool condition(double val) {
+ return val >= threshold;
+ }
+};
+
+
+Supla::Condition *OnGreaterEq(double threshold, bool useAlternativeMeasurement) {
+ return new OnGreaterEqCond(threshold, useAlternativeMeasurement);
+}
+
+
+
diff --git a/lib/SuplaDevice/src/supla/conditions/on_less.cpp b/lib/SuplaDevice/src/supla/conditions/on_less.cpp
new file mode 100644
index 00000000..37541f52
--- /dev/null
+++ b/lib/SuplaDevice/src/supla/conditions/on_less.cpp
@@ -0,0 +1,34 @@
+/*
+ Copyright (C) AC SOFTWARE SP. Z O.O.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ 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 General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "../condition.h"
+
+class OnLessCond : public Supla::Condition {
+ public:
+ OnLessCond(double threshold, bool useAlternativeMeasurement)
+ : Supla::Condition(threshold, useAlternativeMeasurement) {
+ }
+
+ bool condition(double val) {
+ return val < threshold;
+ }
+};
+
+
+Supla::Condition *OnLess(double threshold, bool useAlternativeMeasurement) {
+ return new OnLessCond(threshold, useAlternativeMeasurement);
+}
+
diff --git a/lib/SuplaDevice/src/supla/conditions/on_less_eq.cpp b/lib/SuplaDevice/src/supla/conditions/on_less_eq.cpp
new file mode 100644
index 00000000..359e8058
--- /dev/null
+++ b/lib/SuplaDevice/src/supla/conditions/on_less_eq.cpp
@@ -0,0 +1,35 @@
+/*
+ Copyright (C) AC SOFTWARE SP. Z O.O.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ 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 General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "../condition.h"
+
+class OnLessEqCond : public Supla::Condition {
+ public:
+ OnLessEqCond(double threshold, bool useAlternativeMeasurement)
+ : Supla::Condition(threshold, useAlternativeMeasurement) {
+ }
+
+ bool condition(double val) {
+ return val <= threshold;
+ }
+};
+
+
+Supla::Condition *OnLessEq(double threshold, bool useAlternativeMeasurement) {
+ return new OnLessEqCond(threshold, useAlternativeMeasurement);
+}
+
+
diff --git a/lib/SuplaDevice/src/supla/control/MCP23017/S_MCP23017.cpp b/lib/SuplaDevice/src/supla/control/MCP23017/S_MCP23017.cpp
new file mode 100644
index 00000000..af9a21c3
--- /dev/null
+++ b/lib/SuplaDevice/src/supla/control/MCP23017/S_MCP23017.cpp
@@ -0,0 +1,205 @@
+#include
+#include
+#include "S_MCP23017.h"
+
+static const uint8_t MCP23017_BASEADDRESS = 0x20;
+
+static const uint8_t MCP23017_IODIRA = 0x00;
+static const uint8_t MCP23017_IODIRB = 0x01;
+static const uint8_t MCP23017_IPOLA = 0x02;
+static const uint8_t MCP23017_IPOLB = 0x03;
+static const uint8_t MCP23017_GPINTENA = 0x04;
+static const uint8_t MCP23017_GPINTENB = 0x05;
+static const uint8_t MCP23017_DEFVALA = 0x06;
+static const uint8_t MCP23017_DEFVALB = 0x07;
+static const uint8_t MCP23017_INTCONA = 0x08;
+static const uint8_t MCP23017_INTCONB = 0x09;
+static const uint8_t MCP23017_IOCONA = 0x0A;
+static const uint8_t MCP23017_IOCONB = 0x0B;
+static const uint8_t MCP23017_GPPUA = 0x0C;
+static const uint8_t MCP23017_GPPUB = 0x0D;
+static const uint8_t MCP23017_INTFA = 0x0E;
+static const uint8_t MCP23017_INTFB = 0x0F;
+static const uint8_t MCP23017_INTCAPA = 0x10;
+static const uint8_t MCP23017_INTCAPB = 0x11;
+static const uint8_t MCP23017_GPIOA = 0x12;
+static const uint8_t MCP23017_GPIOB = 0x13;
+static const uint8_t MCP23017_OLATA = 0x14;
+static const uint8_t MCP23017_OLATB = 0x15;
+
+#ifdef ESP8266
+void MCP23017::init(uint8_t sda, uint8_t scl, bool fast) {
+ Wire.begin(sda, scl);
+ if (fast)
+ Wire.setClock(400000);
+}
+#else
+void MCP23017::init(bool fast) {
+ Wire.begin();
+ if (fast)
+ Wire.setClock(400000);
+}
+#endif
+
+bool MCP23017::begin(uint8_t address) {
+ _address = MCP23017_BASEADDRESS | (address & 0x07);
+ return (writeReg16(MCP23017_IOCONA, 0x4242) && writeReg16(MCP23017_IODIRA, 0xFFFF)); // INT MIRROR & INT POL HIGH, ALL INPUTS
+}
+
+void MCP23017::pinMode(uint8_t pin, uint8_t mode) {
+ if (pin < 16) {
+ if (mode == OUTPUT) {
+ updateReg(pin < 8 ? MCP23017_IODIRA : MCP23017_IODIRB, ~(uint8_t)(1 << (pin % 8)), 0x00);
+ } else if ((mode == INPUT) || (mode == INPUT_PULLUP)) {
+ updateReg(pin < 8 ? MCP23017_IODIRA : MCP23017_IODIRB, 0xFF, 1 << (pin % 8));
+ if (mode == INPUT_PULLUP) {
+ updateReg(pin < 8 ? MCP23017_GPPUA : MCP23017_GPPUB, 0xFF, 1 << (pin % 8));
+ updateReg(pin < 8 ? MCP23017_IPOLA : MCP23017_IPOLB, 0xFF, 1 << (pin % 8));
+ } else {
+ updateReg(pin < 8 ? MCP23017_GPPUA : MCP23017_GPPUB, ~(uint8_t)(1 << (pin % 8)), 0x00);
+ updateReg(pin < 8 ? MCP23017_IPOLA : MCP23017_IPOLB, ~(uint8_t)(1 << (pin % 8)), 0x00);
+ }
+ }
+ }
+}
+
+void MCP23017::setPullup(uint8_t pin, bool pullup, bool inverse) {
+ if (pin < 16) {
+ if (pullup)
+ updateReg(pin < 8 ? MCP23017_GPPUA : MCP23017_GPPUB, 0xFF, 1 << (pin % 8));
+ else
+ updateReg(pin < 8 ? MCP23017_GPPUA : MCP23017_GPPUB, ~(uint8_t)(1 << (pin % 8)), 0x00);
+ if (inverse)
+ updateReg(pin < 8 ? MCP23017_IPOLA : MCP23017_IPOLB, 0xFF, 1 << (pin % 8));
+ else
+ updateReg(pin < 8 ? MCP23017_IPOLA : MCP23017_IPOLB, ~(uint8_t)(1 << (pin % 8)), 0x00);
+ }
+}
+
+bool MCP23017::digitalRead(uint8_t pin) {
+ unsigned long now = millis();
+ if (now > get_ba){
+ ba = readReg16(MCP23017_GPIOA); // --------- reads "readReg16" only once every 20 ms ----
+ get_ba = now + 20;
+ }
+ if (pin < 16) {
+ return ((ba >> (pin % 16)) & 0x01);
+ }
+}
+
+void MCP23017::digitalWrite(uint8_t pin, bool value) {
+ if (pin < 16) {
+ if (value)
+ updateReg(pin < 8 ? MCP23017_GPIOA : MCP23017_GPIOB, 0xFF, 1 << (pin % 8));
+ else
+ updateReg(pin < 8 ? MCP23017_GPIOA : MCP23017_GPIOB, ~(uint8_t)(1 << (pin % 8)), 0x00);
+ }
+}
+
+uint16_t MCP23017::digitalReads() {
+ return readReg16(MCP23017_GPIOA);
+}
+
+void MCP23017::digitalWrites(uint16_t values) {
+ writeReg16(MCP23017_GPIOA, values);
+}
+
+void MCP23017::attachInterrupt(uint8_t pin, callback_t callback) {
+ _callback = callback;
+ ::pinMode(pin, INPUT);
+ ::attachInterrupt(digitalPinToInterrupt(pin), std::bind(&MCP23017::_interrupt, this), RISING);
+}
+
+void MCP23017::detachInterrupt(uint8_t pin) {
+ ::detachInterrupt(digitalPinToInterrupt(pin));
+ _callback = NULL;
+}
+
+void MCP23017::setupInterrupt(uint8_t pin, bool enable) {
+ if (pin < 16) {
+ if (enable)
+ updateReg(pin < 8 ? MCP23017_GPINTENA : MCP23017_GPINTENB, 0xFF, 1 << (pin % 8));
+ else
+ updateReg(pin < 8 ? MCP23017_GPINTENA : MCP23017_GPINTENB, ~(uint8_t)(1 << (pin % 8)), 0x00);
+ }
+}
+
+void MCP23017::setupInterrupts(uint16_t pins, bool enable) {
+ if (enable)
+ updateReg16(MCP23017_GPINTENA, 0xFFFF, pins);
+ else
+ updateReg16(MCP23017_GPINTENA, ~pins, 0x00);
+}
+
+bool MCP23017::writeReg(uint8_t reg, uint8_t value) {
+ Wire.beginTransmission(_address);
+ Wire.write(reg);
+ Wire.write(value);
+ return (Wire.endTransmission() == 0);
+}
+
+bool MCP23017::writeReg16(uint8_t reg, uint16_t value) {
+ Wire.beginTransmission(_address);
+ Wire.write(reg);
+ Wire.write(value & 0xFF);
+ Wire.write(value >> 8);
+ return (Wire.endTransmission() == 0);
+}
+
+uint8_t MCP23017::readReg(uint8_t reg) {
+ Wire.beginTransmission(_address);
+ Wire.write(reg);
+ if (Wire.endTransmission() != 0)
+ return 0; // Error!
+ Wire.requestFrom(_address, (uint8_t)1);
+ return Wire.read();
+}
+
+uint16_t MCP23017::readReg16(uint8_t reg) {
+ Wire.beginTransmission(_address);
+ Wire.write(reg);
+ if (Wire.endTransmission() != 0)
+ return 0; // Error!
+ Wire.requestFrom(_address, (uint8_t)2);
+ uint8_t a = Wire.read();
+ return ((Wire.read() << 8) | a);
+}
+
+bool MCP23017::updateReg(uint8_t reg, uint8_t andMask, uint8_t orMask) {
+ Wire.beginTransmission(_address);
+ Wire.write(reg);
+ if (Wire.endTransmission() != 0)
+ return false; // Error!
+ Wire.requestFrom(_address, (uint8_t)1);
+ uint8_t a = (Wire.read() & andMask) | orMask;
+ Wire.beginTransmission(_address);
+ Wire.write(reg);
+ Wire.write(a);
+ return (Wire.endTransmission() == 0);
+}
+
+bool MCP23017::updateReg16(uint8_t reg, uint16_t andMask, uint16_t orMask) {
+ Wire.beginTransmission(_address);
+ Wire.write(reg);
+ if (Wire.endTransmission() != 0)
+ return false; // Error!
+ Wire.requestFrom(_address, (uint8_t)2);
+ uint16_t ab = Wire.read();
+ ab |= (Wire.read() << 8);
+ ab &= andMask;
+ ab |= orMask;
+ Wire.beginTransmission(_address);
+ Wire.write(reg);
+ Wire.write(ab & 0xFF);
+ Wire.write(ab >> 8);
+ return (Wire.endTransmission() == 0);
+}
+
+void IRAM_ATTR MCP23017::_interrupt() {
+ uint16_t pins, values;
+
+ pins = readReg16(MCP23017_INTFA);
+ values = readReg16(MCP23017_INTCAPA);
+ if (_callback)
+ _callback(pins, values);
+}
diff --git a/lib/SuplaDevice/src/supla/control/MCP23017/S_MCP23017.h b/lib/SuplaDevice/src/supla/control/MCP23017/S_MCP23017.h
new file mode 100644
index 00000000..ef08791e
--- /dev/null
+++ b/lib/SuplaDevice/src/supla/control/MCP23017/S_MCP23017.h
@@ -0,0 +1,52 @@
+#ifndef _S_MCP23017_H
+#define _S_MCP23017_H
+
+#include
+#include
+
+class MCP23017 {
+public:
+ typedef std::function callback_t;
+
+ MCP23017() : _callback(NULL) {}
+
+#ifdef ESP8266
+ static void init(uint8_t sda, uint8_t scl, bool fast = true);
+ static void init(bool fast = true) {
+ init(SDA, SCL, fast);
+ }
+#else
+ static void init(bool fast = true);
+#endif
+
+ bool begin(uint8_t address = 0);
+
+ void pinMode(uint8_t pin, uint8_t mode);
+ void setPullup(uint8_t pin, bool pullup, bool inverse = false);
+ bool digitalRead(uint8_t pin);
+ void digitalWrite(uint8_t pin, bool value);
+ uint16_t digitalReads();
+ void digitalWrites(uint16_t values);
+
+ void attachInterrupt(uint8_t pin, callback_t callback);
+ void detachInterrupt(uint8_t pin);
+ void setupInterrupt(uint8_t pin, bool enable = true);
+ void setupInterrupts(uint16_t pins, bool enable = true);
+
+protected:
+ bool writeReg(uint8_t reg, uint8_t value);
+ bool writeReg16(uint8_t reg, uint16_t value);
+ uint8_t readReg(uint8_t reg);
+ uint16_t readReg16(uint8_t reg);
+ bool updateReg(uint8_t reg, uint8_t andMask, uint8_t orMask);
+ bool updateReg16(uint8_t reg, uint16_t andMask, uint16_t orMask);
+
+ void _interrupt();
+
+ uint8_t _address;
+ uint16_t ba = 0;
+ unsigned long get_ba = 0;
+ callback_t _callback;
+};
+
+#endif
diff --git a/lib/SuplaDevice/src/supla/control/MCP23017/examples/Ejemplo_Mcp23017_io/Ejemplo_Mcp23017_io.ino b/lib/SuplaDevice/src/supla/control/MCP23017/examples/Ejemplo_Mcp23017_io/Ejemplo_Mcp23017_io.ino
new file mode 100644
index 00000000..dd4ee2be
--- /dev/null
+++ b/lib/SuplaDevice/src/supla/control/MCP23017/examples/Ejemplo_Mcp23017_io/Ejemplo_Mcp23017_io.ino
@@ -0,0 +1,189 @@
+#define supla_lib_config_h_ // silences unnecessary debug messages "should be disabled by default"
+#include
+#include
+#include
+#include
+
+//
+// ESP8266 based board:
+#include
+Supla::ESPWifi wifi("your_wifi_ssid", "your_wifi_password");
+//
+
+void setup() {
+
+ Serial.begin(115200);
+
+ mcp1.init(4, 5); // init(uint8_t sda, uint8_t scl, bool fast) = Wire.begin
+
+ if (! mcp1.begin(0))Serial.println("MCP23017 1 not found!"); // begin(uint8_t address) "Pin 100 - 115"
+ if (! mcp2.begin(1))Serial.println("MCP23017 2 not found!"); // begin(uint8_t address) "Pin 116 - 131"
+ if (! mcp3.begin(2))Serial.println("MCP23017 3 not found!"); // begin(uint8_t address) "Pin 132 - 147"
+ if (! mcp4.begin(3))Serial.println("MCP23017 4 not found!"); // begin(uint8_t address) "Pin 148 - 163"
+
+ // Replace the falowing GUID with value that you can retrieve from https://www.supla.org/arduino/get-guid
+ char GUID[SUPLA_GUID_SIZE] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+
+ // Replace the following AUTHKEY with value that you can retrieve from: https://www.supla.org/arduino/get-authkey
+ char AUTHKEY[SUPLA_AUTHKEY_SIZE] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+
+ /*
+ * Having your device already registered at cloud.supla.org,
+ * you want to change CHANNEL sequence or remove any of them,
+ * then you must also remove the device itself from cloud.supla.org.
+ * Otherwise you will get "Channel conflict!" error.
+ */
+
+ auto relay_1 = new Supla::Control::Relay(100, true);
+ auto relay_2 = new Supla::Control::Relay(101, true);
+ auto relay_3 = new Supla::Control::Relay(102, true);
+ auto relay_4 = new Supla::Control::Relay(103, true);
+ auto relay_5 = new Supla::Control::Relay(104, true);
+ auto relay_6 = new Supla::Control::Relay(105, true);
+ auto relay_7 = new Supla::Control::Relay(106, true);
+ auto relay_8 = new Supla::Control::Relay(107, true);
+ auto relay_9 = new Supla::Control::Relay(108, true);
+ auto relay_10 = new Supla::Control::Relay(109, true);
+ auto relay_11 = new Supla::Control::Relay(110, true);
+ auto relay_12 = new Supla::Control::Relay(111, true);
+ auto relay_13 = new Supla::Control::Relay(112, true);
+ auto relay_14 = new Supla::Control::Relay(113, true);
+ auto relay_15 = new Supla::Control::Relay(114, true);
+ auto relay_16 = new Supla::Control::Relay(115, true);
+
+ auto relay_17 = new Supla::Control::Relay(148, true);
+ auto relay_18 = new Supla::Control::Relay(149, true);
+ auto relay_19 = new Supla::Control::Relay(150, true);
+ auto relay_20 = new Supla::Control::Relay(151, true);
+ auto relay_21 = new Supla::Control::Relay(152, true);
+ auto relay_22 = new Supla::Control::Relay(153, true);
+ auto relay_23 = new Supla::Control::Relay(154, true);
+ auto relay_24 = new Supla::Control::Relay(155, true);
+ auto relay_25 = new Supla::Control::Relay(156, true);
+ auto relay_26 = new Supla::Control::Relay(157, true);
+ auto relay_27 = new Supla::Control::Relay(158, true);
+ auto relay_28 = new Supla::Control::Relay(159, true);
+ auto relay_29 = new Supla::Control::Relay(160, true);
+ auto relay_30 = new Supla::Control::Relay(161, true);
+ auto relay_31 = new Supla::Control::Relay(162, true);
+ auto relay_32 = new Supla::Control::Relay(163, true);
+
+ auto button_1 = new Supla::Control::Button(116, true, true);
+ auto button_2 = new Supla::Control::Button(117, true, true);
+ auto button_3 = new Supla::Control::Button(118, true, true);
+ auto button_4 = new Supla::Control::Button(119, true, true);
+ auto button_5 = new Supla::Control::Button(120, true, true);
+ auto button_6 = new Supla::Control::Button(121, true, true);
+ auto button_7 = new Supla::Control::Button(122, true, true);
+ auto button_8 = new Supla::Control::Button(123, true, true);
+ auto button_9 = new Supla::Control::Button(124, true, true);
+ auto button_10 = new Supla::Control::Button(125, true, true);
+ auto button_11 = new Supla::Control::Button(126, true, true);
+ auto button_12 = new Supla::Control::Button(127, true, true);
+ auto button_13 = new Supla::Control::Button(128, true, true);
+ auto button_14 = new Supla::Control::Button(129, true, true);
+ auto button_15 = new Supla::Control::Button(130, true, true);
+ auto button_16 = new Supla::Control::Button(131, true, true);
+
+ auto button_17 = new Supla::Control::Button(132, true, true);
+ auto button_18 = new Supla::Control::Button(133, true, true);
+ auto button_19 = new Supla::Control::Button(134, true, true);
+ auto button_20 = new Supla::Control::Button(135, true, true);
+ auto button_21 = new Supla::Control::Button(136, true, true);
+ auto button_22 = new Supla::Control::Button(137, true, true);
+ auto button_23 = new Supla::Control::Button(138, true, true);
+ auto button_24 = new Supla::Control::Button(139, true, true);
+ auto button_25 = new Supla::Control::Button(140, true, true);
+ auto button_26 = new Supla::Control::Button(141, true, true);
+ auto button_27 = new Supla::Control::Button(142, true, true);
+ auto button_28 = new Supla::Control::Button(143, true, true);
+ auto button_29 = new Supla::Control::Button(144, true, true);
+ auto button_30 = new Supla::Control::Button(145, true, true);
+ auto button_31 = new Supla::Control::Button(146, true, true);
+ auto button_32 = new Supla::Control::Button(147, true, true);
+
+ button_1->addAction(Supla::TOGGLE, relay_1, Supla::ON_PRESS);
+ button_1->setSwNoiseFilterDelay(50);
+ button_2->addAction(Supla::TOGGLE, relay_2, Supla::ON_PRESS);
+ button_2->setSwNoiseFilterDelay(50);
+ button_3->addAction(Supla::TOGGLE, relay_3, Supla::ON_PRESS);
+ button_3->setSwNoiseFilterDelay(50);
+ button_4->addAction(Supla::TOGGLE, relay_4, Supla::ON_PRESS);
+ button_4->setSwNoiseFilterDelay(50);
+ button_5->addAction(Supla::TOGGLE, relay_5, Supla::ON_PRESS);
+ button_5->setSwNoiseFilterDelay(50);
+ button_6->addAction(Supla::TOGGLE, relay_6, Supla::ON_PRESS);
+ button_6->setSwNoiseFilterDelay(50);
+ button_7->addAction(Supla::TOGGLE, relay_7, Supla::ON_PRESS);
+ button_7->setSwNoiseFilterDelay(50);
+ button_8->addAction(Supla::TOGGLE, relay_8, Supla::ON_PRESS);
+ button_8->setSwNoiseFilterDelay(50);
+ button_9->addAction(Supla::TOGGLE, relay_9, Supla::ON_PRESS);
+ button_9->setSwNoiseFilterDelay(50);
+ button_10->addAction(Supla::TOGGLE, relay_10, Supla::ON_PRESS);
+ button_10->setSwNoiseFilterDelay(50);
+ button_11->addAction(Supla::TOGGLE, relay_11, Supla::ON_PRESS);
+ button_11->setSwNoiseFilterDelay(50);
+ button_12->addAction(Supla::TOGGLE, relay_12, Supla::ON_PRESS);
+ button_12->setSwNoiseFilterDelay(50);
+ button_13->addAction(Supla::TOGGLE, relay_13, Supla::ON_PRESS);
+ button_13->setSwNoiseFilterDelay(50);
+ button_14->addAction(Supla::TOGGLE, relay_14, Supla::ON_PRESS);
+ button_14->setSwNoiseFilterDelay(50);
+ button_15->addAction(Supla::TOGGLE, relay_15, Supla::ON_PRESS);
+ button_15->setSwNoiseFilterDelay(50);
+ button_16->addAction(Supla::TOGGLE, relay_16, Supla::ON_PRESS);
+ button_16->setSwNoiseFilterDelay(50);
+
+ button_17->addAction(Supla::TOGGLE, relay_17, Supla::ON_PRESS);
+ button_17->setSwNoiseFilterDelay(50);
+ button_18->addAction(Supla::TOGGLE, relay_18, Supla::ON_PRESS);
+ button_18->setSwNoiseFilterDelay(50);
+ button_19->addAction(Supla::TOGGLE, relay_19, Supla::ON_PRESS);
+ button_19->setSwNoiseFilterDelay(50);
+ button_20->addAction(Supla::TOGGLE, relay_20, Supla::ON_PRESS);
+ button_20->setSwNoiseFilterDelay(50);
+ button_21->addAction(Supla::TOGGLE, relay_21, Supla::ON_PRESS);
+ button_21->setSwNoiseFilterDelay(50);
+ button_22->addAction(Supla::TOGGLE, relay_22, Supla::ON_PRESS);
+ button_22->setSwNoiseFilterDelay(50);
+ button_23->addAction(Supla::TOGGLE, relay_23, Supla::ON_PRESS);
+ button_23->setSwNoiseFilterDelay(50);
+ button_24->addAction(Supla::TOGGLE, relay_24, Supla::ON_PRESS);
+ button_24->setSwNoiseFilterDelay(50);
+ button_25->addAction(Supla::TOGGLE, relay_25, Supla::ON_PRESS);
+ button_25->setSwNoiseFilterDelay(50);
+ button_26->addAction(Supla::TOGGLE, relay_26, Supla::ON_PRESS);
+ button_26->setSwNoiseFilterDelay(50);
+ button_27->addAction(Supla::TOGGLE, relay_27, Supla::ON_PRESS);
+ button_27->setSwNoiseFilterDelay(50);
+ button_28->addAction(Supla::TOGGLE, relay_28, Supla::ON_PRESS);
+ button_28->setSwNoiseFilterDelay(50);
+ button_29->addAction(Supla::TOGGLE, relay_29, Supla::ON_PRESS);
+ button_29->setSwNoiseFilterDelay(50);
+ button_30->addAction(Supla::TOGGLE, relay_30, Supla::ON_PRESS);
+ button_30->setSwNoiseFilterDelay(50);
+ button_31->addAction(Supla::TOGGLE, relay_31, Supla::ON_PRESS);
+ button_31->setSwNoiseFilterDelay(50);
+ button_32->addAction(Supla::TOGGLE, relay_32, Supla::ON_PRESS);
+ button_32->setSwNoiseFilterDelay(50);
+
+ /*
+ * SuplaDevice Initialization.
+ * Server address is available at https://cloud.supla.org
+ * If you do not have an account, you can create it at https://cloud.supla.org/account/create
+ * SUPLA and SUPLA CLOUD are free of charge
+ *
+ */
+
+ SuplaDevice.begin(GUID, // Global Unique Identifier
+ "svr1.supla.org", // SUPLA server address
+ "email@address", // Email address used to login to Supla Cloud
+ AUTHKEY); // Authorization key
+
+}
+
+void loop() {
+ SuplaDevice.iterate();
+ delay(25);
+}
diff --git a/lib/SuplaDevice/src/supla/control/MCP23017/readme.txt b/lib/SuplaDevice/src/supla/control/MCP23017/readme.txt
new file mode 100644
index 00000000..9cb235ee
--- /dev/null
+++ b/lib/SuplaDevice/src/supla/control/MCP23017/readme.txt
@@ -0,0 +1,15 @@
+Support for up to 4 x "MCP23017" additional 64 Gpios.
+
+
+BASIC USE:
+
+INSTANTIATE
+#include
+
+SETUP
+ mcp1.init(uint8_t sda, uint8_t scl); // init(uint8_t sda, uint8_t scl) = Wire.begin();
+
+ mcp1.begin(uint8_t mcp23017_address); // Pin 100 - 115
+ mcp2.begin(uint8_t mcp23017_address); // Pin 116 - 131
+ mcp3.begin(uint8_t mcp23017_address); // Pin 132 - 147
+ mcp4.begin(uint8_t mcp23017_address); // Pin 148 - 163
\ No newline at end of file
diff --git a/lib/SuplaDevice/src/supla/control/MCP23017/supla_mcp23017.h b/lib/SuplaDevice/src/supla/control/MCP23017/supla_mcp23017.h
new file mode 100644
index 00000000..8dfa9598
--- /dev/null
+++ b/lib/SuplaDevice/src/supla/control/MCP23017/supla_mcp23017.h
@@ -0,0 +1,78 @@
+
+#ifndef S_mcp_23017_h
+#define S_mcp_23017_h
+
+#include
+#include
+#include
+
+
+ MCP23017 mcp1;
+ MCP23017 mcp2;
+ MCP23017 mcp3;
+ MCP23017 mcp4;
+
+
+class CustomControl : public Supla::Io {
+ public:
+ void customDigitalWrite(int channelNumber, uint8_t pin, uint8_t val) {
+ if (pin < 100) {
+ return ::digitalWrite(pin,val);
+ }
+ if ((pin > 99) && (pin < 116)){
+ mcp1.digitalWrite(pin - 100, val);
+ return;
+ }
+ if ((pin > 115) && (pin < 132)){
+ mcp2.digitalWrite(pin - 116, val);
+ }
+ if ((pin > 131) && (pin < 148)){
+ mcp3.digitalWrite(pin - 132, val);
+ return;
+ }
+ if ((pin > 147) && (pin < 164)){
+ mcp4.digitalWrite(pin - 148, val);
+ return;
+ }
+ }
+ int customDigitalRead(int channelNumber, uint8_t pin) {
+ if (pin < 100){
+ return ::digitalRead(pin);
+ }
+ if ((pin > 99)&& (pin < 116)){
+ return mcp1.digitalRead(pin - 100);
+ }
+ if ((pin > 115)&& (pin < 132)){
+ return mcp2.digitalRead(pin - 116);
+ }
+ if ((pin > 131)&& (pin < 148)){
+ return mcp3.digitalRead(pin - 132);
+ }
+ if ((pin > 147)&& (pin < 164)){
+ return mcp4.digitalRead(pin - 148);
+ }
+ }
+ void customPinMode(int channelNumber, uint8_t pin, uint8_t mode) {
+ (void)(channelNumber);
+ if (pin < 100){
+ return ::pinMode(pin, mode);
+ }
+ if ((pin > 99)&& (pin < 116)){
+ mcp1.pinMode(pin - 100, mode);
+ }
+ if ((pin > 115)&& (pin < 132)){
+ mcp2.pinMode(pin - 116, mode);
+ }
+ if ((pin > 131)&& (pin < 148)){
+ mcp3.pinMode(pin - 132, mode);
+ }
+ if ((pin > 147)&& (pin < 164)){
+ mcp4.pinMode(pin - 148, mode);
+ }
+ }
+
+}CustomControl;
+
+
+#endif
+
diff --git a/lib/SuplaDevice/src/supla/control/bistable_relay.cpp b/lib/SuplaDevice/src/supla/control/bistable_relay.cpp
index 3fabf297..d03f2aa4 100644
--- a/lib/SuplaDevice/src/supla/control/bistable_relay.cpp
+++ b/lib/SuplaDevice/src/supla/control/bistable_relay.cpp
@@ -40,7 +40,7 @@ BistableRelay::BistableRelay(int pin,
void BistableRelay::onInit() {
if (statusPin >= 0) {
- pinMode(statusPin, statusPullUp ? INPUT_PULLUP : INPUT);
+ Supla::Io::pinMode(channel.getChannelNumber(), statusPin, statusPullUp ? INPUT_PULLUP : INPUT);
channel.setNewValue(isOn());
} else {
channel.setNewValue(false);
@@ -56,7 +56,7 @@ void BistableRelay::onInit() {
turnOff();
}
- pinMode(pin, OUTPUT);
+ Supla::Io::pinMode(channel.getChannelNumber(), pin, OUTPUT);
}
void BistableRelay::iterateAlways() {
@@ -138,6 +138,9 @@ void BistableRelay::internalToggle() {
busy = true;
disarmTimeMs = millis();
Supla::Io::digitalWrite(channel.getChannelNumber(), pin, pinOnValue());
+
+ // Schedule save in 5 s after state change
+ Supla::Storage::ScheduleSave(5000);
}
void BistableRelay::toggle(_supla_int_t duration) {
diff --git a/lib/SuplaDevice/src/supla/control/bistable_roller_shutter.cpp b/lib/SuplaDevice/src/supla/control/bistable_roller_shutter.cpp
index 5fc8fe1f..9401633f 100644
--- a/lib/SuplaDevice/src/supla/control/bistable_roller_shutter.cpp
+++ b/lib/SuplaDevice/src/supla/control/bistable_roller_shutter.cpp
@@ -15,6 +15,7 @@
*/
#include "bistable_roller_shutter.h"
+#include
namespace Supla {
namespace Control {
@@ -33,28 +34,30 @@ void BistableRollerShutter::stopMovement() {
}
currentDirection = STOP_DIR;
doNothingTime = millis();
+ // Schedule save in 5 s after stop movement of roller shutter
+ Supla::Storage::ScheduleSave(5000);
}
void BistableRollerShutter::relayDownOn() {
activeBiRelay = true;
toggleTime = millis();
- digitalWrite(pinDown, highIsOn ? HIGH : LOW);
+ Supla::Io::digitalWrite(channel.getChannelNumber(), pinDown, highIsOn ? HIGH : LOW);
}
void BistableRollerShutter::relayUpOn() {
activeBiRelay = true;
toggleTime = millis();
- digitalWrite(pinUp, highIsOn ? HIGH : LOW);
+ Supla::Io::digitalWrite(channel.getChannelNumber(), pinUp, highIsOn ? HIGH : LOW);
}
void BistableRollerShutter::relayDownOff() {
activeBiRelay = false;
- digitalWrite(pinDown, highIsOn ? LOW : HIGH);
+ Supla::Io::digitalWrite(channel.getChannelNumber(), pinDown, highIsOn ? LOW : HIGH);
}
void BistableRollerShutter::relayUpOff() {
activeBiRelay = false;
- digitalWrite(pinUp, highIsOn ? LOW : HIGH);
+ Supla::Io::digitalWrite(channel.getChannelNumber(), pinUp, highIsOn ? LOW : HIGH);
}
void BistableRollerShutter::onTimer() {
diff --git a/lib/SuplaDevice/src/supla/control/button.cpp b/lib/SuplaDevice/src/supla/control/button.cpp
index 950b9f3e..9971de8c 100644
--- a/lib/SuplaDevice/src/supla/control/button.cpp
+++ b/lib/SuplaDevice/src/supla/control/button.cpp
@@ -16,61 +16,15 @@
#include "button.h"
-enum StateResults {PRESSED, RELEASED, TO_PRESSED, TO_RELEASED};
-
-Supla::Control::ButtonState::ButtonState(int pin, bool pullUp, bool invertLogic)
- : debounceTimeMs(0),
- filterTimeMs(0),
- debounceDelayMs(50),
- swNoiseFilterDelayMs(20),
- pin(pin),
- newStatusCandidate(LOW),
- prevState(LOW),
- pullUp(pullUp),
- invertLogic(invertLogic) {
-}
-
-int Supla::Control::ButtonState::update() {
- if (millis() - debounceTimeMs > debounceDelayMs) {
- int currentState = digitalRead(pin);
- if (currentState != prevState) {
- // If status is changed, then make sure that it will be kept at
- // least swNoiseFilterDelayMs ms to avoid noise
- if (currentState != newStatusCandidate) {
- newStatusCandidate = currentState;
- filterTimeMs = millis();
- } else if (millis() - filterTimeMs > swNoiseFilterDelayMs) {
- // If new status is kept at least swNoiseFilterDelayMs ms, then apply
- // change of status
- debounceTimeMs = millis();
- prevState = currentState;
- if (currentState == valueOnPress()) {
- return TO_PRESSED;
- } else {
- return TO_RELEASED;
- }
- }
- } else {
- // If current status is the same as prevState, then reset
- // new status candidate
- newStatusCandidate = prevState;
- }
- }
- if (prevState == valueOnPress()) {
- return PRESSED;
- } else {
- return RELEASED;
- }
-}
Supla::Control::Button::Button(int pin, bool pullUp, bool invertLogic)
- : state(pin, pullUp, invertLogic),
+ : SimpleButton(pin, pullUp, invertLogic),
holdTimeMs(0),
+ repeatOnHoldMs(0),
multiclickTimeMs(0),
- clickCounter(0),
lastStateChangeMs(0),
- enableExtDetection(false),
- holdSend(false),
+ clickCounter(0),
+ holdSend(0),
bistable(false) {
}
@@ -88,15 +42,26 @@ void Supla::Control::Button::onTimer() {
runAction(ON_CHANGE);
}
+ if (stateChanged) {
+ lastStateChangeMs = millis();
+ if (stateResult == TO_PRESSED || bistable) {
+ clickCounter++;
+ }
+ }
+
if (!stateChanged) {
if (!bistable && stateResult == PRESSED) {
- if (clickCounter <= 1 && holdTimeMs > 0 && timeDelta > holdTimeMs && !holdSend) {
+ if (clickCounter <= 1 && holdTimeMs > 0 && timeDelta > (holdTimeMs + holdSend*repeatOnHoldMs) && (repeatOnHoldMs == 0 ? !holdSend : true)) {
runAction(ON_HOLD);
- holdSend = true;
+ ++holdSend;
+ }
+ } else if (clickCounter > 0 && (bistable || stateResult == RELEASED)) {
+ if (multiclickTimeMs == 0) {
+ holdSend = 0;
+ clickCounter = 0;
}
- } else if (bistable || stateResult == RELEASED) {
if (multiclickTimeMs > 0 && timeDelta > multiclickTimeMs) {
- if (!holdSend) {
+ if (holdSend == 0) {
switch (clickCounter) {
case 1:
runAction(ON_CLICK_1);
@@ -129,49 +94,15 @@ void Supla::Control::Button::onTimer() {
runAction(ON_CLICK_10);
break;
}
- }
- holdSend = false;
+ if (clickCounter >= 10) {
+ runAction(ON_CRAZY_CLICKER);
+ }
+ }
+ holdSend = 0;
clickCounter = 0;
}
}
}
-
- if (stateChanged) {
- lastStateChangeMs = millis();
- if (stateResult == TO_PRESSED || bistable) {
- clickCounter++;
- }
-
- }
-}
-
-void Supla::Control::Button::onInit() {
- state.init();
-}
-
-void Supla::Control::ButtonState::init() {
- pinMode(pin, pullUp ? INPUT_PULLUP : INPUT);
- prevState = digitalRead(pin);
- newStatusCandidate = prevState;
-}
-
-int Supla::Control::ButtonState::valueOnPress() {
- return invertLogic ? LOW : HIGH;
-}
-
-void Supla::Control::Button::setSwNoiseFilterDelay(unsigned int newDelayMs) {
- state.setSwNoiseFilterDelay(newDelayMs);
-}
-void Supla::Control::ButtonState::setSwNoiseFilterDelay(unsigned int newDelayMs) {
- swNoiseFilterDelayMs = newDelayMs;
-}
-
-void Supla::Control::Button::setDebounceDelay(unsigned int newDelayMs) {
- state.setDebounceDelay(newDelayMs);
-}
-
-void Supla::Control::ButtonState::setDebounceDelay(unsigned int newDelayMs) {
- debounceDelayMs = newDelayMs;
}
void Supla::Control::Button::setHoldTime(unsigned int timeMs) {
@@ -188,3 +119,7 @@ void Supla::Control::Button::setMulticlickTime(unsigned int timeMs, bool bistabl
holdTimeMs = 0;
}
}
+
+void Supla::Control::Button::repeatOnHoldEvery(unsigned int timeMs) {
+ repeatOnHoldMs = timeMs;
+}
diff --git a/lib/SuplaDevice/src/supla/control/button.h b/lib/SuplaDevice/src/supla/control/button.h
index 7cf146a3..ba31ab58 100644
--- a/lib/SuplaDevice/src/supla/control/button.h
+++ b/lib/SuplaDevice/src/supla/control/button.h
@@ -18,59 +18,27 @@
#define _button_h
#include
-
-#include "../element.h"
-#include "../events.h"
-#include "../local_action.h"
+#include "simple_button.h"
namespace Supla {
namespace Control {
-class ButtonState {
- public:
- ButtonState(int pin, bool pullUp, bool invertLogic);
- int update();
- void init();
-
- void setSwNoiseFilterDelay(unsigned int newDelayMs);
- void setDebounceDelay(unsigned int newDelayMs);
- void setHoldTime(unsigned int timeMs);
- void setMulticlickTime(unsigned int timeMs);
-
- protected:
- int valueOnPress();
-
- unsigned long debounceTimeMs;
- unsigned long filterTimeMs;
- unsigned int debounceDelayMs;
- unsigned int swNoiseFilterDelayMs;
- int pin;
- int8_t newStatusCandidate;
- int8_t prevState;
- bool pullUp;
- bool invertLogic;
-};
-
-class Button : public Element,
- public LocalAction {
+class Button : public SimpleButton {
public:
Button(int pin, bool pullUp = false, bool invertLogic = false);
void onTimer();
- void onInit();
- void setSwNoiseFilterDelay(unsigned int newDelayMs);
- void setDebounceDelay(unsigned int newDelayMs);
void setHoldTime(unsigned int timeMs);
+ void repeatOnHoldEvery(unsigned int timeMs);
void setMulticlickTime(unsigned int timeMs, bool bistableButton = false);
protected:
- ButtonState state;
unsigned int holdTimeMs;
+ unsigned int repeatOnHoldMs;
unsigned int multiclickTimeMs;
- uint8_t clickCounter;
unsigned long lastStateChangeMs;
- bool enableExtDetection;
- bool holdSend;
+ uint8_t clickCounter;
+ unsigned int holdSend;
bool bistable;
};
diff --git a/lib/SuplaDevice/src/supla/control/dimmer_base.cpp b/lib/SuplaDevice/src/supla/control/dimmer_base.cpp
new file mode 100644
index 00000000..88f6f1e6
--- /dev/null
+++ b/lib/SuplaDevice/src/supla/control/dimmer_base.cpp
@@ -0,0 +1,48 @@
+/*
+ Copyright (C) AC SOFTWARE SP. Z O.O.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ 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 General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "dimmer_base.h"
+#include "../storage/storage.h"
+
+Supla::Control::DimmerBase::DimmerBase() {
+ channel.setType(SUPLA_CHANNELTYPE_DIMMER);
+ channel.setDefault(SUPLA_CHANNELFNC_DIMMER);
+}
+
+void Supla::Control::DimmerBase::setRGBW(int red,
+ int green,
+ int blue,
+ int colorBrightness,
+ int brightness,
+ bool toggle) {
+ Supla::Control::RGBWBase::setRGBW(0, 0, 0, 0, brightness, toggle);
+}
+
+void Supla::Control::DimmerBase::onLoadState() {
+ Supla::Storage::ReadState((unsigned char *)&curBrightness,
+ sizeof(curBrightness));
+ Supla::Storage::ReadState((unsigned char *)&lastBrightness, sizeof(lastBrightness));
+}
+
+void Supla::Control::DimmerBase::onSaveState() {
+ Supla::Storage::WriteState((unsigned char *)&curBrightness,
+ sizeof(curBrightness));
+ Supla::Storage::WriteState((unsigned char *)&lastBrightness, sizeof(lastBrightness));
+}
+
+void Supla::Control::DimmerBase::iterateDimmerRGBW(int rgbStep, int wStep) {
+ Supla::Control::RGBWBase::iterateDimmerRGBW(0, wStep);
+}
diff --git a/lib/SuplaDevice/src/supla/control/dimmer_base.h b/lib/SuplaDevice/src/supla/control/dimmer_base.h
index cd88b026..29b665c0 100644
--- a/lib/SuplaDevice/src/supla/control/dimmer_base.h
+++ b/lib/SuplaDevice/src/supla/control/dimmer_base.h
@@ -24,10 +24,20 @@ namespace Supla {
namespace Control {
class DimmerBase : public RGBWBase {
public:
- DimmerBase() {
- channel.setType(SUPLA_CHANNELTYPE_DIMMER);
- channel.setDefault(SUPLA_CHANNELFNC_DIMMER);
- }
+ DimmerBase();
+
+ void setRGBW(int red,
+ int green,
+ int blue,
+ int colorBrightness,
+ int brightness,
+ bool toggle = false);
+
+ void onLoadState();
+ void onSaveState();
+
+ protected:
+ virtual void iterateDimmerRGBW(int rgbStep, int wStep);
};
diff --git a/lib/SuplaDevice/src/supla/control/dimmer_leds.cpp b/lib/SuplaDevice/src/supla/control/dimmer_leds.cpp
new file mode 100644
index 00000000..10abcb05
--- /dev/null
+++ b/lib/SuplaDevice/src/supla/control/dimmer_leds.cpp
@@ -0,0 +1,67 @@
+/*
+Copyright (C) AC SOFTWARE SP. Z O.O.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+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 General Public License for more details.
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "dimmer_leds.h"
+
+#ifdef ARDUINO_ARCH_ESP32
+extern int esp32PwmChannelCouner;
+#endif
+
+Supla::Control::DimmerLeds::DimmerLeds(int brightnessPin)
+ : brightnessPin(brightnessPin) {
+}
+
+void Supla::Control::DimmerLeds::setRGBWValueOnDevice(uint32_t red,
+ uint32_t green,
+ uint32_t blue,
+ uint32_t colorBrightness,
+ uint32_t brightness) {
+ uint32_t brightnessAdj = brightness;
+
+#ifdef ARDUINO_ARCH_AVR
+ brightnessAdj = map(brightnessAdj, 0, 1023, 0, 255);
+#endif
+
+#ifdef ARDUINO_ARCH_ESP32
+ ledcWrite(brightnessPin, brightnessAdj);
+#else
+ analogWrite(brightnessPin, brightnessAdj);
+#endif
+}
+
+void Supla::Control::DimmerLeds::onInit() {
+#ifdef ARDUINO_ARCH_ESP32
+ Serial.print(F("Dimmer: attaching pin "));
+ Serial.print(brightnessPin);
+ Serial.print(F(" to PWM channel: "));
+ Serial.println(esp32PwmChannelCouner);
+
+ ledcSetup(esp32PwmChannelCouner, 12000, 10);
+ ledcAttachPin(brightnessPin, esp32PwmChannelCouner);
+ // on ESP32 we write to PWM channels instead of pins, so we copy channel
+ // number as pin in order to reuse variable
+ brightnessPin = esp32PwmChannelCouner;
+ esp32PwmChannelCouner++;
+#else
+ pinMode(brightnessPin, OUTPUT);
+
+#ifdef ARDUINO_ARCH_ESP8266
+ analogWriteRange(1024);
+#endif
+#endif
+
+ Supla::Control::DimmerBase::onInit();
+}
diff --git a/lib/SuplaDevice/src/supla/control/dimmer_leds.h b/lib/SuplaDevice/src/supla/control/dimmer_leds.h
new file mode 100644
index 00000000..041639e5
--- /dev/null
+++ b/lib/SuplaDevice/src/supla/control/dimmer_leds.h
@@ -0,0 +1,44 @@
+/*
+Copyright (C) AC SOFTWARE SP. Z O.O.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+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 General Public License for more details.
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#ifndef __dimmer_leds_h
+#define __dimmer_leds_h
+
+#include "dimmer_base.h"
+
+namespace Supla {
+namespace Control {
+class DimmerLeds : public DimmerBase {
+ public:
+ DimmerLeds(int brightnessPin);
+
+ void setRGBWValueOnDevice(uint32_t red,
+ uint32_t green,
+ uint32_t blue,
+ uint32_t colorBrightness,
+ uint32_t brightness);
+
+ void onInit();
+
+ protected:
+ int brightnessPin;
+};
+
+}; // namespace Control
+}; // namespace Supla
+
+#endif
+
diff --git a/lib/SuplaDevice/src/supla/control/direct_links.cpp b/lib/SuplaDevice/src/supla/control/direct_links.cpp
new file mode 100644
index 00000000..60cad047
--- /dev/null
+++ b/lib/SuplaDevice/src/supla/control/direct_links.cpp
@@ -0,0 +1,156 @@
+/*
+ Copyright (C) AC SOFTWARE SP. Z O.O.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ 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 General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "direct_links.h"
+
+#include
+
+namespace Supla {
+namespace Control {
+
+DirectLinks::DirectLinks(const char *host, bool isSecured)
+ : _lastStateON(false), _lastStateOFF(false) {
+ setHost(host);
+ enableSSL(isSecured);
+}
+
+DirectLinks::~DirectLinks() {
+ delete[] client;
+}
+
+void DirectLinks::setHost(const char *host) {
+ if (host) {
+ strncpy(_host, host, MAX_HOST_SIZE);
+ }
+}
+
+void DirectLinks::setUrlON(const char *url) {
+ if (url) {
+ strncpy(_urlON, url, MAX_DIRECT_LINKS_SIZE);
+ }
+}
+
+void DirectLinks::setUrlOFF(const char *url) {
+ if (url) {
+ strncpy(_urlOFF, url, MAX_DIRECT_LINKS_SIZE);
+ }
+}
+
+void DirectLinks::enableSSL(bool isSecured) {
+ _isSecured = isSecured;
+}
+
+bool DirectLinks::openConnection() {
+ if (!client->connect(_host, _isSecured ? 443 : 80)) {
+ return false;
+ }
+ return true;
+}
+
+bool DirectLinks::closeConnection() {
+ client->stop();
+ return checkConnection();
+}
+
+bool DirectLinks::checkConnection() {
+ if (client->connected() == 1) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+void DirectLinks::toggleConnection() {
+ if (client == NULL) {
+ if (_isSecured) {
+ client = new WiFiClientSecure();
+ ((WiFiClientSecure *)client)->setInsecure();
+ ((WiFiClientSecure *)client)->setBufferSizes(256, 256);
+ ((WiFiClientSecure *)client)->setTimeout(200);
+ } else {
+ client = new WiFiClient();
+ }
+ }
+
+ if (checkConnection()) {
+ closeConnection();
+ } else {
+ openConnection();
+ }
+}
+
+void DirectLinks::sendRequest(const char *url) {
+ if (client) {
+ (WiFiClientSecure *)client->print(
+ String("GET /direct/") + url + " HTTP/1.1\r\n" + "Host: " + _host +
+ "\r\n" + "User-Agent: BuildFailureDetectorESP8266\r\n" +
+ "Connection: close\r\n\r\n");
+
+ while (client->connected() || client->available()) {
+ String line = client->readStringUntil('\n');
+ if (line == "\r") {
+ Serial.println(F("Direct links - Headers received"));
+ break;
+ }
+ }
+
+ String line = client->readString();
+ if (line.indexOf("true") != -1) {
+ Serial.println(F("Alert sent successfully!"));
+ } else {
+ Serial.print(F("Alert failure"));
+ Serial.println(line);
+ }
+ }
+}
+
+void DirectLinks::send(const char *url) {
+ toggleConnection();
+ sendRequest(url);
+ toggleConnection();
+
+ if (client) {
+ delete client;
+ client = nullptr;
+ }
+}
+
+void DirectLinks::iterateAlways() {
+ if (_lastStateON) {
+ _lastStateON = false;
+ send(_urlON);
+ }
+ if (_lastStateOFF) {
+ _lastStateOFF = false;
+ send(_urlOFF);
+ }
+}
+
+void DirectLinks::handleAction(int event, int action) {
+ (void)(event);
+
+ switch (action) {
+ case SEND_DIRECT_LINKS_ON:
+ _lastStateON = true;
+ break;
+ case SEND_DIRECT_LINKS_OFF:
+ _lastStateOFF = true;
+ break;
+ }
+}
+
+}; // namespace Control
+}; // namespace Supla
diff --git a/lib/SuplaDevice/src/supla/control/direct_links.h b/lib/SuplaDevice/src/supla/control/direct_links.h
new file mode 100644
index 00000000..6526c66e
--- /dev/null
+++ b/lib/SuplaDevice/src/supla/control/direct_links.h
@@ -0,0 +1,75 @@
+/*
+ Copyright (C) AC SOFTWARE SP. Z O.O.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ 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 General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#ifndef _direct_link_h
+#define _direct_link_h
+
+#include
+#include
+
+#include "../action_handler.h"
+#include "../actions.h"
+#include "../channel_element.h"
+
+#define MAX_DIRECT_LINKS_SIZE 32
+#define MAX_HOST_SIZE 32
+
+namespace Supla {
+enum DirectLinks {
+ SEND_DIRECT_LINKS_ON,
+ SEND_DIRECT_LINKS_OFF,
+};
+}
+
+namespace Supla {
+namespace Control {
+
+class DirectLinks : public Element, public ActionHandler {
+ public:
+ DirectLinks(const char *host, bool isSecured = true);
+ ~DirectLinks();
+
+ void setHost(const char *host);
+ void setUrlON(const char *url);
+ void setUrlOFF(const char *url);
+ void enableSSL(bool isSecured);
+
+ void iterateAlways();
+ void handleAction(int event, int action);
+
+ bool checkConnection();
+ void toggleConnection();
+ bool openConnection();
+ bool closeConnection();
+ void sendRequest(const char *url);
+ void send(const char *url);
+
+ protected:
+ WiFiClient *client = NULL;
+ bool _lastStateON;
+ bool _lastStateOFF;
+ int _action;
+
+ bool _isSecured;
+ char _urlON[MAX_DIRECT_LINKS_SIZE];
+ char _urlOFF[MAX_DIRECT_LINKS_SIZE];
+ char _host[MAX_HOST_SIZE];
+};
+
+}; // namespace Control
+}; // namespace Supla
+
+#endif
diff --git a/lib/SuplaDevice/src/supla/control/internal_pin_output.cpp b/lib/SuplaDevice/src/supla/control/internal_pin_output.cpp
new file mode 100644
index 00000000..c889cb40
--- /dev/null
+++ b/lib/SuplaDevice/src/supla/control/internal_pin_output.cpp
@@ -0,0 +1,124 @@
+/*
+ Copyright (C) AC SOFTWARE SP. Z O.O.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ 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 General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include
+
+#include "internal_pin_output.h"
+#include "../events.h"
+
+Supla::Control::InternalPinOutput::InternalPinOutput(int pin, bool highIsOn)
+ : pin(pin),
+ highIsOn(highIsOn),
+ stateOnInit(STATE_ON_INIT_OFF),
+ storedTurnOnDurationMs(0),
+ durationTimestamp(0),
+ durationMs(0) {
+}
+
+Supla::Control::InternalPinOutput &
+Supla::Control::InternalPinOutput::setDefaultStateOn() {
+ stateOnInit = STATE_ON_INIT_ON;
+ return *this;
+}
+Supla::Control::InternalPinOutput &
+Supla::Control::InternalPinOutput::setDefaultStateOff() {
+ stateOnInit = STATE_ON_INIT_OFF;
+ return *this;
+}
+
+uint8_t Supla::Control::InternalPinOutput::pinOnValue() {
+ return highIsOn ? HIGH : LOW;
+}
+
+uint8_t Supla::Control::InternalPinOutput::pinOffValue() {
+ return highIsOn ? LOW : HIGH;
+}
+
+void Supla::Control::InternalPinOutput::turnOn(_supla_int_t duration) {
+ durationMs = duration;
+ durationTimestamp = millis();
+ if (storedTurnOnDurationMs) {
+ durationMs = storedTurnOnDurationMs;
+ }
+
+ runAction(Supla::ON_TURN_ON);
+ runAction(Supla::ON_CHANGE);
+
+ Supla::Io::digitalWrite(pin, pinOnValue());
+}
+
+void Supla::Control::InternalPinOutput::turnOff(_supla_int_t duration) {
+ durationMs = duration;
+ durationTimestamp = millis();
+
+ runAction(Supla::ON_TURN_OFF);
+ runAction(Supla::ON_CHANGE);
+
+ Supla::Io::digitalWrite(pin, pinOffValue());
+}
+
+bool Supla::Control::InternalPinOutput::isOn() {
+ return Supla::Io::digitalRead(pin) == pinOnValue();
+}
+
+void Supla::Control::InternalPinOutput::toggle(_supla_int_t duration) {
+ if (isOn()) {
+ turnOff(duration);
+ } else {
+ turnOn(duration);
+ }
+}
+
+void Supla::Control::InternalPinOutput::handleAction(int event, int action) {
+ (void)(event);
+ switch (action) {
+ case TURN_ON: {
+ turnOn();
+ break;
+ }
+ case TURN_OFF: {
+ turnOff();
+ break;
+ }
+ case TOGGLE: {
+ toggle();
+ break;
+ }
+ }
+}
+
+void Supla::Control::InternalPinOutput::onInit() {
+ if (stateOnInit == STATE_ON_INIT_ON) {
+ turnOn();
+ } else {
+ turnOff();
+ }
+
+ Supla::Io::pinMode(
+ pin, OUTPUT); // pin mode is set after setting pin value in order to
+ // avoid problems with LOW trigger relays
+}
+void Supla::Control::InternalPinOutput::iterateAlways() {
+ if (durationMs && millis() - durationTimestamp > durationMs) {
+ toggle();
+ }
+}
+
+Supla::Control::InternalPinOutput &
+Supla::Control::InternalPinOutput::setDurationMs(_supla_int_t duration) {
+ storedTurnOnDurationMs = duration;
+ return *this;
+}
diff --git a/lib/SuplaDevice/src/supla/control/internal_pin_output.h b/lib/SuplaDevice/src/supla/control/internal_pin_output.h
new file mode 100644
index 00000000..e1efe8bd
--- /dev/null
+++ b/lib/SuplaDevice/src/supla/control/internal_pin_output.h
@@ -0,0 +1,67 @@
+/*
+ Copyright (C) AC SOFTWARE SP. Z O.O.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ 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 General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#ifndef _internal_pin_output_h
+#define _internal_pin_output_h
+
+#include "../action_handler.h"
+#include "../actions.h"
+#include "../element.h"
+#include "../io.h"
+#include "../local_action.h"
+
+#define STATE_ON_INIT_OFF 0
+#define STATE_ON_INIT_ON 1
+
+namespace Supla {
+namespace Control {
+class InternalPinOutput : public Element,
+ public ActionHandler,
+ public LocalAction {
+ public:
+ InternalPinOutput(int pin, bool highIsOn = true);
+
+ virtual InternalPinOutput &setDefaultStateOn();
+ virtual InternalPinOutput &setDefaultStateOff();
+ virtual InternalPinOutput &setDurationMs(_supla_int_t duration);
+
+ virtual uint8_t pinOnValue();
+ virtual uint8_t pinOffValue();
+ virtual void turnOn(_supla_int_t duration = 0);
+ virtual void turnOff(_supla_int_t duration = 0);
+ virtual bool isOn();
+ virtual void toggle(_supla_int_t duration = 0);
+
+ void handleAction(int event, int action);
+
+ void onInit();
+ void iterateAlways();
+
+ protected:
+ int pin;
+ bool highIsOn;
+
+ int8_t stateOnInit;
+
+ unsigned _supla_int_t durationMs;
+ unsigned _supla_int_t storedTurnOnDurationMs;
+ unsigned long durationTimestamp;
+};
+
+}; // namespace Control
+}; // namespace Supla
+
+#endif
diff --git a/lib/SuplaDevice/src/supla/control/pin_status_led.cpp b/lib/SuplaDevice/src/supla/control/pin_status_led.cpp
new file mode 100644
index 00000000..dd4d89e3
--- /dev/null
+++ b/lib/SuplaDevice/src/supla/control/pin_status_led.cpp
@@ -0,0 +1,48 @@
+/*
+ Copyright (C) AC SOFTWARE SP. Z O.O.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ 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 General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include
+
+#include "../io.h"
+#include "pin_status_led.h"
+
+Supla::Control::PinStatusLed::PinStatusLed(uint8_t srcPin,
+ uint8_t outPin,
+ bool invert)
+ : srcPin(srcPin), outPin(outPin), invert(invert) {
+}
+
+void Supla::Control::PinStatusLed::onInit() {
+ updatePin();
+ Supla::Io::pinMode(outPin, OUTPUT);
+}
+
+void Supla::Control::PinStatusLed::iterateAlways() {
+ updatePin();
+}
+
+void Supla::Control::PinStatusLed::setInvertedLogic(bool invertedLogic) {
+ invert = invertedLogic;
+ updatePin();
+}
+
+void Supla::Control::PinStatusLed::updatePin() {
+ int value = Supla::Io::digitalRead(srcPin);
+ value = invert ? !value : value;
+ if (value != Supla::Io::digitalRead(outPin)) {
+ Supla::Io::digitalWrite(outPin, value);
+ }
+}
diff --git a/lib/SuplaDevice/src/supla/control/pin_status_led.h b/lib/SuplaDevice/src/supla/control/pin_status_led.h
new file mode 100644
index 00000000..39d2fc0a
--- /dev/null
+++ b/lib/SuplaDevice/src/supla/control/pin_status_led.h
@@ -0,0 +1,43 @@
+/*
+ Copyright (C) AC SOFTWARE SP. Z O.O.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ 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 General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#ifndef _pin_status_led_h
+#define _pin_status_led_h
+
+#include "../element.h"
+
+namespace Supla {
+namespace Control {
+class PinStatusLed : public Element {
+ public:
+ PinStatusLed(uint8_t srcPin, uint8_t outPin, bool invert = false);
+
+ void onInit();
+ void iterateAlways();
+ void setInvertedLogic(bool invertedLogic);
+
+ protected:
+ void updatePin();
+
+ uint8_t srcPin;
+ uint8_t outPin;
+ bool invert;
+};
+
+}; // namespace Control
+}; // namespace Supla
+
+#endif
diff --git a/lib/SuplaDevice/src/supla/control/pushover.cpp b/lib/SuplaDevice/src/supla/control/pushover.cpp
new file mode 100644
index 00000000..b996da54
--- /dev/null
+++ b/lib/SuplaDevice/src/supla/control/pushover.cpp
@@ -0,0 +1,159 @@
+/*
+ Copyright (C) AC SOFTWARE SP. Z O.O.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ 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 General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "pushover.h"
+
+#include
+
+namespace Supla {
+namespace Control {
+
+Pushover::Pushover(const char *token, const char *user, bool isSecured)
+ : lastMsgReceivedMs(0) {
+ setToken(token);
+ setUser(user);
+ _isSecured = isSecured;
+}
+
+Pushover::~Pushover() {
+ delete[] client;
+}
+
+void Pushover::setToken(const char *token) {
+ if (token) {
+ strncpy(_token, token, MAX_TOKEN_SIZE);
+ }
+}
+
+void Pushover::setUser(const char *user) {
+ if (user) {
+ strncpy(_user, user, MAX_TOKEN_SIZE);
+ }
+}
+
+void Pushover::setTitle(const char *title) {
+ if (title) {
+ strncpy(_title, title, MAX_TOKEN_SIZE);
+ }
+}
+
+void Pushover::setMessage(const char *message) {
+ if (message) {
+ strncpy(_message, message, MAX_TOKEN_SIZE);
+ }
+}
+
+bool Pushover::openConnection() {
+ if (!client->connect(host, _isSecured ? 443 : 80)) {
+ return false;
+ }
+ return true;
+}
+
+bool Pushover::closeConnection() {
+ client->stop();
+ return checkConnection();
+}
+
+bool Pushover::checkConnection() {
+ if (client->connected() == 1) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+void Pushover::toggleConnection() {
+ if (client == NULL) {
+ if (_isSecured) {
+ client = new WiFiClientSecure();
+ ((WiFiClientSecure *)client)->setInsecure();
+ ((WiFiClientSecure *)client)->setBufferSizes(256, 256);
+ ((WiFiClientSecure *)client)->setTimeout(200);
+ } else {
+ client = new WiFiClient();
+ }
+ }
+
+ if (checkConnection()) {
+ closeConnection();
+ } else {
+ openConnection();
+ }
+}
+
+void Pushover::sendRequest() {
+ if (client) {
+ String post = String("token=") + _token + "&user=" + _user +
+ "&title=" + _title + "&message=" + _message;
+
+ /* String("token=") + _token + "&user=" + _user + "&title=" + _title +
+ "&message=" + _message + "&device=" + _device + "&url=" + _url +
+ "&url_title=" + _url_title + "&priority=" + _priority +
+ "&retry=" + _retry + "&expire=" + _expire + "&sound=" + _sound;*/
+
+ (WiFiClientSecure *)client->print(
+ String("POST ") + path + " HTTP/1.1\r\n" + "host: " + host + "\r\n" +
+ "Content-length: " + String(post.length(), DEC) +
+ "\r\n"
+ "Content-Type: application/x-www-form-urlencoded\r\n" +
+ "Connection: close\r\n\r\n" + post);
+
+ while (client->connected()) {
+ String line = client->readStringUntil('\n');
+ if (line == "\r") {
+ Serial.println(F("Headers received"));
+ break;
+ }
+ }
+
+ /* String line = client->readString();
+ if (line.indexOf("\"status\":1") != -1 || line.indexOf("200 OK") != -1) {
+ Serial.println(F("Alert sent successfully!"));
+ } else {
+ Serial.print(F("Alert failure"));
+ Serial.println(line);
+ }*/
+ }
+}
+
+void Pushover::send() {
+ toggleConnection();
+ sendRequest();
+ toggleConnection();
+
+ if (client) {
+ delete client;
+ client = nullptr;
+ }
+}
+
+void Pushover::iterateAlways() {
+ if (lastMsgReceivedMs != 0 && millis() - lastMsgReceivedMs > 1000) {
+ lastMsgReceivedMs = 0;
+ send();
+ }
+}
+
+void Pushover::handleAction(int event, int action) {
+ (void)(event);
+ if (action == SEND_NOTIF_1) {
+ lastMsgReceivedMs = millis();
+ }
+}
+
+}; // namespace Control
+}; // namespace Supla
diff --git a/lib/SuplaDevice/src/supla/control/pushover.h b/lib/SuplaDevice/src/supla/control/pushover.h
new file mode 100644
index 00000000..bf026e83
--- /dev/null
+++ b/lib/SuplaDevice/src/supla/control/pushover.h
@@ -0,0 +1,77 @@
+/*
+ Copyright (C) AC SOFTWARE SP. Z O.O.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ 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 General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#ifndef _pushover_h
+#define _pushover_h
+
+#include
+#include
+
+#include "../action_handler.h"
+#include "../actions.h"
+#include "../channel_element.h"
+
+#define MAX_TOKEN_SIZE 32
+#define MAX_USER_SIZE 32
+#define MAX_TITLE_SIZE 32
+#define MAX_MESSAGE_SIZE 64
+
+namespace Supla {
+enum Pushover { SEND_NOTIF_1 };
+} // namespace Supla
+
+namespace Supla {
+namespace Control {
+
+class Pushover : public Element, public ActionHandler {
+ public:
+ Pushover(const char *token = nullptr,
+ const char *user = nullptr,
+ bool isSecured = true);
+ ~Pushover();
+
+ void setToken(const char *token);
+ void setUser(const char *user);
+ void setMessage(const char *message);
+ void setTitle(const char *title);
+
+ void iterateAlways();
+ void handleAction(int event, int action);
+
+ bool checkConnection();
+ void toggleConnection();
+ bool openConnection();
+ bool closeConnection();
+ void sendRequest();
+ void send();
+
+ protected:
+ WiFiClient *client = NULL;
+ const char *host = "api.pushover.net";
+ const char *path = "/1/messages.json";
+ unsigned long lastMsgReceivedMs;
+
+ bool _isSecured;
+ char _token[MAX_TOKEN_SIZE];
+ char _user[MAX_USER_SIZE];
+ char _title[MAX_TITLE_SIZE];
+ char _message[MAX_MESSAGE_SIZE];
+};
+
+}; // namespace Control
+}; // namespace Supla
+
+#endif
diff --git a/lib/SuplaDevice/src/supla/control/relay.cpp b/lib/SuplaDevice/src/supla/control/relay.cpp
index 081d1fe7..488e9b3c 100644
--- a/lib/SuplaDevice/src/supla/control/relay.cpp
+++ b/lib/SuplaDevice/src/supla/control/relay.cpp
@@ -57,7 +57,7 @@ void Relay::onInit() {
turnOff();
}
- pinMode(pin, OUTPUT); // pin mode is set after setting pin value in order to
+ Supla::Io::pinMode(channel.getChannelNumber(), pin, OUTPUT); // pin mode is set after setting pin value in order to
// avoid problems with LOW trigger relays
}
@@ -94,6 +94,9 @@ void Relay::turnOn(_supla_int_t duration) {
Supla::Io::digitalWrite(channel.getChannelNumber(), pin, pinOnValue());
channel.setNewValue(true);
+
+ // Schedule save in 5 s after state change
+ Supla::Storage::ScheduleSave(5000);
}
void Relay::turnOff(_supla_int_t duration) {
@@ -102,6 +105,9 @@ void Relay::turnOff(_supla_int_t duration) {
Supla::Io::digitalWrite(channel.getChannelNumber(), pin, pinOffValue());
channel.setNewValue(false);
+
+ // Schedule save in 5 s after state change
+ Supla::Storage::ScheduleSave(5000);
}
bool Relay::isOn() {
@@ -117,7 +123,7 @@ void Relay::toggle(_supla_int_t duration) {
}
}
-void Relay::runAction(int event, int action) {
+void Relay::handleAction(int event, int action) {
(void)(event);
switch (action) {
case TURN_ON: {
@@ -135,44 +141,40 @@ void Relay::runAction(int event, int action) {
}
}
-Channel *Relay::getChannel() {
- return &channel;
-}
-
void Relay::onSaveState() {
- if (keepTurnOnDurationMs) {
- Supla::Storage::WriteState((unsigned char *)&storedTurnOnDurationMs,
- sizeof(storedTurnOnDurationMs));
- }
+ Supla::Storage::WriteState((unsigned char *)&storedTurnOnDurationMs,
+ sizeof(storedTurnOnDurationMs));
+ bool enabled = false;
if (stateOnInit < 0) {
- bool enabled = isOn();
- Supla::Storage::WriteState((unsigned char *)&enabled, sizeof(enabled));
- }
+ enabled = isOn();
+ }
+ Supla::Storage::WriteState((unsigned char *)&enabled, sizeof(enabled));
}
void Relay::onLoadState() {
+ Supla::Storage::ReadState((unsigned char *)&storedTurnOnDurationMs,
+ sizeof(storedTurnOnDurationMs));
if (keepTurnOnDurationMs) {
- Supla::Storage::ReadState((unsigned char *)&storedTurnOnDurationMs,
- sizeof(storedTurnOnDurationMs));
Serial.print(F("Relay["));
Serial.print(channel.getChannelNumber());
Serial.print(F("]: restored durationMs: "));
Serial.println(storedTurnOnDurationMs);
+ } else {
+ storedTurnOnDurationMs = 0;
}
+ bool enabled = false;
+ Supla::Storage::ReadState((unsigned char *)&enabled, sizeof(enabled));
if (stateOnInit < 0) {
- bool enabled = false;
- if (Supla::Storage::ReadState((unsigned char *)&enabled, sizeof(enabled))) {
- Serial.print(F("Relay["));
- Serial.print(channel.getChannelNumber());
- Serial.print(F("]: restored relay state: "));
- if (enabled) {
- Serial.println(F("ON"));
- stateOnInit = STATE_ON_INIT_RESTORED_ON;
- } else {
- Serial.println(F("OFF"));
- stateOnInit = STATE_ON_INIT_RESTORED_OFF;
- }
+ Serial.print(F("Relay["));
+ Serial.print(channel.getChannelNumber());
+ Serial.print(F("]: restored relay state: "));
+ if (enabled) {
+ Serial.println(F("ON"));
+ stateOnInit = STATE_ON_INIT_RESTORED_ON;
+ } else {
+ Serial.println(F("OFF"));
+ stateOnInit = STATE_ON_INIT_RESTORED_OFF;
}
}
}
@@ -196,3 +198,7 @@ Relay &Relay::keepTurnOnDuration(bool keep) {
keepTurnOnDurationMs = keep;
return *this;
}
+
+unsigned _supla_int_t Relay::getStoredTurnOnDurationMs() {
+ return storedTurnOnDurationMs;
+}
diff --git a/lib/SuplaDevice/src/supla/control/relay.h b/lib/SuplaDevice/src/supla/control/relay.h
index f7a8813f..dcbf6f6e 100644
--- a/lib/SuplaDevice/src/supla/control/relay.h
+++ b/lib/SuplaDevice/src/supla/control/relay.h
@@ -25,11 +25,11 @@
#include
#include "../actions.h"
-#include "../channel.h"
-#include "../element.h"
+#include "../channel_element.h"
#include "../io.h"
#include "../storage/storage.h"
-#include "../triggerable.h"
+#include "../action_handler.h"
+#include "../local_action.h"
#define STATE_ON_INIT_RESTORED_OFF -3
#define STATE_ON_INIT_RESTORED_ON -2
@@ -39,7 +39,7 @@
namespace Supla {
namespace Control {
-class Relay : public Element, public Triggerable {
+class Relay : public ChannelElement, public ActionHandler {
public:
Relay(int pin,
bool highIsOn = true,
@@ -58,17 +58,16 @@ class Relay : public Element, public Triggerable {
virtual bool isOn();
virtual void toggle(_supla_int_t duration = 0);
- void runAction(int event, int action);
+ void handleAction(int event, int action);
void onInit();
void onLoadState();
void onSaveState();
void iterateAlways();
int handleNewValueFromServer(TSD_SuplaChannelNewValue *newValue);
+ unsigned _supla_int_t getStoredTurnOnDurationMs();
protected:
- Channel *getChannel();
- Channel channel;
int pin;
bool highIsOn;
diff --git a/lib/SuplaDevice/src/supla/control/rgb_base.cpp b/lib/SuplaDevice/src/supla/control/rgb_base.cpp
new file mode 100644
index 00000000..9869e5a1
--- /dev/null
+++ b/lib/SuplaDevice/src/supla/control/rgb_base.cpp
@@ -0,0 +1,61 @@
+/*
+ Copyright (C) AC SOFTWARE SP. Z O.O.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ 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 General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "rgb_base.h"
+#include "../storage/storage.h"
+
+Supla::Control::RGBBase::RGBBase() {
+ channel.setType(SUPLA_CHANNELTYPE_RGBLEDCONTROLLER);
+ channel.setDefault(SUPLA_CHANNELFNC_RGBLIGHTING);
+}
+
+void Supla::Control::RGBBase::setRGBW(int red,
+ int green,
+ int blue,
+ int colorBrightness,
+ int brightness,
+ bool toggle) {
+ Supla::Control::RGBWBase::setRGBW(
+ red, green, blue, colorBrightness, 0, toggle);
+}
+
+void Supla::Control::RGBBase::onSaveState() {
+ /*
+ uint8_t curRed; // 0 - 255
+ uint8_t curGreen; // 0 - 255
+ uint8_t curBlue; // 0 - 255
+ uint8_t curColorBrightness; // 0 - 100
+ uint8_t lastColorBrightness; // 0 - 100
+ */
+ Supla::Storage::WriteState((unsigned char *)&curRed, sizeof(curRed));
+ Supla::Storage::WriteState((unsigned char *)&curGreen, sizeof(curGreen));
+ Supla::Storage::WriteState((unsigned char *)&curBlue, sizeof(curBlue));
+ Supla::Storage::WriteState((unsigned char *)&curColorBrightness,
+ sizeof(curColorBrightness));
+ Supla::Storage::WriteState((unsigned char *)&lastColorBrightness,
+ sizeof(lastColorBrightness));
+}
+
+void Supla::Control::RGBBase::onLoadState() {
+ Supla::Storage::ReadState((unsigned char *)&curRed, sizeof(curRed));
+ Supla::Storage::ReadState((unsigned char *)&curGreen, sizeof(curGreen));
+ Supla::Storage::ReadState((unsigned char *)&curBlue, sizeof(curBlue));
+ Supla::Storage::ReadState((unsigned char *)&curColorBrightness,
+ sizeof(curColorBrightness));
+ Supla::Storage::ReadState((unsigned char *)&lastColorBrightness,
+ sizeof(lastColorBrightness));
+}
+
diff --git a/lib/SuplaDevice/src/supla/control/rgb_base.h b/lib/SuplaDevice/src/supla/control/rgb_base.h
index 7bcc3936..2bc534d9 100644
--- a/lib/SuplaDevice/src/supla/control/rgb_base.h
+++ b/lib/SuplaDevice/src/supla/control/rgb_base.h
@@ -23,11 +23,16 @@ namespace Supla {
namespace Control {
class RGBBase : public RGBWBase {
public:
- RGBBase() {
- channel.setType(SUPLA_CHANNELTYPE_RGBLEDCONTROLLER);
- channel.setDefault(SUPLA_CHANNELFNC_RGBLIGHTING);
- }
+ RGBBase();
+ void setRGBW(int red,
+ int green,
+ int blue,
+ int colorBrightness,
+ int brightness,
+ bool toggle = false);
+ void onLoadState();
+ void onSaveState();
};
}; // namespace Control
diff --git a/lib/SuplaDevice/src/supla/control/rgb_leds.cpp b/lib/SuplaDevice/src/supla/control/rgb_leds.cpp
new file mode 100644
index 00000000..1efc29dd
--- /dev/null
+++ b/lib/SuplaDevice/src/supla/control/rgb_leds.cpp
@@ -0,0 +1,88 @@
+/*
+Copyright (C) AC SOFTWARE SP. Z O.O.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+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 General Public License for more details.
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "rgb_leds.h"
+
+#ifdef ARDUINO_ARCH_ESP32
+extern int esp32PwmChannelCouner;
+#endif
+
+Supla::Control::RGBLeds::RGBLeds(int redPin, int greenPin, int bluePin)
+ : redPin(redPin), greenPin(greenPin), bluePin(bluePin) {
+}
+
+void Supla::Control::RGBLeds::setRGBWValueOnDevice(uint32_t red,
+ uint32_t green,
+ uint32_t blue,
+ uint32_t colorBrightness,
+ uint32_t brightness) {
+ uint32_t redAdj = red * colorBrightness / 1023;
+ uint32_t greenAdj = green * colorBrightness / 1023;
+ uint32_t blueAdj = blue * colorBrightness / 1023;
+
+#ifdef ARDUINO_ARCH_AVR
+ redAdj = map(redAdj, 0, 1023, 0, 255);
+ greenAdj = map(greenAdj, 0, 1023, 0, 255);
+ blueAdj = map(blueAdj, 0, 1023, 0, 255);
+#endif
+
+#ifdef ARDUINO_ARCH_ESP32
+ ledcWrite(redPin, redAdj);
+ ledcWrite(greenPin, greenAdj);
+ ledcWrite(bluePin, blueAdj);
+#else
+ analogWrite(redPin, redAdj);
+ analogWrite(greenPin, greenAdj);
+ analogWrite(bluePin, blueAdj);
+#endif
+}
+
+void Supla::Control::RGBLeds::onInit() {
+#ifdef ARDUINO_ARCH_ESP32
+ Serial.print(F("RGB: attaching pin "));
+ Serial.print(redPin);
+ Serial.print(F(" to PWM channel: "));
+ Serial.println(esp32PwmChannelCouner);
+
+ ledcSetup(esp32PwmChannelCouner, 12000, 10);
+ ledcAttachPin(redPin, esp32PwmChannelCouner);
+ // on ESP32 we write to PWM channels instead of pins, so we copy channel
+ // number as pin in order to reuse variable
+ redPin = esp32PwmChannelCouner;
+ esp32PwmChannelCouner++;
+
+ ledcSetup(esp32PwmChannelCouner, 12000, 10);
+ ledcAttachPin(greenPin, esp32PwmChannelCouner);
+ greenPin = esp32PwmChannelCouner;
+ esp32PwmChannelCouner++;
+
+ ledcSetup(esp32PwmChannelCouner, 12000, 10);
+ ledcAttachPin(bluePin, esp32PwmChannelCouner);
+ bluePin = esp32PwmChannelCouner;
+ esp32PwmChannelCouner++;
+
+#else
+ pinMode(redPin, OUTPUT);
+ pinMode(greenPin, OUTPUT);
+ pinMode(bluePin, OUTPUT);
+
+#ifdef ARDUINO_ARCH_ESP8266
+ analogWriteRange(1024);
+#endif
+#endif
+
+ Supla::Control::RGBBase::onInit();
+}
diff --git a/lib/SuplaDevice/src/supla/control/rgb_leds.h b/lib/SuplaDevice/src/supla/control/rgb_leds.h
new file mode 100644
index 00000000..bebddd3c
--- /dev/null
+++ b/lib/SuplaDevice/src/supla/control/rgb_leds.h
@@ -0,0 +1,45 @@
+/*
+Copyright (C) AC SOFTWARE SP. Z O.O.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+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 General Public License for more details.
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#ifndef __rgb_leds_h
+#define __rgb_leds_h
+
+#include "rgb_base.h"
+
+namespace Supla {
+namespace Control {
+class RGBLeds : public RGBBase {
+ public:
+ RGBLeds(int redPin, int greenPin, int bluePin);
+
+ void setRGBWValueOnDevice(uint32_t red,
+ uint32_t green,
+ uint32_t blue,
+ uint32_t colorBrightness,
+ uint32_t brightness);
+
+ void onInit();
+
+ protected:
+ int redPin;
+ int greenPin;
+ int bluePin;
+};
+
+}; // namespace Control
+}; // namespace Supla
+
+#endif
diff --git a/lib/SuplaDevice/src/supla/control/rgbw_base.cpp b/lib/SuplaDevice/src/supla/control/rgbw_base.cpp
index 461b69b8..228b5a44 100644
--- a/lib/SuplaDevice/src/supla/control/rgbw_base.cpp
+++ b/lib/SuplaDevice/src/supla/control/rgbw_base.cpp
@@ -17,13 +17,23 @@
#include
#include
+#include "../storage/storage.h"
#include "rgbw_base.h"
+#define RGBW_STATE_ON_INIT_RESTORE -1
+#define RGBW_STATE_ON_INIT_OFF 0
+#define RGBW_STATE_ON_INIT_ON 1
+
+#ifdef ARDUINO_ARCH_ESP32
+ int esp32PwmChannelCouner = 0;
+#endif
+
+
namespace Supla {
namespace Control {
RGBWBase::RGBWBase()
- : buttonStep(10),
+ : buttonStep(5),
curRed(0),
curGreen(255),
curBlue(0),
@@ -34,25 +44,40 @@ RGBWBase::RGBWBase()
defaultDimmedBrightness(20),
dimIterationDirection(false),
iterationDelayCounter(0),
- fadeEffect(1000),
- hwRed(0),
- hwGreen(255),
+ fadeEffect(500),
+ hwRed(-1),
+ hwGreen(0),
hwBlue(0),
hwColorBrightness(0),
hwBrightness(0),
- lastTick(0) {
+ lastTick(0),
+ lastMsgReceivedMs(0),
+ stateOnInit(RGBW_STATE_ON_INIT_RESTORE) {
channel.setType(SUPLA_CHANNELTYPE_DIMMERANDRGBLED);
channel.setDefault(SUPLA_CHANNELFNC_DIMMERANDRGBLIGHTING);
}
+void RGBWBase::setRGBW(int red,
+ int green,
+ int blue,
+ int colorBrightness,
+ int brightness,
+ bool toggle) {
+ if (toggle) {
+ lastMsgReceivedMs = 1;
+ } else {
+ lastMsgReceivedMs = millis();
+ }
-void RGBWBase::setRGBW(
- int red, int green, int blue, int colorBrightness, int brightness) {
// Store last non 0 brightness for turn on/toggle operations
- if (colorBrightness > 0) {
+ if (toggle && colorBrightness == 100 && curColorBrightness == 0) {
+ colorBrightness = lastColorBrightness;
+ } else if (colorBrightness > 0) {
lastColorBrightness = colorBrightness;
}
- if (brightness > 0) {
+ if (toggle && brightness == 100 && curBrightness == 0) {
+ brightness = lastBrightness;
+ } else if (brightness > 0) {
lastBrightness = brightness;
}
@@ -73,25 +98,28 @@ void RGBWBase::setRGBW(
curBrightness = brightness;
}
- // If fade effect is disabled, then set new values to device directly
- if (fadeEffect <= 0) {
- setRGBWValueOnDevice(
+ // Schedule save in 5 s after state change
+ Supla::Storage::ScheduleSave(5000);
+}
+
+void RGBWBase::iterateAlways() {
+ if (lastMsgReceivedMs != 0 && millis() - lastMsgReceivedMs > 400) {
+ lastMsgReceivedMs = 0;
+ // Send to Supla server new values
+ channel.setNewValue(
curRed, curGreen, curBlue, curColorBrightness, curBrightness);
}
-
- // Send to Supla server new values
- channel.setNewValue(
- curRed, curGreen, curBlue, curColorBrightness, curBrightness);
}
int RGBWBase::handleNewValueFromServer(TSD_SuplaChannelNewValue *newValue) {
+ uint8_t toggle = static_cast(newValue->value[5]);
uint8_t red = static_cast(newValue->value[4]);
uint8_t green = static_cast(newValue->value[3]);
uint8_t blue = static_cast(newValue->value[2]);
uint8_t colorBrightness = static_cast(newValue->value[1]);
uint8_t brightness = static_cast(newValue->value[0]);
- setRGBW(red, green, blue, colorBrightness, brightness);
+ setRGBW(red, green, blue, colorBrightness, brightness, toggle == 1);
return -1;
}
@@ -121,7 +149,7 @@ uint8_t RGBWBase::addWithLimit(int value, int addition, int limit) {
return value + addition;
}
-void RGBWBase::runAction(int event, int action) {
+void RGBWBase::handleAction(int event, int action) {
(void)(event);
switch (action) {
case TURN_ON: {
@@ -302,14 +330,10 @@ void RGBWBase::iterateDimmerRGBW(int rgbStep, int wStep) {
}
setRGBW(-1,
- -1,
- -1,
- addWithLimit(curColorBrightness, rgbStep, 100),
- addWithLimit(curBrightness, wStep, 100));
-}
-
-Channel *RGBWBase::getChannel() {
- return &channel;
+ -1,
+ -1,
+ addWithLimit(curColorBrightness, rgbStep, 100),
+ addWithLimit(curBrightness, wStep, 100));
}
void RGBWBase::setStep(int step) {
@@ -325,104 +349,166 @@ void RGBWBase::setFadeEffectTime(int timeMs) {
}
void RGBWBase::onTimer() {
- // exit it fade effect is disabled
- if (fadeEffect <= 0) {
- return;
- }
unsigned long timeDiff = millis() - lastTick;
lastTick = millis();
if (timeDiff > 0) {
- int divider = fadeEffect / timeDiff;
+ double divider = 1.0* fadeEffect / timeDiff;
if (divider <= 0) {
divider = 1;
}
- uint8_t rgbStep = 255 / divider;
- uint8_t brightnessStep = 100 / divider;
+ double step = 1023 / divider;
bool valueChanged = false;
- if (rgbStep < 1) {
- rgbStep = 1;
- }
- if (brightnessStep < 1) {
- brightnessStep = 1;
+ if (step < 1) {
+ step = 1;
}
- if (curRed > hwRed) {
+ int curRedAdj = map(curRed, 0, 255, 0, 1023);
+ int curGreenAdj = map(curGreen, 0, 255, 0 , 1023);
+ int curBlueAdj = map(curBlue, 0, 255, 0, 1023);
+ int curColorBrightnessAdj = map(curColorBrightness, 0, 100, 0, 1023);
+ int curBrightnessAdj = map(curBrightness, 0, 100, 0, 1023);
+
+ if (curRedAdj > hwRed) {
valueChanged = true;
- hwRed += rgbStep;
- if (hwRed > curRed) {
- hwRed = curRed;
+ hwRed += step;
+ if (hwRed > curRedAdj) {
+ hwRed = curRedAdj;
}
- } else if (curRed < hwRed) {
+ } else if (curRedAdj < hwRed) {
valueChanged = true;
- hwRed -= rgbStep;
- if (hwRed < curRed) {
- hwRed = curRed;
+ hwRed -= step;
+ if (hwRed < curRedAdj) {
+ hwRed = curRedAdj;
}
}
- if (curGreen > hwGreen) {
+ if (curGreenAdj > hwGreen) {
valueChanged = true;
- hwGreen += rgbStep;
- if (hwGreen > curGreen) {
- hwGreen = curGreen;
+ hwGreen += step;
+ if (hwGreen > curGreenAdj) {
+ hwGreen = curGreenAdj;
}
- } else if (curGreen < hwGreen) {
+ } else if (curGreenAdj < hwGreen) {
valueChanged = true;
- hwGreen -= rgbStep;
- if (hwGreen < curGreen) {
- hwGreen = curGreen;
+ hwGreen -= step;
+ if (hwGreen < curGreenAdj) {
+ hwGreen = curGreenAdj;
}
}
- if (curBlue > hwBlue) {
+ if (curBlueAdj > hwBlue) {
valueChanged = true;
- hwBlue += rgbStep;
- if (hwBlue > curBlue) {
- hwBlue = curBlue;
+ hwBlue += step;
+ if (hwBlue > curBlueAdj) {
+ hwBlue = curBlueAdj;
}
- } else if (curBlue < hwBlue) {
+ } else if (curBlueAdj < hwBlue) {
valueChanged = true;
- hwBlue -= rgbStep;
- if (hwBlue < curBlue) {
- hwBlue = curBlue;
+ hwBlue -= step;
+ if (hwBlue < curBlueAdj) {
+ hwBlue = curBlueAdj;
}
}
- if (curColorBrightness > hwColorBrightness) {
+ if (curColorBrightnessAdj > hwColorBrightness) {
valueChanged = true;
- hwColorBrightness += brightnessStep;
- if (hwColorBrightness > curColorBrightness) {
- hwColorBrightness = curColorBrightness;
+ hwColorBrightness += step;
+ if (hwColorBrightness > curColorBrightnessAdj) {
+ hwColorBrightness = curColorBrightnessAdj;
}
- } else if (curColorBrightness < hwColorBrightness) {
+ } else if (curColorBrightnessAdj < hwColorBrightness) {
valueChanged = true;
- hwColorBrightness -= brightnessStep;
- if (hwColorBrightness < curColorBrightness) {
- hwColorBrightness = curColorBrightness;
+ hwColorBrightness -= step;
+ if (hwColorBrightness < curColorBrightnessAdj) {
+ hwColorBrightness = curColorBrightnessAdj;
}
}
- if (curBrightness > hwBrightness) {
+ if (curBrightnessAdj > hwBrightness) {
valueChanged = true;
- hwBrightness += brightnessStep;
- if (hwBrightness > curBrightness) {
- hwBrightness = curBrightness;
+ hwBrightness += step;
+ if (hwBrightness > curBrightnessAdj) {
+ hwBrightness = curBrightnessAdj;
}
- } else if (curBrightness < hwBrightness) {
+ } else if (curBrightnessAdj < hwBrightness) {
valueChanged = true;
- hwBrightness -= brightnessStep;
- if (hwBrightness < curBrightness) {
- hwBrightness = curBrightness;
+ hwBrightness -= step;
+ if (hwBrightness < curBrightnessAdj) {
+ hwBrightness = curBrightnessAdj;
}
}
if (valueChanged) {
- setRGBWValueOnDevice(hwRed, hwGreen, hwBlue, hwColorBrightness, hwBrightness);
+ setRGBWValueOnDevice(
+ hwRed, hwGreen, hwBlue, hwColorBrightness, hwBrightness);
}
}
}
+void RGBWBase::onInit() {
+ if (stateOnInit == RGBW_STATE_ON_INIT_ON) {
+ curColorBrightness = 100;
+ curBrightness = 100;
+ } else if (stateOnInit == RGBW_STATE_ON_INIT_OFF) {
+ curColorBrightness = 0;
+ curBrightness = 0;
+ }
+
+ setRGBW(curRed, curGreen, curBlue, curColorBrightness, curBrightness);
+}
+
+void RGBWBase::onSaveState() {
+ /*
+ uint8_t curRed; // 0 - 255
+ uint8_t curGreen; // 0 - 255
+ uint8_t curBlue; // 0 - 255
+ uint8_t curColorBrightness; // 0 - 100
+ uint8_t curBrightness; // 0 - 100
+ uint8_t lastColorBrightness; // 0 - 100
+ uint8_t lastBrightness; // 0 - 100
+ */
+ Supla::Storage::WriteState((unsigned char *)&curRed, sizeof(curRed));
+ Supla::Storage::WriteState((unsigned char *)&curGreen, sizeof(curGreen));
+ Supla::Storage::WriteState((unsigned char *)&curBlue, sizeof(curBlue));
+ Supla::Storage::WriteState((unsigned char *)&curColorBrightness,
+ sizeof(curColorBrightness));
+ Supla::Storage::WriteState((unsigned char *)&curBrightness,
+ sizeof(curBrightness));
+ Supla::Storage::WriteState((unsigned char *)&lastColorBrightness,
+ sizeof(lastColorBrightness));
+ Supla::Storage::WriteState((unsigned char *)&lastBrightness, sizeof(lastBrightness));
+}
+
+void RGBWBase::onLoadState() {
+ Supla::Storage::ReadState((unsigned char *)&curRed, sizeof(curRed));
+ Supla::Storage::ReadState((unsigned char *)&curGreen, sizeof(curGreen));
+ Supla::Storage::ReadState((unsigned char *)&curBlue, sizeof(curBlue));
+ Supla::Storage::ReadState((unsigned char *)&curColorBrightness,
+ sizeof(curColorBrightness));
+ Supla::Storage::ReadState((unsigned char *)&curBrightness,
+ sizeof(curBrightness));
+ Supla::Storage::ReadState((unsigned char *)&lastColorBrightness,
+ sizeof(lastColorBrightness));
+ Supla::Storage::ReadState((unsigned char *)&lastBrightness, sizeof(lastBrightness));
+
+}
+
+RGBWBase &RGBWBase::setDefaultStateOn() {
+ stateOnInit = RGBW_STATE_ON_INIT_ON;
+ return *this;
+}
+
+RGBWBase &RGBWBase::setDefaultStateOff() {
+ stateOnInit = RGBW_STATE_ON_INIT_OFF;
+ return *this;
+}
+
+RGBWBase &RGBWBase::setDefaultStateRestore() {
+ stateOnInit = RGBW_STATE_ON_INIT_RESTORE;
+ return *this;
+}
+
}; // namespace Control
}; // namespace Supla
diff --git a/lib/SuplaDevice/src/supla/control/rgbw_base.h b/lib/SuplaDevice/src/supla/control/rgbw_base.h
index 452a66cf..c6d3ac41 100644
--- a/lib/SuplaDevice/src/supla/control/rgbw_base.h
+++ b/lib/SuplaDevice/src/supla/control/rgbw_base.h
@@ -20,48 +20,52 @@
#include
#include
-#include "../channel.h"
-#include "../element.h"
-#include "../triggerable.h"
+#include "../action_handler.h"
#include "../actions.h"
+#include "../channel_element.h"
namespace Supla {
namespace Control {
-class RGBWBase : public Element, public Triggerable {
+class RGBWBase : public ChannelElement, public ActionHandler {
public:
RGBWBase();
- virtual void setRGBWValueOnDevice(uint8_t red,
- uint8_t green,
- uint8_t blue,
- uint8_t colorBrightness,
- uint8_t brightness) = 0;
+ virtual void setRGBWValueOnDevice(uint32_t red,
+ uint32_t green,
+ uint32_t blue,
+ uint32_t colorBrightness,
+ uint32_t brightness) = 0;
- virtual void setRGBW(
- int red, int green, int blue, int colorBrightness, int brightness);
+ virtual void setRGBW(int red,
+ int green,
+ int blue,
+ int colorBrightness,
+ int brightness,
+ bool toggle = false);
int handleNewValueFromServer(TSD_SuplaChannelNewValue *newValue);
virtual void turnOn();
virtual void turnOff();
virtual void toggle();
- void runAction(int event, int action);
+ void handleAction(int event, int action);
void setStep(int step);
void setDefaultDimmedBrightness(int dimmedBrightness);
void setFadeEffectTime(int timeMs);
+
+ void onInit();
+ void iterateAlways();
void onTimer();
+ void onLoadState();
+ void onSaveState();
-void onInit() {
+ virtual RGBWBase &setDefaultStateOn();
+ virtual RGBWBase &setDefaultStateOff();
+ virtual RGBWBase &setDefaultStateRestore();
- // Send to Supla server new values
- channel.setNewValue(
- curRed, curGreen, curBlue, curColorBrightness, curBrightness);
-}
protected:
uint8_t addWithLimit(int value, int addition, int limit = 255);
- Channel *getChannel();
- void iterateDimmerRGBW(int rgbStep, int wStep);
+ virtual void iterateDimmerRGBW(int rgbStep, int wStep);
- Channel channel;
uint8_t buttonStep; // 10
uint8_t curRed; // 0 - 255
uint8_t curGreen; // 0 - 255
@@ -74,13 +78,14 @@ void onInit() {
bool dimIterationDirection;
int iterationDelayCounter;
int fadeEffect;
- int hwRed; // 0 - 255
- int hwGreen; // 0 - 255
- int hwBlue; // 0 - 255
- int hwColorBrightness; // 0 - 100
- int hwBrightness; // 0 - 100
+ int hwRed; // 0 - 255
+ int hwGreen; // 0 - 255
+ int hwBlue; // 0 - 255
+ int hwColorBrightness; // 0 - 100
+ int hwBrightness; // 0 - 100
unsigned long lastTick;
-
+ unsigned long lastMsgReceivedMs;
+ int8_t stateOnInit;
};
}; // namespace Control
diff --git a/lib/SuplaDevice/src/supla/control/rgbw_leds.cpp b/lib/SuplaDevice/src/supla/control/rgbw_leds.cpp
new file mode 100644
index 00000000..11f85f9d
--- /dev/null
+++ b/lib/SuplaDevice/src/supla/control/rgbw_leds.cpp
@@ -0,0 +1,105 @@
+/*
+Copyright (C) AC SOFTWARE SP. Z O.O.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+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 General Public License for more details.
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "rgbw_leds.h"
+#include
+
+#ifdef ARDUINO_ARCH_ESP32
+extern int esp32PwmChannelCouner;
+#endif
+
+Supla::Control::RGBWLeds::RGBWLeds(int redPin,
+ int greenPin,
+ int bluePin,
+ int brightnessPin)
+ : redPin(redPin),
+ greenPin(greenPin),
+ bluePin(bluePin),
+ brightnessPin(brightnessPin) {
+}
+
+void Supla::Control::RGBWLeds::setRGBWValueOnDevice(uint32_t red,
+ uint32_t green,
+ uint32_t blue,
+ uint32_t colorBrightness,
+ uint32_t brightness) {
+ uint32_t redAdj = red * colorBrightness / 1023;
+ uint32_t greenAdj = green * colorBrightness / 1023;
+ uint32_t blueAdj = blue * colorBrightness / 1023;
+ uint32_t brightnessAdj = brightness;
+
+#ifdef ARDUINO_ARCH_AVR
+ redAdj = map(redAdj, 0, 1023, 0, 255);
+ greenAdj = map(greenAdj, 0, 1023, 0, 255);
+ blueAdj = map(blueAdj, 0, 1023, 0, 255);
+ brightnessAdj = map(brightnessAdj, 0, 1023, 0, 255);
+#endif
+
+#ifdef ARDUINO_ARCH_ESP32
+ ledcWrite(redPin, redAdj);
+ ledcWrite(greenPin, greenAdj);
+ ledcWrite(bluePin, blueAdj);
+ ledcWrite(brightnessPin, brightnessAdj);
+#else
+ analogWrite(redPin, redAdj);
+ analogWrite(greenPin, greenAdj);
+ analogWrite(bluePin, blueAdj);
+ analogWrite(brightnessPin, brightnessAdj);
+#endif
+}
+
+void Supla::Control::RGBWLeds::onInit() {
+#ifdef ARDUINO_ARCH_ESP32
+ Serial.print(F("RGBW: attaching pin "));
+ Serial.print(redPin);
+ Serial.print(F(" to PWM channel: "));
+ Serial.println(esp32PwmChannelCouner);
+
+ ledcSetup(esp32PwmChannelCouner, 12000, 10);
+ ledcAttachPin(redPin, esp32PwmChannelCouner);
+ // on ESP32 we write to PWM channels instead of pins, so we copy channel
+ // number as pin in order to reuse variable
+ redPin = esp32PwmChannelCouner;
+ esp32PwmChannelCouner++;
+
+ ledcSetup(esp32PwmChannelCouner, 12000, 10);
+ ledcAttachPin(greenPin, esp32PwmChannelCouner);
+ greenPin = esp32PwmChannelCouner;
+ esp32PwmChannelCouner++;
+
+ ledcSetup(esp32PwmChannelCouner, 12000, 10);
+ ledcAttachPin(bluePin, esp32PwmChannelCouner);
+ bluePin = esp32PwmChannelCouner;
+ esp32PwmChannelCouner++;
+
+ ledcSetup(esp32PwmChannelCouner, 12000, 10);
+ ledcAttachPin(brightnessPin, esp32PwmChannelCouner);
+ brightnessPin = esp32PwmChannelCouner;
+ esp32PwmChannelCouner++;
+
+#else
+ pinMode(redPin, OUTPUT);
+ pinMode(greenPin, OUTPUT);
+ pinMode(bluePin, OUTPUT);
+ pinMode(brightnessPin, OUTPUT);
+
+ #ifdef ARDUINO_ARCH_ESP8266
+ analogWriteRange(1024);
+ #endif
+#endif
+
+ Supla::Control::RGBWBase::onInit();
+}
diff --git a/lib/SuplaDevice/src/supla/control/rgbw_leds.h b/lib/SuplaDevice/src/supla/control/rgbw_leds.h
new file mode 100644
index 00000000..b3133e99
--- /dev/null
+++ b/lib/SuplaDevice/src/supla/control/rgbw_leds.h
@@ -0,0 +1,49 @@
+/*
+Copyright (C) AC SOFTWARE SP. Z O.O.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+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 General Public License for more details.
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#ifndef __rgbw_leds_h
+#define __rgbw_leds_h
+
+#include "rgbw_base.h"
+
+namespace Supla {
+namespace Control {
+class RGBWLeds : public RGBWBase {
+ public:
+ RGBWLeds(int redPin,
+ int greenPin,
+ int bluePin,
+ int brightnessPin);
+
+ void setRGBWValueOnDevice(uint32_t red,
+ uint32_t green,
+ uint32_t blue,
+ uint32_t colorBrightness,
+ uint32_t brightness);
+
+ void onInit();
+
+ protected:
+ int redPin;
+ int greenPin;
+ int bluePin;
+ int brightnessPin;
+};
+
+}; // namespace Control
+}; // namespace Supla
+
+#endif
diff --git a/lib/SuplaDevice/src/supla/control/roller_shutter.cpp b/lib/SuplaDevice/src/supla/control/roller_shutter.cpp
index 630fb105..c249ef34 100644
--- a/lib/SuplaDevice/src/supla/control/roller_shutter.cpp
+++ b/lib/SuplaDevice/src/supla/control/roller_shutter.cpp
@@ -14,8 +14,9 @@
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
+#include
+
#include "roller_shutter.h"
-#include "supla/storage/storage.h"
namespace Supla {
namespace Control {
@@ -53,10 +54,12 @@ RollerShutter::RollerShutter(int pinUp, int pinDown, bool highIsOn)
}
void RollerShutter::onInit() {
- pinMode(pinUp, OUTPUT);
- pinMode(pinDown, OUTPUT);
- digitalWrite(pinUp, highIsOn ? LOW : HIGH);
- digitalWrite(pinDown, highIsOn ? LOW : HIGH);
+ Supla::Io::digitalWrite(
+ channel.getChannelNumber(), pinUp, highIsOn ? LOW : HIGH);
+ Supla::Io::digitalWrite(
+ channel.getChannelNumber(), pinDown, highIsOn ? LOW : HIGH);
+ Supla::Io::pinMode(channel.getChannelNumber(), pinUp, OUTPUT);
+ Supla::Io::pinMode(channel.getChannelNumber(), pinDown, OUTPUT);
}
/*
@@ -124,7 +127,7 @@ void RollerShutter::setOpenCloseTime(uint32_t newClosingTimeMs,
}
}
-void RollerShutter::runAction(int event, int action) {
+void RollerShutter::handleAction(int event, int action) {
(void)(event);
switch (action) {
case CLOSE_OR_STOP: {
@@ -268,22 +271,28 @@ void RollerShutter::stopMovement() {
switchOffRelays();
currentDirection = STOP_DIR;
doNothingTime = millis();
+ // Schedule save in 5 s after stop movement of roller shutter
+ Supla::Storage::ScheduleSave(5000);
}
void RollerShutter::relayDownOn() {
- digitalWrite(pinDown, highIsOn ? HIGH : LOW);
+ Supla::Io::digitalWrite(
+ channel.getChannelNumber(), pinDown, highIsOn ? HIGH : LOW);
}
void RollerShutter::relayUpOn() {
- digitalWrite(pinUp, highIsOn ? HIGH : LOW);
+ Supla::Io::digitalWrite(
+ channel.getChannelNumber(), pinUp, highIsOn ? HIGH : LOW);
}
void RollerShutter::relayDownOff() {
- digitalWrite(pinDown, highIsOn ? LOW : HIGH);
+ Supla::Io::digitalWrite(
+ channel.getChannelNumber(), pinDown, highIsOn ? LOW : HIGH);
}
void RollerShutter::relayUpOff() {
- digitalWrite(pinUp, highIsOn ? LOW : HIGH);
+ Supla::Io::digitalWrite(
+ channel.getChannelNumber(), pinUp, highIsOn ? LOW : HIGH);
}
void RollerShutter::startClosing() {
@@ -383,7 +392,7 @@ void RollerShutter::onTimer() {
// just handle roller movement/status
if (currentDirection == UP_DIR && currentPosition > 0) {
int movementDistance = lastPositionBeforeMovement;
- int timeRequired = (1.0 * openingTimeMs * movementDistance / 100.0);
+ uint32_t timeRequired = (1.0 * openingTimeMs * movementDistance / 100.0);
float fractionOfMovemendDone =
(1.0 * (millis() - lastMovementStartTime) / timeRequired);
if (fractionOfMovemendDone > 1) {
@@ -396,7 +405,7 @@ void RollerShutter::onTimer() {
}
} else if (currentDirection == DOWN_DIR && currentPosition < 100) {
int movementDistance = 100 - lastPositionBeforeMovement;
- int timeRequired = (1.0 * closingTimeMs * movementDistance / 100.0);
+ uint32_t timeRequired = (1.0 * closingTimeMs * movementDistance / 100.0);
float fractionOfMovemendDone =
(1.0 * (millis() - lastMovementStartTime) / timeRequired);
if (fractionOfMovemendDone > 1) {
@@ -453,14 +462,10 @@ void RollerShutter::onTimer() {
}
// if (newCurrentPosition != currentPosition) {
// currentPosition = newCurrentPosition;
- channel.setNewValue(
- currentPosition); // value set on channel will be send to server
- // during iterateConnected() execution
- // }
-}
-
-Channel *RollerShutter::getChannel() {
- return &channel;
+ channel.setNewValue(static_cast<_supla_int_t>(
+ currentPosition)); // value set on channel will be send to server
+ // during iterateConnected() execution
+ // }
}
void RollerShutter::configComfortUpValue(uint8_t position) {
diff --git a/lib/SuplaDevice/src/supla/control/roller_shutter.h b/lib/SuplaDevice/src/supla/control/roller_shutter.h
index 26e46f81..d9a55233 100644
--- a/lib/SuplaDevice/src/supla/control/roller_shutter.h
+++ b/lib/SuplaDevice/src/supla/control/roller_shutter.h
@@ -20,9 +20,8 @@
#include
#include "../io.h"
-#include "../channel.h"
-#include "../element.h"
-#include "../triggerable.h"
+#include "../channel_element.h"
+#include "../action_handler.h"
#include "../actions.h"
#define UNKNOWN_POSITION -1
@@ -35,12 +34,12 @@ namespace Control {
enum Directions { STOP_DIR, DOWN_DIR, UP_DIR };
-class RollerShutter : public Element, public Triggerable {
+class RollerShutter : public ChannelElement, public ActionHandler {
public:
RollerShutter(int pinUp, int pinDown, bool highIsOn = true);
int handleNewValueFromServer(TSD_SuplaChannelNewValue *newValue);
- void runAction(int event, int action);
+ void handleAction(int event, int action);
void close(); // Sets target position to 100%
void open(); // Sets target position to 0%
@@ -74,10 +73,6 @@ class RollerShutter : public Element, public Triggerable {
bool lastDirectionWasClose();
bool inMove();
- Channel *getChannel();
-
- Channel channel;
-
uint32_t closingTimeMs;
uint32_t openingTimeMs;
bool calibrate; // set to true when new closing/opening time is given - calibration is done to sync roller shutter position
diff --git a/lib/SuplaDevice/src/supla/control/sequence_button.cpp b/lib/SuplaDevice/src/supla/control/sequence_button.cpp
new file mode 100644
index 00000000..f86dd4c8
--- /dev/null
+++ b/lib/SuplaDevice/src/supla/control/sequence_button.cpp
@@ -0,0 +1,137 @@
+/*
+ Copyright (C) AC SOFTWARE SP. Z O.O.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ 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 General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "sequence_button.h"
+#include
+
+Supla::Control::SequenceButton::SequenceButton(int pin, bool pullUp, bool invertLogic)
+ : SimpleButton(pin, pullUp, invertLogic),
+ lastStateChangeMs(0),
+ longestSequenceTimeDeltaWithMargin(800),
+ clickCounter(0),
+ sequenceDetectecion(true),
+ currentSequence(),
+ matchSequence(),
+ margin(0.3) {
+}
+
+void Supla::Control::SequenceButton::onTimer() {
+ unsigned int timeDelta = millis() - lastStateChangeMs;
+ bool stateChanged = false;
+ int stateResult = state.update();
+ if (stateResult == TO_PRESSED) {
+ stateChanged = true;
+ runAction(ON_PRESS);
+ runAction(ON_CHANGE);
+ } else if (stateResult == TO_RELEASED) {
+ stateChanged = true;
+ runAction(ON_RELEASE);
+ runAction(ON_CHANGE);
+ }
+
+ if (stateChanged) {
+ lastStateChangeMs = millis();
+ if (clickCounter > 0 && clickCounter < SEQUENCE_MAX_SIZE + 1) {
+ currentSequence.data[clickCounter - 1] = timeDelta;
+ }
+ if (clickCounter == 0) {
+ memset(currentSequence.data, 0, sizeof(uint16_t [SEQUENCE_MAX_SIZE]));
+ }
+ clickCounter++;
+ }
+
+ if (!stateChanged) {
+ if (clickCounter > 0 && stateResult == RELEASED) {
+ if (timeDelta > longestSequenceTimeDeltaWithMargin) {
+ Serial.print(F("Recorded sequence: "));
+ if (clickCounter > 31) {
+ clickCounter = 31;
+ }
+ for (int i = 0; i < clickCounter - 1; i++) {
+ Serial.print(currentSequence.data[i]);
+ Serial.print(F(", "));
+ }
+ Serial.println();
+
+ int matchSequenceSize = 0;
+ for (; matchSequenceSize < 30; matchSequenceSize++) {
+ if (matchSequence.data[matchSequenceSize] == 0) {
+ break;
+ }
+ }
+ if (matchSequenceSize != clickCounter - 1) {
+ Serial.println(F("Sequence size doesn't match"));
+ runAction(ON_SEQUENCE_DOESNT_MATCH);
+ } else {
+ bool match = true;
+ for (int i = 0; i < clickCounter - 1; i++) {
+ unsigned int marginValue = calculateMargin(matchSequence.data[i]);
+ if (!(matchSequence.data[i] - marginValue <= currentSequence.data[i] && matchSequence.data[i] + marginValue >= currentSequence.data[i])) {
+ match = false;
+ break;
+ }
+ }
+ if (match) {
+ Serial.println(F("Sequence match"));
+ runAction(ON_SEQUENCE_MATCH);
+ } else {
+ Serial.println(F("Sequence doesn't match"));
+ runAction(ON_SEQUENCE_DOESNT_MATCH);
+ }
+
+ }
+ clickCounter = 0;
+ }
+ }
+ }
+
+}
+
+unsigned int Supla::Control::SequenceButton::calculateMargin(unsigned int value) {
+ unsigned int result = margin*value;
+ if (result < 20) {
+ result = 20;
+ }
+ return result;
+}
+
+void Supla::Control::SequenceButton::setMargin(float newMargin) {
+ margin = newMargin;
+ if (margin < 0) {
+ margin = 0;
+ } else if (margin > 1) {
+ margin = 1;
+ }
+}
+
+void Supla::Control::SequenceButton::setSequence(uint16_t *sequence) {
+ uint16_t maxValue = 0;
+ for (int i = 0; i < SEQUENCE_MAX_SIZE; i++) {
+ matchSequence.data[i] = sequence[i];
+ if (sequence[i] > maxValue) {
+ maxValue = sequence[i];
+ }
+ }
+ maxValue *= 1.5;
+ if (maxValue < 500) {
+ maxValue = 500;
+ }
+ longestSequenceTimeDeltaWithMargin = maxValue;
+}
+
+void Supla::Control::SequenceButton::getLastRecordedSequence(uint16_t *sequence) {
+ memcpy(sequence, currentSequence.data, sizeof(uint16_t [SEQUENCE_MAX_SIZE]));
+}
diff --git a/lib/SuplaDevice/src/supla/control/sequence_button.h b/lib/SuplaDevice/src/supla/control/sequence_button.h
new file mode 100644
index 00000000..d4e12b12
--- /dev/null
+++ b/lib/SuplaDevice/src/supla/control/sequence_button.h
@@ -0,0 +1,58 @@
+/*
+ Copyright (C) AC SOFTWARE SP. Z O.O.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ 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 General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#ifndef _sequence_button_h
+#define _sequence_button_h
+
+#include "button.h"
+
+namespace Supla {
+namespace Control {
+
+#define SEQUENCE_MAX_SIZE 30
+
+struct ClickSequence {
+ uint16_t data[SEQUENCE_MAX_SIZE];
+};
+
+class SequenceButton : public SimpleButton {
+ public:
+ SequenceButton(int pin, bool pullUp = false, bool invertLogic = false);
+
+ void onTimer();
+
+ void setSequence(uint16_t *sequence);
+ void setMargin(float);
+ void getLastRecordedSequence(uint16_t *sequence);
+
+ protected:
+ unsigned long lastStateChangeMs;
+ uint16_t longestSequenceTimeDeltaWithMargin;
+ uint8_t clickCounter;
+ bool sequenceDetectecion;
+
+ ClickSequence currentSequence;
+ ClickSequence matchSequence;
+
+ float margin;
+ unsigned int calculateMargin(unsigned int);
+
+};
+
+}; // namespace Control
+}; // namespace Supla
+
+#endif
diff --git a/lib/SuplaDevice/src/supla/control/simple_button.cpp b/lib/SuplaDevice/src/supla/control/simple_button.cpp
new file mode 100644
index 00000000..2bbbd387
--- /dev/null
+++ b/lib/SuplaDevice/src/supla/control/simple_button.cpp
@@ -0,0 +1,109 @@
+/*
+ Copyright (C) AC SOFTWARE SP. Z O.O.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ 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 General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "button.h"
+#include "../io.h"
+
+Supla::Control::ButtonState::ButtonState(int pin, bool pullUp, bool invertLogic)
+ : debounceTimeMs(0),
+ filterTimeMs(0),
+ debounceDelayMs(50),
+ swNoiseFilterDelayMs(20),
+ pin(pin),
+ newStatusCandidate(LOW),
+ prevState(LOW),
+ pullUp(pullUp),
+ invertLogic(invertLogic) {
+}
+
+int Supla::Control::ButtonState::update() {
+ unsigned long curMillis = millis();
+ if (debounceDelayMs == 0 || curMillis - debounceTimeMs > debounceDelayMs) {
+ int currentState = Supla::Io::digitalRead(pin);
+ if (currentState != prevState) {
+ // If status is changed, then make sure that it will be kept at
+ // least swNoiseFilterDelayMs ms to avoid noise
+ if (swNoiseFilterDelayMs != 0 && currentState != newStatusCandidate) {
+ newStatusCandidate = currentState;
+ filterTimeMs = curMillis;
+ } else if (curMillis - filterTimeMs > swNoiseFilterDelayMs) {
+ // If new status is kept at least swNoiseFilterDelayMs ms, then apply
+ // change of status
+ debounceTimeMs = curMillis;
+ prevState = currentState;
+ if (currentState == valueOnPress()) {
+ return TO_PRESSED;
+ } else {
+ return TO_RELEASED;
+ }
+ }
+ } else {
+ // If current status is the same as prevState, then reset
+ // new status candidate
+ newStatusCandidate = prevState;
+ }
+ }
+ if (prevState == valueOnPress()) {
+ return PRESSED;
+ } else {
+ return RELEASED;
+ }
+}
+
+Supla::Control::SimpleButton::SimpleButton(int pin, bool pullUp, bool invertLogic)
+ : state(pin, pullUp, invertLogic) {
+}
+
+void Supla::Control::SimpleButton::onTimer() {
+ int stateResult = state.update();
+ if (stateResult == TO_PRESSED) {
+ runAction(ON_PRESS);
+ runAction(ON_CHANGE);
+ } else if (stateResult == TO_RELEASED) {
+ runAction(ON_RELEASE);
+ runAction(ON_CHANGE);
+ }
+}
+
+void Supla::Control::SimpleButton::onInit() {
+ state.init();
+}
+
+void Supla::Control::ButtonState::init() {
+ Supla::Io::pinMode(pin, pullUp ? INPUT_PULLUP : INPUT);
+ prevState = Supla::Io::digitalRead(pin);
+ newStatusCandidate = prevState;
+}
+
+int Supla::Control::ButtonState::valueOnPress() {
+ return invertLogic ? LOW : HIGH;
+}
+
+void Supla::Control::SimpleButton::setSwNoiseFilterDelay(unsigned int newDelayMs) {
+ state.setSwNoiseFilterDelay(newDelayMs);
+}
+void Supla::Control::ButtonState::setSwNoiseFilterDelay(unsigned int newDelayMs) {
+ swNoiseFilterDelayMs = newDelayMs;
+}
+
+void Supla::Control::SimpleButton::setDebounceDelay(unsigned int newDelayMs) {
+ state.setDebounceDelay(newDelayMs);
+}
+
+void Supla::Control::ButtonState::setDebounceDelay(unsigned int newDelayMs) {
+ debounceDelayMs = newDelayMs;
+}
+
diff --git a/lib/SuplaDevice/src/supla/control/simple_button.h b/lib/SuplaDevice/src/supla/control/simple_button.h
new file mode 100644
index 00000000..8b66fb7e
--- /dev/null
+++ b/lib/SuplaDevice/src/supla/control/simple_button.h
@@ -0,0 +1,71 @@
+/*
+ Copyright (C) AC SOFTWARE SP. Z O.O.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ 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 General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#ifndef _simple_button_h
+#define _simple_button_h
+
+#include
+
+#include "../element.h"
+#include "../events.h"
+#include "../local_action.h"
+
+namespace Supla {
+namespace Control {
+
+enum StateResults {PRESSED, RELEASED, TO_PRESSED, TO_RELEASED};
+
+class ButtonState {
+ public:
+ ButtonState(int pin, bool pullUp, bool invertLogic);
+ int update();
+ void init();
+
+ void setSwNoiseFilterDelay(unsigned int newDelayMs);
+ void setDebounceDelay(unsigned int newDelayMs);
+
+ protected:
+ int valueOnPress();
+
+ unsigned long debounceTimeMs;
+ unsigned long filterTimeMs;
+ unsigned int debounceDelayMs;
+ unsigned int swNoiseFilterDelayMs;
+ int pin;
+ int8_t newStatusCandidate;
+ int8_t prevState;
+ bool pullUp;
+ bool invertLogic;
+};
+
+class SimpleButton : public Element,
+ public LocalAction {
+ public:
+ SimpleButton(int pin, bool pullUp = false, bool invertLogic = false);
+
+ void onTimer();
+ void onInit();
+ void setSwNoiseFilterDelay(unsigned int newDelayMs);
+ void setDebounceDelay(unsigned int newDelayMs);
+
+ protected:
+ ButtonState state;
+};
+
+}; // namespace Control
+}; // namespace Supla
+
+#endif
diff --git a/lib/SuplaDevice/src/supla/control/virtual_relay.cpp b/lib/SuplaDevice/src/supla/control/virtual_relay.cpp
new file mode 100644
index 00000000..9cfc3ea8
--- /dev/null
+++ b/lib/SuplaDevice/src/supla/control/virtual_relay.cpp
@@ -0,0 +1,57 @@
+/*
+ Copyright (C) AC SOFTWARE SP. Z O.O.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ 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 General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "virtual_relay.h"
+
+Supla::Control::VirtualRelay::VirtualRelay(_supla_int_t functions)
+ : Relay(-1, true, functions), state(false) {
+}
+
+void Supla::Control::VirtualRelay::onInit() {
+ if (stateOnInit == STATE_ON_INIT_ON ||
+ stateOnInit == STATE_ON_INIT_RESTORED_ON) {
+ turnOn();
+ } else {
+ turnOff();
+ }
+}
+
+void Supla::Control::VirtualRelay::turnOn(_supla_int_t duration) {
+ durationMs = duration;
+ durationTimestamp = millis();
+ if (keepTurnOnDurationMs) {
+ durationMs = storedTurnOnDurationMs;
+ }
+ state = true;
+
+ channel.setNewValue(state);
+ // Schedule save in 5 s after state change
+ Supla::Storage::ScheduleSave(5000);
+}
+
+void Supla::Control::VirtualRelay::turnOff(_supla_int_t duration) {
+ durationMs = duration;
+ durationTimestamp = millis();
+ state = false;
+
+ channel.setNewValue(state);
+ // Schedule save in 5 s after state change
+ Supla::Storage::ScheduleSave(5000);
+}
+
+bool Supla::Control::VirtualRelay::isOn() {
+ return state;
+}
diff --git a/lib/SuplaDevice/src/supla/control/virtual_relay.h b/lib/SuplaDevice/src/supla/control/virtual_relay.h
index 1a54c51f..ee51affd 100644
--- a/lib/SuplaDevice/src/supla/control/virtual_relay.h
+++ b/lib/SuplaDevice/src/supla/control/virtual_relay.h
@@ -24,41 +24,12 @@ namespace Control {
class VirtualRelay : public Relay {
public:
VirtualRelay(_supla_int_t functions =
- (0xFF ^ SUPLA_BIT_FUNC_CONTROLLINGTHEROLLERSHUTTER))
- : Relay(-1, true, functions), state(false) {
- }
+ (0xFF ^ SUPLA_BIT_FUNC_CONTROLLINGTHEROLLERSHUTTER));
- void onInit() {
- if (stateOnInit == STATE_ON_INIT_ON ||
- stateOnInit == STATE_ON_INIT_RESTORED_ON) {
- turnOn();
- } else {
- turnOff();
- }
- }
-
- void turnOn(_supla_int_t duration = 0) {
- durationMs = duration;
- durationTimestamp = millis();
- if (keepTurnOnDurationMs) {
- durationMs = storedTurnOnDurationMs;
- }
- state = true;
-
- channel.setNewValue(state);
- }
-
- virtual void turnOff(_supla_int_t duration = 0) {
- durationMs = duration;
- durationTimestamp = millis();
- state = false;
-
- channel.setNewValue(state);
- }
-
- virtual bool isOn() {
- return state;
- }
+ void onInit();
+ void turnOn(_supla_int_t duration = 0);
+ void turnOff(_supla_int_t duration = 0);
+ bool isOn();
protected:
bool state;
diff --git a/lib/SuplaDevice/src/supla/crc16.h b/lib/SuplaDevice/src/supla/crc16.h
new file mode 100644
index 00000000..5713f7bd
--- /dev/null
+++ b/lib/SuplaDevice/src/supla/crc16.h
@@ -0,0 +1,14 @@
+
+uint16_t crc16_update(uint16_t crc, uint8_t a) {
+ int i;
+
+ crc ^= a;
+ for (i = 0; i < 8; ++i) {
+ if (crc & 1)
+ crc = (crc >> 1) ^ 0xA001;
+ else
+ crc = (crc >> 1);
+ }
+
+ return crc;
+}
diff --git a/lib/SuplaDevice/src/supla/element.cpp b/lib/SuplaDevice/src/supla/element.cpp
index b7f1b22c..70fc8a11 100644
--- a/lib/SuplaDevice/src/supla/element.cpp
+++ b/lib/SuplaDevice/src/supla/element.cpp
@@ -29,6 +29,20 @@ Element::Element() : nextPtr(nullptr) {
}
}
+Element::~Element() {
+ if (begin() == this) {
+ firstPtr = next();
+ return;
+ }
+
+ auto ptr = begin();
+ while (ptr->next() != this) {
+ ptr = ptr->next();
+ }
+
+ ptr->nextPtr = ptr->next()->next();
+}
+
Element *Element::begin() {
return firstPtr;
}
@@ -95,6 +109,10 @@ Channel *Element::getChannel() {
return nullptr;
}
+Channel *Element::getSecondaryChannel() {
+ return nullptr;
+}
+
void Element::handleGetChannelState(TDSC_ChannelState &channelState) {
(void)(channelState);
return;
diff --git a/lib/SuplaDevice/src/supla/element.h b/lib/SuplaDevice/src/supla/element.h
index f2ee9fdc..34e48cc5 100644
--- a/lib/SuplaDevice/src/supla/element.h
+++ b/lib/SuplaDevice/src/supla/element.h
@@ -27,6 +27,7 @@ namespace Supla {
class Element {
public:
Element();
+ virtual ~Element();
static Element *begin();
static Element *last();
static Element *getElementByChannelNumber(int channelNumber);
@@ -76,11 +77,12 @@ class Element {
virtual int handleCalcfgFromServer(TSD_DeviceCalCfgRequest *request);
int getChannelNumber();
+ virtual Channel *getChannel();
+ virtual Channel *getSecondaryChannel();
Element &disableChannelState();
protected:
- virtual Channel *getChannel();
static Element *firstPtr;
Element *nextPtr;
};
diff --git a/lib/SuplaDevice/src/supla/events.h b/lib/SuplaDevice/src/supla/events.h
index c72c122f..a65b0a4c 100644
--- a/lib/SuplaDevice/src/supla/events.h
+++ b/lib/SuplaDevice/src/supla/events.h
@@ -34,7 +34,13 @@ enum Event {
ON_CLICK_7,
ON_CLICK_8,
ON_CLICK_9,
- ON_CLICK_10
+ ON_CLICK_10,
+ ON_CRAZY_CLICKER, // triggered on >= 10 clicks
+ ON_SEQUENCE_MATCH, // triggered by SequenceButton
+ ON_SEQUENCE_DOESNT_MATCH, // triggered by SequenceButton
+ ON_TURN_ON,
+ ON_TURN_OFF,
+ ON_SECONDARY_CHANNEL_CHANGE
};
};
diff --git a/lib/SuplaDevice/src/supla/io.cpp b/lib/SuplaDevice/src/supla/io.cpp
index 59cccc81..6132709c 100644
--- a/lib/SuplaDevice/src/supla/io.cpp
+++ b/lib/SuplaDevice/src/supla/io.cpp
@@ -19,6 +19,26 @@
#include
namespace Supla {
+void Io::pinMode(uint8_t pin, uint8_t mode) {
+ return pinMode(-1, pin, mode);
+}
+
+int Io::digitalRead(uint8_t pin) {
+ return digitalRead(-1, pin);
+}
+
+void Io::digitalWrite(uint8_t pin, uint8_t val) {
+ digitalWrite(-1, pin, val);
+}
+
+void Io::pinMode(int channelNumber, uint8_t pin, uint8_t mode) {
+ if (ioInstance) {
+ ioInstance->customPinMode(channelNumber, pin, mode);
+ } else {
+ ::pinMode(pin, mode);
+ }
+}
+
int Io::digitalRead(int channelNumber, uint8_t pin) {
if (ioInstance) {
return ioInstance->customDigitalRead(channelNumber, pin);
@@ -46,6 +66,10 @@ Io::Io() {
ioInstance = this;
}
+Io::~Io() {
+ ioInstance = nullptr;
+}
+
int Io::customDigitalRead(int channelNumber, uint8_t pin) {
(void)(channelNumber);
return ::digitalRead(pin);
@@ -56,4 +80,9 @@ void Io::customDigitalWrite(int channelNumber, uint8_t pin, uint8_t val) {
::digitalWrite(pin, val);
}
+void Io::customPinMode(int channelNumber, uint8_t pin, uint8_t mode) {
+ (void)(channelNumber);
+ ::pinMode(pin, mode);
+}
+
}; // namespace Supla
diff --git a/lib/SuplaDevice/src/supla/io.h b/lib/SuplaDevice/src/supla/io.h
index 461f8b6a..918ceb0b 100644
--- a/lib/SuplaDevice/src/supla/io.h
+++ b/lib/SuplaDevice/src/supla/io.h
@@ -30,12 +30,18 @@ namespace Supla {
// changed.
class Io {
public:
+ static void pinMode(uint8_t pin, uint8_t mode);
+ static int digitalRead(uint8_t pin);
+ static void digitalWrite(uint8_t pin, uint8_t val);
+ static void pinMode(int channelNumber, uint8_t pin, uint8_t mode);
static int digitalRead(int channelNumber, uint8_t pin);
static void digitalWrite(int channelNumber, uint8_t pin, uint8_t val);
static Io *ioInstance;
Io();
+ virtual ~Io();
+ virtual void customPinMode(int channelNumber, uint8_t pin, uint8_t mode);
virtual int customDigitalRead(int channelNumber, uint8_t pin);
virtual void customDigitalWrite(int channelNumber, uint8_t pin, uint8_t val);
};
diff --git a/lib/SuplaDevice/src/supla/local_action.cpp b/lib/SuplaDevice/src/supla/local_action.cpp
index cc4c08eb..478c4bd9 100644
--- a/lib/SuplaDevice/src/supla/local_action.cpp
+++ b/lib/SuplaDevice/src/supla/local_action.cpp
@@ -18,29 +18,91 @@
namespace Supla {
-LocalAction::LocalAction() : registeredClientsCount(0) {
-}
+class ActionHandlerClient;
+
+class ActionHandlerClient {
+ public:
+ ActionHandlerClient()
+ : trigger(nullptr),
+ client(nullptr),
+ next(nullptr),
+ onEvent(0),
+ action(0) {
+ if (begin == nullptr) {
+ begin = this;
+ } else {
+ auto ptr = begin;
+ while (ptr->next) {
+ ptr = ptr->next;
+ }
+ ptr->next = this;
+ }
+ }
+
+ ~ActionHandlerClient() {
+ if (begin == this) {
+ begin = next;
+ return;
+ }
+
+ auto ptr = begin;
+ while (ptr->next != this) {
+ ptr = ptr->next;
+ }
+
+ ptr->next = ptr->next->next;
+ }
+
+ LocalAction *trigger;
+ ActionHandler *client;
+ ActionHandlerClient *next;
+ uint8_t onEvent;
+ uint8_t action;
+ static ActionHandlerClient *begin;
+};
+
+ActionHandlerClient *ActionHandlerClient::begin = nullptr;
-void LocalAction::addAction(int action, Triggerable &client, int event) {
- if (registeredClientsCount < MAX_TRIGGERABLE_CLIENTS) {
- clients[registeredClientsCount].client = &client;
- clients[registeredClientsCount].onEvent = event;
- clients[registeredClientsCount].action = action;
- registeredClientsCount++;
+LocalAction::~LocalAction() {
+ auto ptr = ActionHandlerClient::begin;
+ while (ptr) {
+ if (ptr->trigger == this) {
+ auto tbdptr = ptr;
+ ptr = ptr->next;
+ if (tbdptr->client->deleteClient()) {
+ delete tbdptr->client;
+ }
+ delete tbdptr;
+ } else {
+ ptr = ptr->next;
+ }
}
}
-void LocalAction::addAction(int action, Triggerable *client, int event) {
+void LocalAction::addAction(int action, ActionHandler &client, int event) {
+ auto ptr = new ActionHandlerClient;
+ ptr->trigger = this;
+ ptr->client = &client;
+ ptr->onEvent = event;
+ ptr->action = action;
+}
+
+void LocalAction::addAction(int action, ActionHandler *client, int event) {
addAction(action, *client, event);
}
void LocalAction::runAction(int event) {
- for (int i = 0; i < registeredClientsCount; i++) {
- if (clients[i].onEvent == event) {
- clients[i].client->runAction(event, clients[i].action);
+ auto ptr = ActionHandlerClient::begin;
+ while (ptr) {
+ if (ptr->trigger == this && ptr->onEvent == event) {
+ ptr->client->handleAction(event, ptr->action);
}
+ ptr = ptr->next;
}
}
-}; // namespace Supla
+ActionHandlerClient *LocalAction::getClientListPtr() {
+ return ActionHandlerClient::begin;
+}
+}; // namespace Supla
diff --git a/lib/SuplaDevice/src/supla/local_action.h b/lib/SuplaDevice/src/supla/local_action.h
index 4ec39711..33a91adf 100644
--- a/lib/SuplaDevice/src/supla/local_action.h
+++ b/lib/SuplaDevice/src/supla/local_action.h
@@ -18,31 +18,21 @@
#define _local_action_h
#include
-#include "triggerable.h"
-
-#define MAX_TRIGGERABLE_CLIENTS 10
+#include "action_handler.h"
namespace Supla {
-class TriggerableClient {
- public:
- Triggerable *client;
- uint8_t onEvent;
- uint8_t action;
-};
+class ActionHandlerClient;
class LocalAction {
public:
- LocalAction();
-
- virtual void addAction(int action, Triggerable &client, int event);
- virtual void addAction(int action, Triggerable *client, int event);
+ virtual ~LocalAction();
+ virtual void addAction(int action, ActionHandler &client, int event);
+ virtual void addAction(int action, ActionHandler *client, int event);
virtual void runAction(int event);
- protected:
- TriggerableClient clients[MAX_TRIGGERABLE_CLIENTS];
- uint8_t registeredClientsCount;
+ static ActionHandlerClient *getClientListPtr();
};
}; // namespace Supla
diff --git a/lib/SuplaDevice/src/supla/network/esp32_wifi.h b/lib/SuplaDevice/src/supla/network/esp32_wifi.h
index fa3915d1..e45ee3cc 100644
--- a/lib/SuplaDevice/src/supla/network/esp32_wifi.h
+++ b/lib/SuplaDevice/src/supla/network/esp32_wifi.h
@@ -14,120 +14,15 @@
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-#ifndef esp_wifi_h__
-#define esp_wifi_h__
+// DEPRECATED: please use esp_wifi.h instead
-#include