├── CHANGELOG.md ├── FHEM └── 73_AutoShuttersControl.pm ├── LICENSE ├── README.md ├── controls_AutoShuttersControl.txt ├── hooks ├── commit-msg ├── post-commit └── pre-commit └── lib └── FHEM └── Automation ├── ShuttersControl.pm └── ShuttersControl ├── Dev.pm ├── Dev ├── Attr.pm └── Readings.pm ├── EventProcessingFunctions.pm ├── Helper.pm ├── Rainprotection.pm ├── Roommate.pm ├── Shading.pm ├── Shutters.pm ├── Shutters ├── Attr.pm └── Readings.pm ├── Window.pm └── Window ├── Attr.pm └── Readings.pm /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FHEM::AutoShuttersControl 2 | 3 | ## Used branching model 4 | * Master branch: Production version (copy of [fhem/fhem-mirror/blob/master/fhem/FHEM/73_AutoShuttersControl.pm](https://github.com/fhem/fhem-mirror/blob/master/fhem/FHEM/73_AutoShuttersControl.pm)) 5 | * Devel branch: Latest development version 6 | 7 | ## Community support 8 | The FHEM Forum is available [here](https://forum.fhem.de/) for general support. 9 | In case you have a specific question about this module, it is recommended to find the right sub-forum. 10 | It can either be found from the module info card using the FHEM Installer (e.g. using command `search `) or it can be determined from the [MAINTAINER.txt](https://github.com/fhem/fhem-mirror/blob/master/fhem/MAINTAINER.txt) file. 11 | 12 | ## Bug reports and feature requests 13 | Identified bugs and feature requests are tracked using [Github Issues](https://github.com/fhem/AutoShuttersControl/issues). 14 | 15 | ## Pull requests / How to participate into development 16 | You are invited to send pull requests to the devel branch whenever you think you can contribute with some useful improvements to the module. The module maintainer will review you code and decide whether it is going to be part of the module in a future release. 17 | -------------------------------------------------------------------------------- /controls_AutoShuttersControl.txt: -------------------------------------------------------------------------------- 1 | UPD 2025-02-05_07:57:04 117935 FHEM/73_AutoShuttersControl.pm 2 | UPD 2025-01-25_11:47:02 76570 lib/FHEM/Automation/ShuttersControl.pm 3 | UPD 2024-10-12_09:12:30 2691 lib/FHEM/Automation/ShuttersControl/Dev.pm 4 | UPD 2024-10-12_09:12:30 2675 lib/FHEM/Automation/ShuttersControl/Roommate.pm 5 | UPD 2024-10-12_09:12:30 31828 lib/FHEM/Automation/ShuttersControl/Shutters.pm 6 | UPD 2024-10-12_09:12:30 25541 lib/FHEM/Automation/ShuttersControl/Shading.pm 7 | UPD 2024-10-12_09:12:30 112297 lib/FHEM/Automation/ShuttersControl/EventProcessingFunctions.pm 8 | UPD 2024-10-12_09:12:30 40681 lib/FHEM/Automation/ShuttersControl/Helper.pm 9 | UPD 2024-10-12_09:12:30 2209 lib/FHEM/Automation/ShuttersControl/Window.pm 10 | UPD 2024-10-12_09:12:30 11857 lib/FHEM/Automation/ShuttersControl/Dev/Attr.pm 11 | UPD 2024-10-12_09:12:30 7265 lib/FHEM/Automation/ShuttersControl/Dev/Readings.pm 12 | UPD 2024-10-12_09:12:30 52751 lib/FHEM/Automation/ShuttersControl/Shutters/Attr.pm 13 | UPD 2024-10-12_09:12:30 2799 lib/FHEM/Automation/ShuttersControl/Shutters/Readings.pm 14 | UPD 2024-10-12_09:12:30 3887 lib/FHEM/Automation/ShuttersControl/Window/Attr.pm 15 | UPD 2024-10-12_09:12:30 2200 lib/FHEM/Automation/ShuttersControl/Window/Readings.pm 16 | UPD 2024-10-12_09:12:30 7394 lib/FHEM/Automation/ShuttersControl/Rainprotection.pm 17 | -------------------------------------------------------------------------------- /hooks/commit-msg: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # An example hook script to check the commit log message. 4 | # Called by "git commit" with one argument, the name of the file 5 | # that has the commit message. The hook should exit with non-zero 6 | # status after issuing an appropriate message if it wants to stop the 7 | # commit. The hook is allowed to edit the commit message file. 8 | # 9 | # To enable this hook, rename this file to "commit-msg". 10 | 11 | # Uncomment the below to add a Signed-off-by line to the message. 12 | # Doing this in a hook is a bad idea in general, but the prepare-commit-msg 13 | # hook is more suited to it. 14 | # 15 | # SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') 16 | # grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" 17 | 18 | # This example catches duplicate Signed-off-by lines. 19 | 20 | commit_msg=$(cat "${1:?Missing commit message file}") 21 | 22 | test "" = "$(grep '^Signed-off-by: ' "$1" | 23 | sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || { 24 | echo >&2 Duplicate Signed-off-by lines. 25 | exit 1 26 | } 27 | 28 | if ! echo "$commit_msg" | grep -Eq "^(build|chore|ci|docs|feat|feat!|fix|perf|refactor|revert|style|test)(\(.+\))?: .*$" ; then 29 | 30 | echo "Invalid commit message" 31 | 32 | exit 1 33 | 34 | fi 35 | 36 | echo "Commit message is valid!" 37 | -------------------------------------------------------------------------------- /hooks/post-commit: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -eu 3 | 4 | # destination of the final changelog file 5 | OUTPUT_FILE=CHANGELOG.md 6 | 7 | # generate the changelog 8 | git --no-pager log --no-merges --format="### %s%d%n>%aD%n%n>Author: %aN (%aE)%n%n>Commiter: %cN (%cE)%n%n%b%n%N%n" > $OUTPUT_FILE 9 | 10 | # prevent recursion! 11 | # since a 'commit --amend' will trigger the post-commit script again 12 | # we have to check if the changelog file has changed or not 13 | res=$(git status --porcelain | grep -c ".\$OUTPUT_FILE$") 14 | if [ "$res" -gt 0 ]; then 15 | git add $OUTPUT_FILE 16 | git commit --amend 17 | echo "Populated Changelog in $OUTPUT_FILE" 18 | fi 19 | -------------------------------------------------------------------------------- /hooks/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | use File::Basename; 4 | use POSIX qw(strftime); 5 | use strict; 6 | 7 | my @filenames = ( 'FHEM/73_AutoShuttersControl.pm', 8 | 'lib/FHEM/Automation/ShuttersControl.pm', 9 | 'lib/FHEM/Automation/ShuttersControl/Dev.pm', 10 | 'lib/FHEM/Automation/ShuttersControl/Roommate.pm', 11 | 'lib/FHEM/Automation/ShuttersControl/Shutters.pm', 12 | 'lib/FHEM/Automation/ShuttersControl/Shading.pm', 13 | 'lib/FHEM/Automation/ShuttersControl/EventProcessingFunctions.pm', 14 | 'lib/FHEM/Automation/ShuttersControl/Helper.pm', 15 | 'lib/FHEM/Automation/ShuttersControl/Window.pm', 16 | 'lib/FHEM/Automation/ShuttersControl/Dev/Attr.pm', 17 | 'lib/FHEM/Automation/ShuttersControl/Dev/Readings.pm', 18 | 'lib/FHEM/Automation/ShuttersControl/Shutters/Attr.pm', 19 | 'lib/FHEM/Automation/ShuttersControl/Shutters/Readings.pm', 20 | 'lib/FHEM/Automation/ShuttersControl/Window/Attr.pm', 21 | 'lib/FHEM/Automation/ShuttersControl/Window/Readings.pm', 22 | 'lib/FHEM/Automation/ShuttersControl/Rainprotection.pm' 23 | ); 24 | 25 | my $controlsfile = 'controls_AutoShuttersControl.txt'; 26 | 27 | open(FH, ">$controlsfile") || return("Can't open $controlsfile: $!"); 28 | 29 | for my $filename (@filenames) { 30 | my @statOutput = stat($filename); 31 | 32 | if (scalar @statOutput != 13) { 33 | printf 'error: stat has unexpected return value for ' . $filename . "\n"; 34 | next; 35 | } 36 | 37 | my $mtime = $statOutput[9]; 38 | my $date = POSIX::strftime("%Y-%m-%d", localtime($mtime)); 39 | my $time = POSIX::strftime("%H:%M:%S", localtime($mtime)); 40 | my $filetime = $date."_".$time; 41 | 42 | my $filesize = $statOutput[7]; 43 | 44 | printf FH 'UPD ' . $filetime . ' ' . $filesize . ' ' .$filename . "\n"; 45 | } 46 | 47 | close(FH); 48 | 49 | system("git add $controlsfile"); 50 | 51 | print 'Create controls File succesfully' . "\n"; 52 | 53 | exit 0; 54 | -------------------------------------------------------------------------------- /lib/FHEM/Automation/ShuttersControl/Dev.pm: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # Developed with VSCodium and richterger perl plugin 4 | # 5 | # (c) 2018-2025 Copyright: Marko Oldenburg (fhemdevelopment at cooltux dot net) 6 | # All rights reserved 7 | # 8 | # Special thanks goes to: 9 | # - Bernd (Cluni) this module is based on the logic of his script "Rollladensteuerung für HM/ROLLO inkl. Abschattung und Komfortfunktionen in Perl" (https://forum.fhem.de/index.php/topic,73964.0.html) 10 | # - Beta-User for many tests, many suggestions and good discussions 11 | # - pc1246 write english commandref 12 | # - FunkOdyssey commandref style 13 | # - sledge fix many typo in commandref 14 | # - many User that use with modul and report bugs 15 | # - Christoph (christoph.kaiser.in) Patch that expand RegEx for Window Events 16 | # - Julian (Loredo) expand Residents Events for new Residents functions 17 | # - Christoph (Christoph Morrison) for fix Commandref, many suggestions and good discussions 18 | # 19 | # 20 | # This script is free software; you can redistribute it and/or modify 21 | # it under the terms of the GNU General Public License as published by 22 | # the Free Software Foundation; either version 2 of the License,or 23 | # any later version. 24 | # 25 | # The GNU General Public License can be found at 26 | # http://www.gnu.org/copyleft/gpl.html. 27 | # A copy is found in the textfile GPL.txt and important notices to the license 28 | # from the author is found in LICENSE.txt distributed with these scripts. 29 | # 30 | # This script is distributed in the hope that it will be useful, 31 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 32 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 33 | # GNU General Public License for more details. 34 | # 35 | # 36 | # $Id$ 37 | # 38 | ############################################################################### 39 | 40 | ## Klasse ASC_Dev plus Subklassen ASC_Attr_Dev und ASC_Readings_Dev## 41 | package FHEM::Automation::ShuttersControl::Dev; 42 | 43 | use FHEM::Automation::ShuttersControl::Dev::Readings; 44 | use FHEM::Automation::ShuttersControl::Dev::Attr; 45 | 46 | use base 47 | qw(FHEM::Automation::ShuttersControl::Dev::Readings FHEM::Automation::ShuttersControl::Dev::Attr); 48 | 49 | use strict; 50 | use warnings; 51 | use utf8; 52 | 53 | sub new { 54 | my $class = shift; 55 | 56 | my $self = { name => undef, }; 57 | 58 | bless $self, $class; 59 | return $self; 60 | } 61 | 62 | sub setName { 63 | my $self = shift; 64 | my $name = shift; 65 | 66 | $self->{name} = $name if ( defined($name) ); 67 | return $self->{name}; 68 | } 69 | 70 | sub setDefault { 71 | my $self = shift; 72 | my $defaultarg = shift; 73 | 74 | $self->{defaultarg} = $defaultarg if ( defined($defaultarg) ); 75 | return $self->{defaultarg}; 76 | } 77 | 78 | sub getName { 79 | my $self = shift; 80 | return $self->{name}; 81 | } 82 | 83 | 1; 84 | -------------------------------------------------------------------------------- /lib/FHEM/Automation/ShuttersControl/Dev/Attr.pm: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # Developed with VSCodium and richterger perl plugin 4 | # 5 | # (c) 2018-2025 Copyright: Marko Oldenburg (fhemdevelopment at cooltux dot net) 6 | # All rights reserved 7 | # 8 | # Special thanks goes to: 9 | # - Bernd (Cluni) this module is based on the logic of his script "Rollladensteuerung für HM/ROLLO inkl. Abschattung und Komfortfunktionen in Perl" (https://forum.fhem.de/index.php/topic,73964.0.html) 10 | # - Beta-User for many tests, many suggestions and good discussions 11 | # - pc1246 write english commandref 12 | # - FunkOdyssey commandref style 13 | # - sledge fix many typo in commandref 14 | # - many User that use with modul and report bugs 15 | # - Christoph (christoph.kaiser.in) Patch that expand RegEx for Window Events 16 | # - Julian (Loredo) expand Residents Events for new Residents functions 17 | # - Christoph (Christoph Morrison) for fix Commandref, many suggestions and good discussions 18 | # 19 | # 20 | # This script is free software; you can redistribute it and/or modify 21 | # it under the terms of the GNU General Public License as published by 22 | # the Free Software Foundation; either version 2 of the License,or 23 | # any later version. 24 | # 25 | # The GNU General Public License can be found at 26 | # http://www.gnu.org/copyleft/gpl.html. 27 | # A copy is found in the textfile GPL.txt and important notices to the license 28 | # from the author is found in LICENSE.txt distributed with these scripts. 29 | # 30 | # This script is distributed in the hope that it will be useful, 31 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 32 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 33 | # GNU General Public License for more details. 34 | # 35 | # 36 | # $Id$ 37 | # 38 | ############################################################################### 39 | 40 | ## Subklasse Attr ## 41 | package FHEM::Automation::ShuttersControl::Dev::Attr; 42 | 43 | use strict; 44 | use warnings; 45 | use utf8; 46 | 47 | sub getShuttersOffset { 48 | my $self = shift; 49 | 50 | my $name = $self->{name}; 51 | 52 | return ::AttrVal( $name, 'ASC_shuttersDriveDelay', -1 ); 53 | } 54 | 55 | sub getBrightnessMinVal { 56 | my $self = shift; 57 | 58 | my $name = $self->{name}; 59 | 60 | return $self->{ASC_brightness}->{triggermin} 61 | if ( exists( $self->{ASC_brightness}->{LASTGETTIME} ) 62 | && ( ::gettimeofday() - $self->{ASC_brightness}->{LASTGETTIME} ) < 2 ); 63 | $FHEM::Automation::ShuttersControl::ascDev->getBrightnessMaxVal; 64 | 65 | return $self->{ASC_brightness}->{triggermin}; 66 | } 67 | 68 | sub getBrightnessMaxVal { 69 | my $self = shift; 70 | 71 | my $name = $self->{name}; 72 | 73 | return $self->{ASC_brightness}->{triggermax} 74 | if ( exists( $self->{ASC_brightness}->{LASTGETTIME} ) 75 | && ( ::gettimeofday() - $self->{ASC_brightness}->{LASTGETTIME} ) < 2 ); 76 | $self->{ASC_brightness}->{LASTGETTIME} = int( ::gettimeofday() ); 77 | 78 | my ( $triggermax, $triggermin ) = 79 | FHEM::Automation::ShuttersControl::Helper::GetAttrValues( $name, 80 | 'ASC_brightnessDriveUpDown', '800:500' ); 81 | 82 | ## erwartetes Ergebnis 83 | # max:min 84 | 85 | $self->{ASC_brightness}->{triggermin} = $triggermin; 86 | $self->{ASC_brightness}->{triggermax} = $triggermax; 87 | 88 | return $self->{ASC_brightness}->{triggermax}; 89 | } 90 | 91 | sub _getTwilightDevice { 92 | my $self = shift; 93 | 94 | my $name = $self->{name}; 95 | 96 | return ::AttrVal( $name, 'ASC_twilightDevice', 'none' ); 97 | } 98 | 99 | sub getAutoAstroModeEvening { 100 | my $self = shift; 101 | 102 | my $name = $self->{name}; 103 | 104 | return ::AttrVal( $name, 'ASC_autoAstroModeEvening', 'REAL' ); 105 | } 106 | 107 | sub getAutoAstroModeEveningHorizon { 108 | my $self = shift; 109 | 110 | my $name = $self->{name}; 111 | 112 | return ::AttrVal( $name, 'ASC_autoAstroModeEveningHorizon', 0 ); 113 | } 114 | 115 | sub getAutoAstroModeMorning { 116 | my $self = shift; 117 | 118 | my $name = $self->{name}; 119 | 120 | return ::AttrVal( $name, 'ASC_autoAstroModeMorning', 'REAL' ); 121 | } 122 | 123 | sub getAutoAstroModeMorningHorizon { 124 | my $self = shift; 125 | 126 | my $name = $self->{name}; 127 | 128 | return ::AttrVal( $name, 'ASC_autoAstroModeMorningHorizon', 0 ); 129 | } 130 | 131 | sub getAutoShuttersControlMorning { 132 | my $self = shift; 133 | 134 | my $name = $self->{name}; 135 | 136 | return ::AttrVal( $name, 'ASC_autoShuttersControlMorning', 'on' ); 137 | } 138 | 139 | sub getAutoShuttersControlEvening { 140 | my $self = shift; 141 | 142 | my $name = $self->{name}; 143 | 144 | return ::AttrVal( $name, 'ASC_autoShuttersControlEvening', 'on' ); 145 | } 146 | 147 | sub getAutoShuttersControlComfort { 148 | my $self = shift; 149 | 150 | my $name = $self->{name}; 151 | 152 | return ::AttrVal( $name, 'ASC_autoShuttersControlComfort', 'off' ); 153 | } 154 | 155 | sub getFreezeTemp { 156 | my $self = shift; 157 | 158 | my $name = $self->{name}; 159 | 160 | return ::AttrVal( $name, 'ASC_freezeTemp', 3 ); 161 | } 162 | 163 | sub getSlatDriveCmdInverse { 164 | my $self = shift; 165 | 166 | my $name = $self->{name}; 167 | 168 | return ::AttrVal( $name, 'ASC_slatDriveCmdInverse', 0 ); 169 | } 170 | 171 | sub _getTempSensor { 172 | my $self = shift; 173 | 174 | my $name = $self->{name}; 175 | 176 | return $self->{ASC_tempSensor}->{device} 177 | if ( exists( $self->{ASC_tempSensor}->{LASTGETTIME} ) 178 | && ( ::gettimeofday() - $self->{ASC_tempSensor}->{LASTGETTIME} ) < 2 ); 179 | $self->{ASC_tempSensor}->{LASTGETTIME} = int( ::gettimeofday() ); 180 | my ( $device, $reading ) = 181 | FHEM::Automation::ShuttersControl::Helper::GetAttrValues( $name, 182 | 'ASC_tempSensor', 'none' ); 183 | 184 | ## erwartetes Ergebnis 185 | # DEVICE:READING 186 | $self->{ASC_tempSensor}->{device} = $device; 187 | $self->{ASC_tempSensor}->{reading} = 188 | ( $reading ne 'none' ? $reading : 'temperature' ); 189 | 190 | return $self->{ASC_tempSensor}->{device}; 191 | } 192 | 193 | sub getTempSensorReading { 194 | my $self = shift; 195 | 196 | my $name = $self->{name}; 197 | 198 | return $self->{ASC_tempSensor}->{reading} 199 | if ( exists( $self->{ASC_tempSensor}->{LASTGETTIME} ) 200 | && ( ::gettimeofday() - $self->{ASC_tempSensor}->{LASTGETTIME} ) < 2 ); 201 | $FHEM::Automation::ShuttersControl::ascDev->_getTempSensor; 202 | return $self->{ASC_tempSensor}->{reading}; 203 | } 204 | 205 | sub _getResidentsDev { 206 | my $self = shift; 207 | 208 | my $name = $self->{name}; 209 | 210 | return $self->{ASC_residentsDev}->{device} 211 | if ( exists( $self->{ASC_residentsDev}->{LASTGETTIME} ) 212 | && ( ::gettimeofday() - $self->{ASC_residentsDev}->{LASTGETTIME} ) < 213 | 2 ); 214 | $self->{ASC_residentsDev}->{LASTGETTIME} = int( ::gettimeofday() ); 215 | my ( $device, $reading ) = 216 | FHEM::Automation::ShuttersControl::Helper::GetAttrValues( $name, 217 | 'ASC_residentsDev', 'none' ); 218 | 219 | $self->{ASC_residentsDev}->{device} = $device; 220 | $self->{ASC_residentsDev}->{reading} = 221 | ( $reading ne 'none' ? $reading : 'state' ); 222 | 223 | return $self->{ASC_residentsDev}->{device}; 224 | } 225 | 226 | sub getResidentsReading { 227 | my $self = shift; 228 | 229 | my $name = $self->{name}; 230 | 231 | return $self->{ASC_residentsDev}->{reading} 232 | if ( exists( $self->{ASC_residentsDev}->{LASTGETTIME} ) 233 | && ( ::gettimeofday() - $self->{ASC_residentsDev}->{LASTGETTIME} ) < 234 | 2 ); 235 | $FHEM::Automation::ShuttersControl::ascDev->_getResidentsDev; 236 | return $self->{ASC_residentsDev}->{reading}; 237 | } 238 | 239 | sub _getRainSensor { 240 | my $self = shift; 241 | 242 | my $name = $self->{name}; 243 | 244 | return $self->{ASC_rainSensor}->{device} 245 | if ( exists( $self->{ASC_rainSensor}->{LASTGETTIME} ) 246 | && ( ::gettimeofday() - $self->{ASC_rainSensor}->{LASTGETTIME} ) < 2 ); 247 | $self->{ASC_rainSensor}->{LASTGETTIME} = int( ::gettimeofday() ); 248 | my ( $device, $reading, $max, $hyst, $pos, $wait ) = 249 | FHEM::Automation::ShuttersControl::Helper::GetAttrValues( $name, 250 | 'ASC_rainSensor', 'none' ); 251 | 252 | ## erwartetes Ergebnis 253 | # DEVICE:READING MAX:HYST 254 | 255 | return $device if ( $device eq 'none' ); 256 | $self->{ASC_rainSensor}->{device} = $device; 257 | $self->{ASC_rainSensor}->{reading} = 258 | ( $reading ne 'none' ? $reading : 'rain' ); 259 | $self->{ASC_rainSensor}->{triggermax} = ( 260 | ( $max ne 'none' && $max =~ m{\A(-?\d+(\.\d+)?)\z}xms ) 261 | ? $max 262 | : 1000 263 | ); 264 | 265 | $self->{ASC_rainSensor}->{triggerhyst} = ( 266 | $hyst ne 'none' 267 | ? $self->{ASC_rainSensor}->{triggermax} - $hyst 268 | : ( $self->{ASC_rainSensor}->{triggermax} * 0 ) 269 | ); 270 | 271 | $self->{ASC_rainSensor}->{shuttersClosedPos} = ( 272 | $pos ne 'none' 273 | ? $pos 274 | : $FHEM::Automation::ShuttersControl::shutters->getClosedPos 275 | ); 276 | $self->{ASC_rainSensor}->{waitingTime} = 277 | ( $wait ne 'none' ? $wait : 0 ); 278 | 279 | return $self->{ASC_rainSensor}->{device}; 280 | } 281 | 282 | sub getRainSensorReading { 283 | my $self = shift; 284 | 285 | my $name = $self->{name}; 286 | 287 | return $self->{ASC_rainSensor}->{reading} 288 | if ( exists( $self->{ASC_rainSensor}->{LASTGETTIME} ) 289 | && ( ::gettimeofday() - $self->{ASC_rainSensor}->{LASTGETTIME} ) < 2 ); 290 | $FHEM::Automation::ShuttersControl::ascDev->_getRainSensor; 291 | return $self->{ASC_rainSensor}->{reading}; 292 | } 293 | 294 | sub getRainTriggerMax { 295 | my $self = shift; 296 | 297 | my $name = $self->{name}; 298 | 299 | return $self->{ASC_rainSensor}->{triggermax} 300 | if ( exists( $self->{ASC_rainSensor}->{LASTGETTIME} ) 301 | && ( ::gettimeofday() - $self->{ASC_rainSensor}->{LASTGETTIME} ) < 2 ); 302 | $FHEM::Automation::ShuttersControl::ascDev->_getRainSensor; 303 | return $self->{ASC_rainSensor}->{triggermax}; 304 | } 305 | 306 | sub getRainTriggerMin { 307 | my $self = shift; 308 | 309 | my $name = $self->{name}; 310 | 311 | return $self->{ASC_rainSensor}->{triggerhyst} 312 | if ( exists( $self->{ASC_rainSensor}->{LASTGETTIME} ) 313 | && ( ::gettimeofday() - $self->{ASC_rainSensor}->{LASTGETTIME} ) < 2 ); 314 | $FHEM::Automation::ShuttersControl::ascDev->_getRainSensor; 315 | return $self->{ASC_rainSensor}->{triggerhyst}; 316 | } 317 | 318 | sub getRainSensorShuttersClosedPos { 319 | my $self = shift; 320 | 321 | my $name = $self->{name}; 322 | 323 | return $self->{ASC_rainSensor}->{shuttersClosedPos} 324 | if ( exists( $self->{ASC_rainSensor}->{LASTGETTIME} ) 325 | && ( ::gettimeofday() - $self->{ASC_rainSensor}->{LASTGETTIME} ) < 2 ); 326 | $FHEM::Automation::ShuttersControl::ascDev->_getRainSensor; 327 | return $self->{ASC_rainSensor}->{shuttersClosedPos}; 328 | } 329 | 330 | sub getRainWaitingTime { 331 | my $self = shift; 332 | 333 | my $name = $self->{name}; 334 | 335 | return $self->{ASC_rainSensor}->{waitingTime} 336 | if ( exists( $self->{ASC_rainSensor}->{LASTGETTIME} ) 337 | && ( ::gettimeofday() - $self->{ASC_rainSensor}->{LASTGETTIME} ) < 2 ); 338 | $FHEM::Automation::ShuttersControl::ascDev->_getRainSensor; 339 | return $self->{ASC_rainSensor}->{waitingTime}; 340 | } 341 | 342 | sub _getWindSensor { 343 | my $self = shift; 344 | 345 | my $name = $self->{name}; 346 | 347 | return $self->{ASC_windSensor}->{device} 348 | if ( exists( $self->{ASC_windSensor}->{LASTGETTIME} ) 349 | && ( ::gettimeofday() - $self->{ASC_windSensor}->{LASTGETTIME} ) < 2 ); 350 | $self->{ASC_windSensor}->{LASTGETTIME} = int( ::gettimeofday() ); 351 | my ( $device, $reading ) = 352 | FHEM::Automation::ShuttersControl::Helper::GetAttrValues( $name, 353 | 'ASC_windSensor', 'none' ); 354 | 355 | return $device if ( $device eq 'none' ); 356 | $self->{ASC_windSensor}->{device} = $device; 357 | $self->{ASC_windSensor}->{reading} = 358 | ( $reading ne 'none' ? $reading : 'wind' ); 359 | 360 | return $self->{ASC_windSensor}->{device}; 361 | } 362 | 363 | sub getWindSensorReading { 364 | my $self = shift; 365 | 366 | my $name = $self->{name}; 367 | 368 | return $self->{ASC_windSensor}->{reading} 369 | if ( exists( $self->{ASC_windSensor}->{LASTGETTIME} ) 370 | && ( ::gettimeofday() - $self->{ASC_windSensor}->{LASTGETTIME} ) < 2 ); 371 | $FHEM::Automation::ShuttersControl::ascDev->_getWindSensor; 372 | return ( 373 | defined( $self->{ASC_windSensor}->{reading} ) 374 | ? $self->{ASC_windSensor}->{reading} 375 | : 'wind' 376 | ); 377 | } 378 | 379 | sub getBlockAscDrivesAfterManual { 380 | my $self = shift; 381 | 382 | my $name = $self->{name}; 383 | 384 | return ::AttrVal( $name, 'ASC_blockAscDrivesAfterManual', 0 ); 385 | } 386 | 387 | sub getAdvStartDate { 388 | my $self = shift; 389 | 390 | my $name = $self->{name}; 391 | 392 | return ::AttrVal( $name, 'ASC_advStartDate', 'FirstAdvent' ); 393 | } 394 | 395 | sub getAdvEndDate { 396 | my $self = shift; 397 | 398 | my $name = $self->{name}; 399 | 400 | return ::AttrVal( $name, 'ASC_advEndDate', 'EpiphanyDay' ); 401 | } 402 | 403 | 1; 404 | -------------------------------------------------------------------------------- /lib/FHEM/Automation/ShuttersControl/Dev/Readings.pm: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # Developed with VSCodium and richterger perl plugin 4 | # 5 | # (c) 2018-2025 Copyright: Marko Oldenburg (fhemdevelopment at cooltux dot net) 6 | # All rights reserved 7 | # 8 | # Special thanks goes to: 9 | # - Bernd (Cluni) this module is based on the logic of his script "Rollladensteuerung für HM/ROLLO inkl. Abschattung und Komfortfunktionen in Perl" (https://forum.fhem.de/index.php/topic,73964.0.html) 10 | # - Beta-User for many tests, many suggestions and good discussions 11 | # - pc1246 write english commandref 12 | # - FunkOdyssey commandref style 13 | # - sledge fix many typo in commandref 14 | # - many User that use with modul and report bugs 15 | # - Christoph (christoph.kaiser.in) Patch that expand RegEx for Window Events 16 | # - Julian (Loredo) expand Residents Events for new Residents functions 17 | # - Christoph (Christoph Morrison) for fix Commandref, many suggestions and good discussions 18 | # 19 | # 20 | # This script is free software; you can redistribute it and/or modify 21 | # it under the terms of the GNU General Public License as published by 22 | # the Free Software Foundation; either version 2 of the License,or 23 | # any later version. 24 | # 25 | # The GNU General Public License can be found at 26 | # http://www.gnu.org/copyleft/gpl.html. 27 | # A copy is found in the textfile GPL.txt and important notices to the license 28 | # from the author is found in LICENSE.txt distributed with these scripts. 29 | # 30 | # This script is distributed in the hope that it will be useful, 31 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 32 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 33 | # GNU General Public License for more details. 34 | # 35 | # 36 | # $Id$ 37 | # 38 | ############################################################################### 39 | 40 | ## Subklasse Readings ## 41 | package FHEM::Automation::ShuttersControl::Dev::Readings; 42 | 43 | use strict; 44 | use warnings; 45 | use utf8; 46 | 47 | use GPUtils qw(GP_Import); 48 | 49 | ## Import der FHEM Funktionen 50 | BEGIN { 51 | GP_Import(qw(defs)); 52 | } 53 | 54 | sub setDelayCmdReading { 55 | my $self = shift; 56 | 57 | my $name = $self->{name}; 58 | my $hash = $defs{$name}; 59 | 60 | ::readingsSingleUpdate( 61 | $hash, 62 | $FHEM::Automation::ShuttersControl::shutters->getShuttersDev 63 | . '_lastDelayPosValue', 64 | $FHEM::Automation::ShuttersControl::shutters->getDelayCmd, 65 | 1 66 | ); 67 | return; 68 | } 69 | 70 | sub setStateReading { 71 | my $self = shift; 72 | my $value = shift; 73 | 74 | my $name = $self->{name}; 75 | my $hash = $defs{$name}; 76 | 77 | ::readingsSingleUpdate( 78 | $hash, 'state', 79 | ( 80 | defined($value) 81 | ? $value 82 | : $FHEM::Automation::ShuttersControl::shutters->getLastDrive 83 | ), 84 | 1 85 | ); 86 | return; 87 | } 88 | 89 | sub setPosReading { 90 | my $self = shift; 91 | 92 | my $name = $self->{name}; 93 | my $hash = $defs{$name}; 94 | 95 | ::readingsSingleUpdate( 96 | $hash, 97 | $FHEM::Automation::ShuttersControl::shutters->getShuttersDev 98 | . '_PosValue', 99 | $FHEM::Automation::ShuttersControl::shutters->getStatus, 100 | 1 101 | ); 102 | return; 103 | } 104 | 105 | sub setLastPosReading { 106 | my $self = shift; 107 | 108 | my $name = $self->{name}; 109 | my $hash = $defs{$name}; 110 | 111 | ::readingsSingleUpdate( 112 | $hash, 113 | $FHEM::Automation::ShuttersControl::shutters->getShuttersDev 114 | . '_lastPosValue', 115 | $FHEM::Automation::ShuttersControl::shutters->getLastPos, 116 | 1 117 | ); 118 | return; 119 | } 120 | 121 | sub getPartyMode { 122 | my $self = shift; 123 | 124 | my $name = $self->{name}; 125 | 126 | return ::ReadingsVal( $name, 'partyMode', 'off' ); 127 | } 128 | 129 | sub getHardLockOut { 130 | my $self = shift; 131 | 132 | my $name = $self->{name}; 133 | 134 | return ::ReadingsVal( $name, 'hardLockOut', 'none' ); 135 | } 136 | 137 | sub getSunriseTimeWeHoliday { 138 | my $self = shift; 139 | 140 | my $name = $self->{name}; 141 | 142 | return ::ReadingsVal( $name, 'sunriseTimeWeHoliday', 'none' ); 143 | } 144 | 145 | sub getMonitoredDevs { 146 | my $self = shift; 147 | 148 | my $name = $self->{name}; 149 | 150 | $self->{monitoredDevs} = ::ReadingsVal( $name, '.monitoredDevs', 'none' ); 151 | return $self->{monitoredDevs}; 152 | } 153 | 154 | sub getOutTemp { 155 | my $self = shift; 156 | 157 | return ::ReadingsVal( 158 | $FHEM::Automation::ShuttersControl::ascDev->_getTempSensor, 159 | $FHEM::Automation::ShuttersControl::ascDev->getTempSensorReading, 160 | -100 ); 161 | } 162 | 163 | sub getResidentsStatus { 164 | my $self = shift; 165 | 166 | my $val = 167 | ::ReadingsVal( 168 | $FHEM::Automation::ShuttersControl::ascDev->_getResidentsDev, 169 | $FHEM::Automation::ShuttersControl::ascDev->getResidentsReading, 170 | 'none' ); 171 | 172 | if ( $val =~ m{^(?:(.+)_)?(.+)$}xms ) { 173 | return ( $1, $2 ) if (wantarray); 174 | return $1 && $1 eq 'pet' ? 'absent' : $2; 175 | } 176 | elsif ( 177 | ::ReadingsVal( 178 | $FHEM::Automation::ShuttersControl::ascDev->_getResidentsDev, 179 | 'homealoneType', '-' ) eq 'PET' 180 | ) 181 | { 182 | return ( 'pet', 'absent' ) if (wantarray); 183 | return 'absent'; 184 | } 185 | else { 186 | return ( undef, $val ) if (wantarray); 187 | return $val; 188 | } 189 | } 190 | 191 | sub getResidentsLastStatus { 192 | my $self = shift; 193 | 194 | my $val = 195 | ::ReadingsVal( 196 | $FHEM::Automation::ShuttersControl::ascDev->_getResidentsDev, 197 | 'lastState', 'none' ); 198 | 199 | if ( $val =~ m{^(?:(.+)_)?(.+)$}xms ) { 200 | return ( $1, $2 ) if (wantarray); 201 | return $1 && $1 eq 'pet' ? 'absent' : $2; 202 | } 203 | elsif ( 204 | ::ReadingsVal( 205 | $FHEM::Automation::ShuttersControl::ascDev->_getResidentsDev, 206 | 'lastHomealoneType', '-' ) eq 'PET' 207 | ) 208 | { 209 | return ( 'pet', 'absent' ) if (wantarray); 210 | return 'absent'; 211 | } 212 | else { 213 | return ( undef, $val ) if (wantarray); 214 | return $val; 215 | } 216 | } 217 | 218 | sub getAutoShuttersControlShading { 219 | my $self = shift; 220 | 221 | my $name = $self->{name}; 222 | 223 | return ::ReadingsVal( $name, 'controlShading', 'none' ); 224 | } 225 | 226 | sub getSelfDefense { 227 | my $self = shift; 228 | 229 | my $name = $self->{name}; 230 | 231 | return ::ReadingsVal( $name, 'selfDefense', 'none' ); 232 | } 233 | 234 | sub getAzimuth { 235 | my $self = shift; 236 | 237 | my $azimuth; 238 | 239 | $azimuth = ::ReadingsVal( 240 | $FHEM::Automation::ShuttersControl::ascDev->_getTwilightDevice, 241 | 'azimuth', -1 ) 242 | if ( 243 | $defs{ $FHEM::Automation::ShuttersControl::ascDev->_getTwilightDevice } 244 | ->{TYPE} eq 'Twilight' ); 245 | $azimuth = ::ReadingsVal( 246 | $FHEM::Automation::ShuttersControl::ascDev->_getTwilightDevice, 247 | 'SunAz', -1 ) 248 | if ( 249 | $defs{ $FHEM::Automation::ShuttersControl::ascDev->_getTwilightDevice } 250 | ->{TYPE} eq 'Astro' ); 251 | 252 | return $azimuth; 253 | } 254 | 255 | sub getElevation { 256 | my $self = shift; 257 | 258 | my $elevation; 259 | 260 | $elevation = ::ReadingsVal( 261 | $FHEM::Automation::ShuttersControl::ascDev->_getTwilightDevice, 262 | 'elevation', -1 ) 263 | if ( 264 | $defs{ $FHEM::Automation::ShuttersControl::ascDev->_getTwilightDevice } 265 | ->{TYPE} eq 'Twilight' ); 266 | $elevation = ::ReadingsVal( 267 | $FHEM::Automation::ShuttersControl::ascDev->_getTwilightDevice, 268 | 'SunAlt', -1 ) 269 | if ( 270 | $defs{ $FHEM::Automation::ShuttersControl::ascDev->_getTwilightDevice } 271 | ->{TYPE} eq 'Astro' ); 272 | 273 | return $elevation; 274 | } 275 | 276 | sub getASCenable { 277 | my $self = shift; 278 | 279 | my $name = $self->{name}; 280 | 281 | return ::ReadingsVal( $name, 'ascEnable', 'none' ); 282 | } 283 | 284 | 1; 285 | -------------------------------------------------------------------------------- /lib/FHEM/Automation/ShuttersControl/Helper.pm: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # Developed with VSCodium and richterger perl plugin 4 | # 5 | # (c) 2018-2025 Copyright: Marko Oldenburg (fhemdevelopment at cooltux dot net) 6 | # All rights reserved 7 | # 8 | # Special thanks goes to: 9 | # - Bernd (Cluni) this module is based on the logic of his script "Rollladensteuerung für HM/ROLLO inkl. Abschattung und Komfortfunktionen in Perl" (https://forum.fhem.de/index.php/topic,73964.0.html) 10 | # - Beta-User for many tests, many suggestions and good discussions 11 | # - pc1246 write english commandref 12 | # - FunkOdyssey commandref style 13 | # - sledge fix many typo in commandref 14 | # - many User that use with modul and report bugs 15 | # - Christoph (christoph.kaiser.in) Patch that expand RegEx for Window Events 16 | # - Julian (Loredo) expand Residents Events for new Residents functions 17 | # - Christoph (Christoph Morrison) for fix Commandref, many suggestions and good discussions 18 | # 19 | # 20 | # This script is free software; you can redistribute it and/or modify 21 | # it under the terms of the GNU General Public License as published by 22 | # the Free Software Foundation; either version 2 of the License,or 23 | # any later version. 24 | # 25 | # The GNU General Public License can be found at 26 | # http://www.gnu.org/copyleft/gpl.html. 27 | # A copy is found in the textfile GPL.txt and important notices to the license 28 | # from the author is found in LICENSE.txt distributed with these scripts. 29 | # 30 | # This script is distributed in the hope that it will be useful, 31 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 32 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 33 | # GNU General Public License for more details. 34 | # 35 | # 36 | # $Id$ 37 | # 38 | ############################################################################### 39 | 40 | ## unserer packagename 41 | package FHEM::Automation::ShuttersControl::Helper; 42 | 43 | use strict; 44 | use warnings; 45 | use POSIX qw(strftime); 46 | use utf8; 47 | 48 | require Exporter; 49 | use base qw(Exporter); 50 | 51 | # our @ISA = qw(Exporter); 52 | our @EXPORT_OK = qw( 53 | PositionValueWindowRec 54 | AutoSearchTwilightDev 55 | GetAttrValues 56 | CheckIfShuttersWindowRecOpen 57 | ExtractNotifyDevFromEvent 58 | ShuttersSunrise 59 | ShuttersSunset 60 | makeReadingName 61 | IsWe 62 | IsAfterShuttersTimeBlocking 63 | IsAfterShuttersManualBlocking 64 | AverageBrightness 65 | PerlCodeCheck 66 | IsAdv 67 | IsInTime 68 | ); 69 | our %EXPORT_TAGS = ( 70 | ALL => [ 71 | qw( 72 | PositionValueWindowRec 73 | AutoSearchTwilightDev 74 | GetAttrValues 75 | CheckIfShuttersWindowRecOpen 76 | ExtractNotifyDevFromEvent 77 | ShuttersSunrise 78 | ShuttersSunset 79 | makeReadingName 80 | IsWe 81 | IsAfterShuttersTimeBlocking 82 | IsAfterShuttersManualBlocking 83 | AverageBrightness 84 | PerlCodeCheck 85 | IsAdv 86 | IsInTime 87 | ) 88 | ], 89 | ); 90 | 91 | use GPUtils qw(GP_Import); 92 | ## Import der FHEM Funktionen 93 | BEGIN { 94 | GP_Import(qw(cmdFromAnalyze)); 95 | } 96 | 97 | sub PositionValueWindowRec { 98 | my $shuttersDev = shift; 99 | my $posValue = shift; 100 | 101 | if ( CheckIfShuttersWindowRecOpen($shuttersDev) == 1 102 | && $FHEM::Automation::ShuttersControl::shutters->getVentilateOpen eq 103 | 'on' ) 104 | { 105 | $posValue = 106 | $FHEM::Automation::ShuttersControl::shutters->getVentilatePos; 107 | } 108 | elsif ( CheckIfShuttersWindowRecOpen($shuttersDev) == 2 109 | && $FHEM::Automation::ShuttersControl::shutters->getSubTyp eq 110 | 'threestate' 111 | && $FHEM::Automation::ShuttersControl::ascDev 112 | ->getAutoShuttersControlComfort eq 'on' ) 113 | { 114 | $posValue = 115 | $FHEM::Automation::ShuttersControl::shutters->getComfortOpenPos; 116 | } 117 | elsif ( 118 | CheckIfShuttersWindowRecOpen($shuttersDev) == 2 119 | && ( $FHEM::Automation::ShuttersControl::shutters->getSubTyp eq 120 | 'threestate' 121 | || $FHEM::Automation::ShuttersControl::shutters->getSubTyp eq 122 | 'twostate' ) 123 | && $FHEM::Automation::ShuttersControl::shutters->getVentilateOpen eq 124 | 'on' 125 | ) 126 | { 127 | $posValue = 128 | $FHEM::Automation::ShuttersControl::shutters->getVentilatePos; 129 | } 130 | 131 | if ( 132 | $FHEM::Automation::ShuttersControl::shutters->getQueryShuttersPos( 133 | $posValue) 134 | ) 135 | { 136 | $posValue = $FHEM::Automation::ShuttersControl::shutters->getStatus; 137 | } 138 | 139 | return $posValue; 140 | } 141 | 142 | sub AutoSearchTwilightDev { 143 | my $hash = shift; 144 | 145 | my $name = $hash->{NAME}; 146 | 147 | if ( ::devspec2array('TYPE=(Astro|Twilight)') > 0 ) { 148 | ::CommandAttr( undef, 149 | $name 150 | . ' ASC_twilightDevice ' 151 | . ( ::devspec2array('TYPE=(Astro|Twilight)') )[0] ) 152 | if ( ::AttrVal( $name, 'ASC_twilightDevice', 'none' ) eq 'none' ); 153 | } 154 | 155 | return; 156 | } 157 | 158 | sub GetAttrValues { 159 | my $dev = shift; 160 | my $attribut = shift; 161 | my $default = shift; 162 | 163 | my @values = split( 164 | ' ', 165 | ::AttrVal( $dev, $attribut, ( defined($default) ? $default : 'none' ) ) 166 | ); 167 | my ( $value1, $value2 ) = split( ':', $values[0] ); 168 | 169 | my ( $value3, $value4, $value5, $value6, $value7, $value8 ); 170 | ( $value3, $value4 ) = split( ':', $values[1] ) 171 | if ( defined( $values[1] ) ); 172 | ( $value5, $value6 ) = split( ':', $values[2] ) 173 | if ( defined( $values[2] ) ); 174 | ( $value7, $value8 ) = split( ':', $values[3] ) 175 | if ( defined( $values[3] ) ); 176 | 177 | return ( 178 | $value1, 179 | defined($value2) ? $value2 : 'none', 180 | defined($value3) ? $value3 : 'none', 181 | defined($value4) ? $value4 : 'none', 182 | defined($value5) ? $value5 : 'none', 183 | defined($value6) ? $value6 : 'none', 184 | defined($value7) ? $value7 : 'none', 185 | defined($value8) ? $value8 : 'none' 186 | ); 187 | } 188 | 189 | ## Kontrolliert ob das Fenster von einem bestimmten Rolladen offen ist 190 | sub CheckIfShuttersWindowRecOpen { 191 | my $shuttersDev = shift; 192 | $FHEM::Automation::ShuttersControl::shutters->setShuttersDev($shuttersDev); 193 | 194 | if ( $FHEM::Automation::ShuttersControl::shutters->getWinStatus =~ 195 | m{[Oo]pen|false}xms ) # CK: covers: open|opened 196 | { 197 | return 2; 198 | } 199 | elsif ( 200 | $FHEM::Automation::ShuttersControl::shutters->getWinStatus =~ m{tilt}xms 201 | && $FHEM::Automation::ShuttersControl::shutters->getSubTyp eq 202 | 'threestate' ) # CK: covers: tilt|tilted 203 | { 204 | return 1; 205 | } 206 | elsif ( $FHEM::Automation::ShuttersControl::shutters->getWinStatus =~ 207 | m{[Cc]lose|true}xms ) 208 | { 209 | return 0; 210 | } # CK: covers: close|closed 211 | } 212 | 213 | sub ExtractNotifyDevFromEvent { 214 | my $hash = shift; 215 | my $shuttersDev = shift; 216 | my $shuttersAttr = shift; 217 | 218 | my %notifyDevs; 219 | while ( my $notifyDev = each %{ $hash->{monitoredDevs} } ) { 220 | ::Log3( $hash->{NAME}, 4, 221 | "AutoShuttersControl ($hash->{NAME}) - ExtractNotifyDevFromEvent - NotifyDev: " 222 | . $notifyDev ); 223 | ::Log3( $hash->{NAME}, 5, 224 | "AutoShuttersControl ($hash->{NAME}) - ExtractNotifyDevFromEvent - ShuttersDev: " 225 | . $shuttersDev ); 226 | 227 | if ( defined( $hash->{monitoredDevs}{$notifyDev}{$shuttersDev} ) 228 | && $hash->{monitoredDevs}{$notifyDev}{$shuttersDev} eq 229 | $shuttersAttr ) 230 | { 231 | ::Log3( $hash->{NAME}, 4, 232 | "AutoShuttersControl ($hash->{NAME}) - ExtractNotifyDevFromEvent - ShuttersDevHash: " 233 | . $hash->{monitoredDevs}{$notifyDev}{$shuttersDev} ); 234 | ::Log3( $hash->{NAME}, 5, 235 | "AutoShuttersControl ($hash->{NAME}) - ExtractNotifyDevFromEvent - return ShuttersDev: " 236 | . $notifyDev ); 237 | $notifyDevs{$notifyDev} = $shuttersDev; 238 | } 239 | } 240 | return \%notifyDevs; 241 | } 242 | 243 | ## Ist Tag oder Nacht für den entsprechende Rolladen 244 | sub _IsDay { 245 | my $shuttersDev = shift; 246 | 247 | $FHEM::Automation::ShuttersControl::shutters->setShuttersDev($shuttersDev); 248 | 249 | my $brightnessMinVal = ( 250 | $FHEM::Automation::ShuttersControl::shutters->getBrightnessMinVal > -2 251 | ? $FHEM::Automation::ShuttersControl::shutters->getBrightnessMinVal 252 | : $FHEM::Automation::ShuttersControl::ascDev->getBrightnessMinVal 253 | ); 254 | 255 | my $brightnessMaxVal = ( 256 | $FHEM::Automation::ShuttersControl::shutters->getBrightnessMaxVal > -2 257 | ? $FHEM::Automation::ShuttersControl::shutters->getBrightnessMaxVal 258 | : $FHEM::Automation::ShuttersControl::ascDev->getBrightnessMaxVal 259 | ); 260 | 261 | my $isday = ( ShuttersSunrise( $shuttersDev, 'unix' ) > 262 | ShuttersSunset( $shuttersDev, 'unix' ) ? 1 : 0 ); 263 | my $respIsDay = $isday; 264 | 265 | FHEM::Automation::ShuttersControl::ASC_Debug( 266 | 'FnIsDay: ' . $shuttersDev . ' Allgemein: ' . $respIsDay ); 267 | 268 | if ( 269 | ( 270 | ( 271 | ( 272 | int( ::gettimeofday() / 86400 ) != int( 273 | ::computeAlignTime( 274 | '24:00', 275 | $FHEM::Automation::ShuttersControl::shutters 276 | ->getTimeUpEarly 277 | ) / 86400 278 | ) 279 | && ( 280 | !IsWe() 281 | || ( 282 | IsWe() 283 | && ( $FHEM::Automation::ShuttersControl::ascDev 284 | ->getSunriseTimeWeHoliday eq 'off' 285 | || $FHEM::Automation::ShuttersControl::shutters 286 | ->getTimeUpWeHoliday eq '01:25' ) 287 | ) 288 | ) 289 | ) 290 | || ( 291 | int( ::gettimeofday() / 86400 ) != int( 292 | ::computeAlignTime( 293 | '24:00', 294 | $FHEM::Automation::ShuttersControl::shutters 295 | ->getTimeUpWeHoliday 296 | ) / 86400 297 | ) 298 | && IsWe() 299 | && $FHEM::Automation::ShuttersControl::ascDev 300 | ->getSunriseTimeWeHoliday eq 'on' 301 | && $FHEM::Automation::ShuttersControl::shutters 302 | ->getTimeUpWeHoliday ne '01:25' 303 | ) 304 | ) 305 | && int( ::gettimeofday() / 86400 ) == int( 306 | ::computeAlignTime( 307 | '24:00', 308 | $FHEM::Automation::ShuttersControl::shutters->getTimeUpLate 309 | ) / 86400 310 | ) 311 | ) 312 | || ( 313 | int( ::gettimeofday() / 86400 ) != int( 314 | ::computeAlignTime( 315 | '24:00', 316 | $FHEM::Automation::ShuttersControl::shutters 317 | ->getTimeDownEarly 318 | ) / 86400 319 | ) 320 | && int( ::gettimeofday() / 86400 ) == int( 321 | ::computeAlignTime( 322 | '24:00', 323 | $FHEM::Automation::ShuttersControl::shutters 324 | ->getTimeDownLate 325 | ) / 86400 326 | ) 327 | ) 328 | ) 329 | { 330 | ##### Nach Sonnenuntergang / Abends 331 | $respIsDay = ( 332 | ( 333 | ( 334 | $FHEM::Automation::ShuttersControl::shutters 335 | ->getBrightness > $brightnessMinVal 336 | && $isday 337 | && !$FHEM::Automation::ShuttersControl::shutters 338 | ->getSunset 339 | ) 340 | || $FHEM::Automation::ShuttersControl::shutters->getSunrise 341 | ) ? 1 : 0 342 | ) 343 | if ( $FHEM::Automation::ShuttersControl::shutters->getDown eq 344 | 'brightness' ); 345 | 346 | FHEM::Automation::ShuttersControl::ASC_Debug( 'FnIsDay: ' 347 | . $shuttersDev 348 | . ' getDownBrightness: ' 349 | . $respIsDay 350 | . ' Brightness: ' 351 | . $FHEM::Automation::ShuttersControl::shutters->getBrightness 352 | . ' BrightnessMin: ' 353 | . $brightnessMinVal 354 | . ' Sunset: ' 355 | . $FHEM::Automation::ShuttersControl::shutters->getSunset ); 356 | 357 | ##### Nach Sonnenauf / Morgens 358 | $respIsDay = ( 359 | ( 360 | ( 361 | $FHEM::Automation::ShuttersControl::shutters 362 | ->getBrightness > $brightnessMaxVal 363 | && !$isday 364 | && $FHEM::Automation::ShuttersControl::shutters 365 | ->getSunrise 366 | ) 367 | || $respIsDay 368 | || $FHEM::Automation::ShuttersControl::shutters->getSunrise 369 | ) ? 1 : 0 370 | ) 371 | if ( $FHEM::Automation::ShuttersControl::shutters->getUp eq 372 | 'brightness' ); 373 | 374 | FHEM::Automation::ShuttersControl::ASC_Debug( 'FnIsDay: ' 375 | . $shuttersDev 376 | . ' getUpBrightness: ' 377 | . $respIsDay 378 | . ' Brightness: ' 379 | . $FHEM::Automation::ShuttersControl::shutters->getBrightness 380 | . ' BrightnessMax: ' 381 | . $brightnessMaxVal 382 | . ' Sunrise: ' 383 | . $FHEM::Automation::ShuttersControl::shutters->getSunrise ); 384 | } 385 | 386 | $respIsDay = 1 387 | if ( 388 | ( 389 | $FHEM::Automation::ShuttersControl::shutters->getDown eq 'roommate' 390 | and ( $FHEM::Automation::ShuttersControl::shutters->getRoommates ne 391 | 'asleep' 392 | or $FHEM::Automation::ShuttersControl::shutters->getRoommates 393 | ne 'gotosleep' ) 394 | ) 395 | or ( 396 | $FHEM::Automation::ShuttersControl::shutters->getUp eq 'roommate' 397 | and ( $FHEM::Automation::ShuttersControl::shutters->getRoommates ne 398 | 'asleep' 399 | or $FHEM::Automation::ShuttersControl::shutters->getRoommates 400 | ne 'gotosleep' ) 401 | ) 402 | or ( $FHEM::Automation::ShuttersControl::shutters->getShuttersPlace eq 403 | 'awning' ) 404 | ); 405 | 406 | return $respIsDay; 407 | } 408 | 409 | sub ShuttersSunrise { 410 | my $shuttersDev = shift; 411 | my $tm = shift; # Tm steht für Timemode und bedeutet Realzeit oder Unixzeit 412 | 413 | my $autoAstroMode; 414 | $FHEM::Automation::ShuttersControl::shutters->setShuttersDev($shuttersDev); 415 | 416 | if ( $FHEM::Automation::ShuttersControl::shutters->getAutoAstroModeMorning 417 | ne 'none' ) 418 | { 419 | $autoAstroMode = 420 | $FHEM::Automation::ShuttersControl::shutters->getAutoAstroModeMorning; 421 | $autoAstroMode = 422 | $autoAstroMode . '=' 423 | . $FHEM::Automation::ShuttersControl::shutters 424 | ->getAutoAstroModeMorningHorizon 425 | if ( $autoAstroMode eq 'HORIZON' ); 426 | } 427 | else { 428 | $autoAstroMode = 429 | $FHEM::Automation::ShuttersControl::ascDev->getAutoAstroModeMorning; 430 | $autoAstroMode = 431 | $autoAstroMode . '=' 432 | . $FHEM::Automation::ShuttersControl::ascDev 433 | ->getAutoAstroModeMorningHorizon 434 | if ( $autoAstroMode eq 'HORIZON' ); 435 | } 436 | my $oldFuncHash = 437 | $FHEM::Automation::ShuttersControl::shutters->getInTimerFuncHash; 438 | my $shuttersSunriseUnixtime = 439 | ::computeAlignTime( '24:00', ::sunrise( 'REAL', 0, '4:30', '8:30' ) ); 440 | 441 | if ( $tm eq 'unix' ) { 442 | if ( $FHEM::Automation::ShuttersControl::shutters->getUp eq 'astro' ) { 443 | if ( ( IsWe() || IsWe('tomorrow') ) 444 | && $FHEM::Automation::ShuttersControl::ascDev 445 | ->getSunriseTimeWeHoliday eq 'on' 446 | && $FHEM::Automation::ShuttersControl::shutters 447 | ->getTimeUpWeHoliday ne '01:25' ) 448 | { 449 | if ( !IsWe('tomorrow') ) { 450 | if ( 451 | IsWe() 452 | && int( ::gettimeofday() / 86400 ) == int( 453 | ( 454 | ::computeAlignTime( 455 | '24:00', 456 | ::sunrise_abs( 457 | $autoAstroMode, 458 | 0, 459 | $FHEM::Automation::ShuttersControl::shutters 460 | ->getTimeUpWeHoliday 461 | ) 462 | ) + 1 463 | ) / 86400 464 | ) 465 | ) 466 | { 467 | $shuttersSunriseUnixtime = ( 468 | ::computeAlignTime( 469 | '24:00', 470 | ::sunrise_abs( 471 | $autoAstroMode, 472 | 0, 473 | $FHEM::Automation::ShuttersControl::shutters 474 | ->getTimeUpWeHoliday 475 | ) 476 | ) + 1 477 | ); 478 | } 479 | elsif ( 480 | int( ::gettimeofday() / 86400 ) == int( 481 | ( 482 | ::computeAlignTime( 483 | '24:00', 484 | ::sunrise_abs( 485 | $autoAstroMode, 486 | 0, 487 | $FHEM::Automation::ShuttersControl::shutters 488 | ->getTimeUpEarly, 489 | $FHEM::Automation::ShuttersControl::shutters 490 | ->getTimeUpLate 491 | ) 492 | ) + 1 493 | ) / 86400 494 | ) 495 | ) 496 | { 497 | $shuttersSunriseUnixtime = ( 498 | ::computeAlignTime( 499 | '24:00', 500 | ::sunrise_abs( 501 | $autoAstroMode, 502 | 0, 503 | $FHEM::Automation::ShuttersControl::shutters 504 | ->getTimeUpWeHoliday 505 | ) 506 | ) + 1 507 | ); 508 | } 509 | else { 510 | $shuttersSunriseUnixtime = ( 511 | ::computeAlignTime( 512 | '24:00', 513 | ::sunrise_abs( 514 | $autoAstroMode, 515 | 0, 516 | $FHEM::Automation::ShuttersControl::shutters 517 | ->getTimeUpEarly, 518 | $FHEM::Automation::ShuttersControl::shutters 519 | ->getTimeUpLate 520 | ) 521 | ) + 1 522 | ); 523 | } 524 | } 525 | else { 526 | if ( 527 | IsWe() 528 | && ( 529 | int( ::gettimeofday() / 86400 ) == int( 530 | ( 531 | ::computeAlignTime( 532 | '24:00', 533 | ::sunrise_abs( 534 | $autoAstroMode, 535 | 0, 536 | $FHEM::Automation::ShuttersControl::shutters 537 | ->getTimeUpWeHoliday 538 | ) 539 | ) + 1 540 | ) / 86400 541 | ) 542 | || int( ::gettimeofday() / 86400 ) != int( 543 | ( 544 | ::computeAlignTime( 545 | '24:00', 546 | ::sunrise_abs( 547 | $autoAstroMode, 548 | 0, 549 | $FHEM::Automation::ShuttersControl::shutters 550 | ->getTimeUpWeHoliday 551 | ) 552 | ) + 1 553 | ) / 86400 554 | ) 555 | ) 556 | ) 557 | { 558 | $shuttersSunriseUnixtime = ( 559 | ::computeAlignTime( 560 | '24:00', 561 | ::sunrise_abs( 562 | $autoAstroMode, 563 | 0, 564 | $FHEM::Automation::ShuttersControl::shutters 565 | ->getTimeUpWeHoliday 566 | ) 567 | ) + 1 568 | ); 569 | } 570 | elsif ( 571 | int( ::gettimeofday() / 86400 ) == int( 572 | ( 573 | ::computeAlignTime( 574 | '24:00', 575 | ::sunrise_abs( 576 | $autoAstroMode, 577 | 0, 578 | $FHEM::Automation::ShuttersControl::shutters 579 | ->getTimeUpEarly, 580 | $FHEM::Automation::ShuttersControl::shutters 581 | ->getTimeUpLate 582 | ) 583 | ) + 1 584 | ) / 86400 585 | ) 586 | ) 587 | { 588 | $shuttersSunriseUnixtime = ( 589 | ::computeAlignTime( 590 | '24:00', 591 | ::sunrise_abs( 592 | $autoAstroMode, 593 | 0, 594 | $FHEM::Automation::ShuttersControl::shutters 595 | ->getTimeUpEarly, 596 | $FHEM::Automation::ShuttersControl::shutters 597 | ->getTimeUpLate 598 | ) 599 | ) + 1 600 | ); 601 | } 602 | else { 603 | if ( 604 | int( ::gettimeofday() / 86400 ) == int( 605 | ( 606 | ::computeAlignTime( 607 | '24:00', 608 | ::sunrise_abs( 609 | $autoAstroMode, 610 | 0, 611 | $FHEM::Automation::ShuttersControl::shutters 612 | ->getTimeUpWeHoliday 613 | ) 614 | ) + 1 615 | ) / 86400 616 | ) 617 | ) 618 | { 619 | $shuttersSunriseUnixtime = ( 620 | ::computeAlignTime( 621 | '24:00', 622 | ::sunrise_abs( 623 | $autoAstroMode, 624 | 0, 625 | $FHEM::Automation::ShuttersControl::shutters 626 | ->getTimeUpWeHoliday 627 | ) 628 | ) + 86401 629 | ); 630 | } 631 | else { 632 | $shuttersSunriseUnixtime = ( 633 | ::computeAlignTime( 634 | '24:00', 635 | ::sunrise_abs( 636 | $autoAstroMode, 637 | 0, 638 | $FHEM::Automation::ShuttersControl::shutters 639 | ->getTimeUpWeHoliday 640 | ) 641 | ) + 1 642 | ); 643 | } 644 | } 645 | } 646 | } 647 | else { 648 | $shuttersSunriseUnixtime = ( 649 | ::computeAlignTime( 650 | '24:00', 651 | ::sunrise_abs( 652 | $autoAstroMode, 653 | 0, 654 | $FHEM::Automation::ShuttersControl::shutters 655 | ->getTimeUpEarly, 656 | $FHEM::Automation::ShuttersControl::shutters 657 | ->getTimeUpLate 658 | ) 659 | ) + 1 660 | ); 661 | } 662 | if ( defined($oldFuncHash) 663 | && ref($oldFuncHash) eq 'HASH' 664 | && ( IsWe() || IsWe('tomorrow') ) 665 | && $FHEM::Automation::ShuttersControl::ascDev 666 | ->getSunriseTimeWeHoliday eq 'on' 667 | && $FHEM::Automation::ShuttersControl::shutters 668 | ->getTimeUpWeHoliday ne '01:25' ) 669 | { 670 | if ( !IsWe('tomorrow') ) { 671 | if ( 672 | int( ::gettimeofday() / 86400 ) == int( 673 | ( 674 | ::computeAlignTime( 675 | '24:00', 676 | ::sunrise_abs( 677 | $autoAstroMode, 678 | 0, 679 | $FHEM::Automation::ShuttersControl::shutters 680 | ->getTimeUpEarly, 681 | $FHEM::Automation::ShuttersControl::shutters 682 | ->getTimeUpLate 683 | ) 684 | ) + 1 685 | ) / 86400 686 | ) 687 | ) 688 | { 689 | $shuttersSunriseUnixtime = 690 | ( $shuttersSunriseUnixtime + 86400 ) 691 | if ( $shuttersSunriseUnixtime < 692 | ( $oldFuncHash->{sunrisetime} + 180 ) 693 | && $oldFuncHash->{sunrisetime} < ::gettimeofday() ); 694 | } 695 | } 696 | } 697 | elsif ( defined($oldFuncHash) && ref($oldFuncHash) eq 'HASH' ) { 698 | $shuttersSunriseUnixtime = ( $shuttersSunriseUnixtime + 86400 ) 699 | if ( $shuttersSunriseUnixtime < 700 | ( $oldFuncHash->{sunrisetime} + 180 ) 701 | && $oldFuncHash->{sunrisetime} < ::gettimeofday() ); 702 | } 703 | } 704 | elsif ( $FHEM::Automation::ShuttersControl::shutters->getUp eq 'time' ) 705 | { 706 | if ( ( IsWe() || IsWe('tomorrow') ) 707 | && $FHEM::Automation::ShuttersControl::ascDev 708 | ->getSunriseTimeWeHoliday eq 'on' 709 | && $FHEM::Automation::ShuttersControl::shutters 710 | ->getTimeUpWeHoliday ne '01:25' ) 711 | { 712 | if ( !IsWe('tomorrow') ) { 713 | if ( 714 | int( ::gettimeofday() / 86400 ) == int( 715 | ::computeAlignTime( 716 | '24:00', 717 | $FHEM::Automation::ShuttersControl::shutters 718 | ->getTimeUpWeHoliday 719 | ) / 86400 720 | ) 721 | ) 722 | { 723 | $shuttersSunriseUnixtime = ::computeAlignTime( '24:00', 724 | $FHEM::Automation::ShuttersControl::shutters 725 | ->getTimeUpWeHoliday ); 726 | } 727 | elsif ( 728 | int( ::gettimeofday() / 86400 ) == int( 729 | ::computeAlignTime( 730 | '24:00', 731 | $FHEM::Automation::ShuttersControl::shutters 732 | ->getTimeUpEarly 733 | ) / 86400 734 | ) 735 | && $FHEM::Automation::ShuttersControl::shutters 736 | ->getSunrise 737 | ) 738 | { 739 | $shuttersSunriseUnixtime = ::computeAlignTime( '24:00', 740 | $FHEM::Automation::ShuttersControl::shutters 741 | ->getTimeUpEarly ) + 86400; 742 | } 743 | else { 744 | $shuttersSunriseUnixtime = ::computeAlignTime( '24:00', 745 | $FHEM::Automation::ShuttersControl::shutters 746 | ->getTimeUpEarly ); 747 | } 748 | } 749 | else { 750 | if ( 751 | IsWe() 752 | && int( ::gettimeofday() / 86400 ) == int( 753 | ::computeAlignTime( 754 | '24:00', 755 | $FHEM::Automation::ShuttersControl::shutters 756 | ->getTimeUpWeHoliday 757 | ) / 86400 758 | ) 759 | ) 760 | { 761 | $shuttersSunriseUnixtime = ::computeAlignTime( '24:00', 762 | $FHEM::Automation::ShuttersControl::shutters 763 | ->getTimeUpWeHoliday ); 764 | } 765 | elsif ( 766 | int( ::gettimeofday() / 86400 ) == int( 767 | ::computeAlignTime( 768 | '24:00', 769 | $FHEM::Automation::ShuttersControl::shutters 770 | ->getTimeUpEarly 771 | ) / 86400 772 | ) 773 | ) 774 | { 775 | $shuttersSunriseUnixtime = ::computeAlignTime( '24:00', 776 | $FHEM::Automation::ShuttersControl::shutters 777 | ->getTimeUpEarly ); 778 | } 779 | elsif ( 780 | int( ::gettimeofday() / 86400 ) != int( 781 | ::computeAlignTime( 782 | '24:00', 783 | $FHEM::Automation::ShuttersControl::shutters 784 | ->getTimeUpWeHoliday 785 | ) / 86400 786 | ) 787 | ) 788 | { 789 | $shuttersSunriseUnixtime = ::computeAlignTime( '24:00', 790 | $FHEM::Automation::ShuttersControl::shutters 791 | ->getTimeUpWeHoliday ); 792 | } 793 | else { 794 | $shuttersSunriseUnixtime = ::computeAlignTime( '24:00', 795 | $FHEM::Automation::ShuttersControl::shutters 796 | ->getTimeUpWeHoliday ) + 86400; 797 | } 798 | } 799 | } 800 | else { 801 | $shuttersSunriseUnixtime = ::computeAlignTime( '24:00', 802 | $FHEM::Automation::ShuttersControl::shutters 803 | ->getTimeUpEarly ); 804 | } 805 | } 806 | elsif ( $FHEM::Automation::ShuttersControl::shutters->getUp eq 807 | 'brightness' ) 808 | { 809 | $shuttersSunriseUnixtime = ::computeAlignTime( '24:00', 810 | $FHEM::Automation::ShuttersControl::shutters->getTimeUpLate ); 811 | } 812 | 813 | return $shuttersSunriseUnixtime; 814 | } 815 | elsif ( $tm eq 'real' ) { 816 | return ::sunrise_abs( 817 | $autoAstroMode, 818 | 0, 819 | $FHEM::Automation::ShuttersControl::shutters->getTimeUpEarly, 820 | $FHEM::Automation::ShuttersControl::shutters->getTimeUpLate 821 | ) 822 | if ( $FHEM::Automation::ShuttersControl::shutters->getUp eq 'astro' ); 823 | return $FHEM::Automation::ShuttersControl::shutters->getTimeUpEarly 824 | if ( $FHEM::Automation::ShuttersControl::shutters->getUp eq 'time' ); 825 | } 826 | 827 | return; 828 | } 829 | 830 | sub ShuttersSunset { 831 | my $shuttersDev = shift; 832 | my $tm = shift; # Tm steht für Timemode und bedeutet Realzeit oder Unixzeit 833 | 834 | my $autoAstroMode; 835 | $FHEM::Automation::ShuttersControl::shutters->setShuttersDev($shuttersDev); 836 | 837 | if ( $FHEM::Automation::ShuttersControl::shutters->getAutoAstroModeEvening 838 | ne 'none' ) 839 | { 840 | $autoAstroMode = 841 | $FHEM::Automation::ShuttersControl::shutters->getAutoAstroModeEvening; 842 | $autoAstroMode = 843 | $autoAstroMode . '=' 844 | . $FHEM::Automation::ShuttersControl::shutters 845 | ->getAutoAstroModeEveningHorizon 846 | if ( $autoAstroMode eq 'HORIZON' ); 847 | } 848 | else { 849 | $autoAstroMode = 850 | $FHEM::Automation::ShuttersControl::ascDev->getAutoAstroModeEvening; 851 | $autoAstroMode = 852 | $autoAstroMode . '=' 853 | . $FHEM::Automation::ShuttersControl::ascDev 854 | ->getAutoAstroModeEveningHorizon 855 | if ( $autoAstroMode eq 'HORIZON' ); 856 | } 857 | my $oldFuncHash = 858 | $FHEM::Automation::ShuttersControl::shutters->getInTimerFuncHash; 859 | my $shuttersSunsetUnixtime = 860 | ::computeAlignTime( '24:00', ::sunset( 'REAL', 0, '15:30', '21:30' ) ); 861 | 862 | if ( $tm eq 'unix' ) { 863 | if ( $FHEM::Automation::ShuttersControl::shutters->getDown eq 'astro' ) 864 | { 865 | $shuttersSunsetUnixtime = ( 866 | ::computeAlignTime( 867 | '24:00', 868 | ::sunset_abs( 869 | $autoAstroMode, 870 | 0, 871 | $FHEM::Automation::ShuttersControl::shutters 872 | ->getTimeDownEarly, 873 | $FHEM::Automation::ShuttersControl::shutters 874 | ->getTimeDownLate 875 | ) 876 | ) + 1 877 | ); 878 | if ( defined($oldFuncHash) && ref($oldFuncHash) eq 'HASH' ) { 879 | $shuttersSunsetUnixtime += 86400 880 | if ( $shuttersSunsetUnixtime < 881 | ( $oldFuncHash->{sunsettime} + 180 ) 882 | && $oldFuncHash->{sunsettime} < ::gettimeofday() ); 883 | } 884 | } 885 | elsif ( 886 | $FHEM::Automation::ShuttersControl::shutters->getDown eq 'time' ) 887 | { 888 | $shuttersSunsetUnixtime = ::computeAlignTime( '24:00', 889 | $FHEM::Automation::ShuttersControl::shutters->getTimeDownEarly 890 | ); 891 | } 892 | elsif ( $FHEM::Automation::ShuttersControl::shutters->getDown eq 893 | 'brightness' ) 894 | { 895 | $shuttersSunsetUnixtime = 896 | ::computeAlignTime( '24:00', 897 | $FHEM::Automation::ShuttersControl::shutters->getTimeDownLate ); 898 | } 899 | return $shuttersSunsetUnixtime; 900 | } 901 | elsif ( $tm eq 'real' ) { 902 | return ::sunset_abs( 903 | $autoAstroMode, 904 | 0, 905 | $FHEM::Automation::ShuttersControl::shutters->getTimeDownEarly, 906 | $FHEM::Automation::ShuttersControl::shutters->getTimeDownLate 907 | ) 908 | if ( 909 | $FHEM::Automation::ShuttersControl::shutters->getDown eq 'astro' ); 910 | return $FHEM::Automation::ShuttersControl::shutters->getTimeDownEarly 911 | if ( 912 | $FHEM::Automation::ShuttersControl::shutters->getDown eq 'time' ); 913 | } 914 | 915 | return; 916 | } 917 | 918 | sub IsAfterShuttersTimeBlocking { 919 | my $shuttersDev = shift; 920 | 921 | $FHEM::Automation::ShuttersControl::shutters->setShuttersDev($shuttersDev); 922 | 923 | if ( 924 | ( 925 | int( ::gettimeofday() ) - 926 | $FHEM::Automation::ShuttersControl::shutters->getLastManPosTimestamp 927 | ) < 928 | $FHEM::Automation::ShuttersControl::shutters->getBlockingTimeAfterManual 929 | || ( 930 | !$FHEM::Automation::ShuttersControl::shutters->getIsDay 931 | && defined( 932 | $FHEM::Automation::ShuttersControl::shutters->getSunriseUnixTime 933 | ) 934 | && $FHEM::Automation::ShuttersControl::shutters->getSunriseUnixTime 935 | - ( int( ::gettimeofday() ) ) < 936 | $FHEM::Automation::ShuttersControl::shutters 937 | ->getBlockingTimeBeforDayOpen 938 | ) 939 | || ( 940 | $FHEM::Automation::ShuttersControl::shutters->getIsDay 941 | && defined( 942 | $FHEM::Automation::ShuttersControl::shutters->getSunriseUnixTime 943 | ) 944 | && $FHEM::Automation::ShuttersControl::shutters->getSunsetUnixTime 945 | - ( int( ::gettimeofday() ) ) < 946 | $FHEM::Automation::ShuttersControl::shutters 947 | ->getBlockingTimeBeforNightClose 948 | ) 949 | ) 950 | { 951 | return 0; 952 | } 953 | 954 | else { return 1 } 955 | } 956 | 957 | sub IsAfterShuttersManualBlocking { 958 | my $shuttersDev = shift; 959 | $FHEM::Automation::ShuttersControl::shutters->setShuttersDev($shuttersDev); 960 | 961 | if ( 962 | $FHEM::Automation::ShuttersControl::ascDev->getBlockAscDrivesAfterManual 963 | && $FHEM::Automation::ShuttersControl::shutters->getStatus != 964 | $FHEM::Automation::ShuttersControl::shutters->getOpenPos 965 | && $FHEM::Automation::ShuttersControl::shutters->getStatus != 966 | $FHEM::Automation::ShuttersControl::shutters->getClosedPos 967 | && $FHEM::Automation::ShuttersControl::shutters->getStatus != 968 | $FHEM::Automation::ShuttersControl::shutters->getWindPos 969 | && $FHEM::Automation::ShuttersControl::shutters->getStatus != 970 | $FHEM::Automation::ShuttersControl::shutters->getShadingPos 971 | && $FHEM::Automation::ShuttersControl::shutters->getStatus != 972 | $FHEM::Automation::ShuttersControl::shutters->getComfortOpenPos 973 | && $FHEM::Automation::ShuttersControl::shutters->getStatus != 974 | $FHEM::Automation::ShuttersControl::shutters->getVentilatePos 975 | && $FHEM::Automation::ShuttersControl::shutters->getStatus != 976 | $FHEM::Automation::ShuttersControl::shutters->getAntiFreezePos 977 | && $FHEM::Automation::ShuttersControl::shutters->getLastDrive eq 978 | 'manual' ) 979 | { 980 | return 0; 981 | } 982 | elsif ( 983 | ( 984 | int( ::gettimeofday() ) - 985 | $FHEM::Automation::ShuttersControl::shutters->getLastManPosTimestamp 986 | ) < 987 | $FHEM::Automation::ShuttersControl::shutters->getBlockingTimeAfterManual 988 | ) 989 | { 990 | return 0; 991 | } 992 | 993 | else { return 1 } 994 | } 995 | 996 | sub IsWe { 997 | return main::IsWe( shift, shift ); 998 | } 999 | 1000 | sub AverageBrightness { 1001 | my @input = @_; 1002 | use List::Util qw(sum); 1003 | 1004 | return int( sum(@input) / @input ); 1005 | } 1006 | 1007 | sub PerlCodeCheck { 1008 | my $exec = shift; 1009 | my $val = undef; 1010 | 1011 | if ( $exec =~ m{\A\{(.+)\}\z}xms ) { 1012 | $val = main::AnalyzePerlCommand( undef, $1 ); 1013 | } 1014 | 1015 | return $val; 1016 | } 1017 | 1018 | sub IsAdv { 1019 | use HTTP::Date; 1020 | my ( undef, undef, undef, $monthday, $month, $year, undef, undef, undef ) = 1021 | localtime( ::gettimeofday() ); 1022 | my $adv = 0; 1023 | $year += 1900; 1024 | 1025 | if ( $month < 1 1026 | && $FHEM::Automation::ShuttersControl::ascDev->getAdvEndDate eq 1027 | 'EpiphanyDay' ) 1028 | { 1029 | $adv = $monthday < 7 ? 1 : 0; 1030 | } 1031 | elsif ($month < 2 1032 | && $FHEM::Automation::ShuttersControl::ascDev->getAdvEndDate eq 1033 | 'CandlemasDay' ) 1034 | { 1035 | $adv = $month = 1 || ( $month = 2 && $monthday < 3 ) ? 1 : 0; 1036 | } 1037 | else { 1038 | my $time = str2time( $year . '-12-25' ); 1039 | my $wday = ( localtime($time) )[6]; 1040 | $wday = $wday ? $wday : 7; 1041 | $time -= ( 1042 | $FHEM::Automation::ShuttersControl::ascDev->getAdvStartDate eq 1043 | 'DeadSunday' 1044 | ? ( $wday + 27 ) * 86400 1045 | : ( $wday + 21 ) * 86400 1046 | ); 1047 | $adv = 1 if ( $time < time ); 1048 | } 1049 | 1050 | return $adv; 1051 | } 1052 | 1053 | sub IsInTime { 1054 | my $dfi = shift; 1055 | 1056 | $dfi =~ s/{([^\x7d]*)}/$cmdFromAnalyze=$1; eval $1/ge; # Forum #69787 1057 | my ( $sec, $min, $hour, $mday, $month, $year, $wday, $yday, $isdst ) = 1058 | localtime( ::gettimeofday() ); 1059 | my $dhms = sprintf( "%s\@%02d:%02d:%02d", $wday, $hour, $min, $sec ); 1060 | foreach my $ft ( split( " ", $dfi ) ) { 1061 | my ( $from, $to ) = split( "-", $ft ); 1062 | if ( defined($from) && defined($to) ) { 1063 | $from = "$wday\@$from" if ( index( $from, "@" ) < 0 ); 1064 | $to = "$wday\@$to" if ( index( $to, "@" ) < 0 ); 1065 | return 1 if ( $from le $dhms && $dhms le $to ); 1066 | } 1067 | } 1068 | 1069 | return 0; 1070 | } 1071 | 1072 | 1; 1073 | -------------------------------------------------------------------------------- /lib/FHEM/Automation/ShuttersControl/Rainprotection.pm: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # Developed with VSCodium and richterger perl plugin 4 | # 5 | # (c) 2018-2025 Copyright: Marko Oldenburg (fhemdevelopment at cooltux dot net) 6 | # All rights reserved 7 | # 8 | # Special thanks goes to: 9 | # - Bernd (Cluni) this module is based on the logic of his script "Rollladensteuerung für HM/ROLLO inkl. Abschattung und Komfortfunktionen in Perl" (https://forum.fhem.de/index.php/topic,73964.0.html) 10 | # - Beta-User for many tests, many suggestions and good discussions 11 | # - pc1246 write english commandref 12 | # - FunkOdyssey commandref style 13 | # - sledge fix many typo in commandref 14 | # - many User that use with modul and report bugs 15 | # - Christoph (christoph.kaiser.in) Patch that expand RegEx for Window Events 16 | # - Julian (Loredo) expand Residents Events for new Residents functions 17 | # - Christoph (Christoph Morrison) for fix Commandref, many suggestions and good discussions 18 | # 19 | # 20 | # This script is free software; you can redistribute it and/or modify 21 | # it under the terms of the GNU General Public License as published by 22 | # the Free Software Foundation; either version 2 of the License,or 23 | # any later version. 24 | # 25 | # The GNU General Public License can be found at 26 | # http://www.gnu.org/copyleft/gpl.html. 27 | # A copy is found in the textfile GPL.txt and important notices to the license 28 | # from the author is found in LICENSE.txt distributed with these scripts. 29 | # 30 | # This script is distributed in the hope that it will be useful, 31 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 32 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 33 | # GNU General Public License for more details. 34 | # 35 | # 36 | # $Id$ 37 | # 38 | ############################################################################### 39 | 40 | ## unserer packagename 41 | package FHEM::Automation::ShuttersControl::Rainprotection; 42 | 43 | use strict; 44 | use warnings; 45 | use utf8; 46 | 47 | use FHEM::Automation::ShuttersControl::Helper qw (:ALL); 48 | 49 | require Exporter; 50 | use base qw(Exporter); 51 | 52 | # our @ISA = qw(Exporter); 53 | our @EXPORT_OK = qw( 54 | RainProcessing 55 | ); 56 | our %EXPORT_TAGS = ( 57 | ALL => [ 58 | qw( 59 | RainProcessing 60 | ) 61 | ], 62 | ); 63 | 64 | sub RainProcessing { 65 | my ( $hash, $val, $triggerMax, $triggerMin ) = @_; 66 | 67 | my $rainClosedPos = $FHEM::Automation::ShuttersControl::ascDev 68 | ->getRainSensorShuttersClosedPos; 69 | 70 | for my $shuttersDev ( @{ $hash->{helper}{shuttersList} } ) { 71 | $FHEM::Automation::ShuttersControl::shutters->setShuttersDev( 72 | $shuttersDev); 73 | 74 | next 75 | if ( 76 | $FHEM::Automation::ShuttersControl::shutters->getRainProtection eq 77 | 'off' ); 78 | 79 | if ( 80 | $val > $triggerMax 81 | && $FHEM::Automation::ShuttersControl::shutters->getStatus != 82 | $rainClosedPos 83 | && $FHEM::Automation::ShuttersControl::shutters 84 | ->getRainProtectionStatus eq 'unprotected' 85 | || ( $FHEM::Automation::ShuttersControl::shutters 86 | ->getRainProtectionStatus eq 'unprotected' 87 | && $FHEM::Automation::ShuttersControl::shutters 88 | ->getRainUnprotectionDelayObj ne 'none' ) 89 | ) 90 | { 91 | _RainProtected(); 92 | } 93 | elsif ( ( $val == 0 || $val < $triggerMin ) 94 | && $FHEM::Automation::ShuttersControl::shutters->getStatus == 95 | $rainClosedPos 96 | && IsAfterShuttersManualBlocking($shuttersDev) 97 | && $FHEM::Automation::ShuttersControl::shutters 98 | ->getRainProtectionStatus eq 'protected' ) 99 | { 100 | my %funcHash = ( shuttersdevice => $shuttersDev, ); 101 | 102 | $FHEM::Automation::ShuttersControl::shutters 103 | ->setRainUnprotectionDelayObj( \%funcHash ); 104 | ::InternalTimer( 105 | ::gettimeofday() + 106 | $FHEM::Automation::ShuttersControl::ascDev 107 | ->getRainWaitingTime, 108 | \&_RainUnprotected, \%funcHash 109 | ); 110 | 111 | $FHEM::Automation::ShuttersControl::shutters 112 | ->setRainProtectionStatus('unprotected'); 113 | } 114 | else { 115 | if ( $FHEM::Automation::ShuttersControl::shutters->getStatus != 116 | $rainClosedPos 117 | && ( $val == 0 || $val < $triggerMin ) ) 118 | { 119 | $FHEM::Automation::ShuttersControl::shutters 120 | ->setRainProtectionStatus('unprotected'); 121 | } 122 | elsif ( $val > $triggerMax ) { 123 | $FHEM::Automation::ShuttersControl::shutters 124 | ->setRainProtectionStatus('protected'); 125 | } 126 | } 127 | } 128 | 129 | return; 130 | } 131 | 132 | ### es muss noch beobachtet werden ob die Auswahl des Rollos welches bearbeitet werden soll bestehen bleibt oder mit in die neuen Funktionen übergeben werden muss 133 | sub _RainProtected { 134 | ::RemoveInternalTimer( $FHEM::Automation::ShuttersControl::shutters 135 | ->getRainUnprotectionDelayObj ) 136 | if ( $FHEM::Automation::ShuttersControl::shutters 137 | ->getRainUnprotectionDelayObj ne 'none' ); 138 | 139 | $FHEM::Automation::ShuttersControl::shutters->setRainUnprotectionDelayObj( 140 | 'none'); 141 | 142 | $FHEM::Automation::ShuttersControl::shutters->setLastDrive( 143 | 'rain protected'); 144 | 145 | $FHEM::Automation::ShuttersControl::shutters->setDriveCmd( 146 | $FHEM::Automation::ShuttersControl::ascDev 147 | ->getRainSensorShuttersClosedPos ); 148 | 149 | $FHEM::Automation::ShuttersControl::shutters->setRainProtectionStatus( 150 | 'protected'); 151 | 152 | return; 153 | } 154 | 155 | sub _RainUnprotected { 156 | my $h = shift; 157 | my $targetPos = $FHEM::Automation::ShuttersControl::shutters->getLastPos; 158 | 159 | my $shuttersDev = $h->{shuttersdevice}; 160 | $FHEM::Automation::ShuttersControl::shutters->setShuttersDev($shuttersDev); 161 | 162 | $FHEM::Automation::ShuttersControl::shutters->setLastDrive( 163 | 'rain un-protected'); 164 | 165 | if ( $FHEM::Automation::ShuttersControl::shutters 166 | ->getRainUnprotectionDelayObj ne 'none' ) 167 | { 168 | ::RemoveInternalTimer( $FHEM::Automation::ShuttersControl::shutters 169 | ->getRainUnprotectionDelayObj ); 170 | $FHEM::Automation::ShuttersControl::shutters 171 | ->setRainUnprotectionDelayObj('none'); 172 | } 173 | 174 | if ( $FHEM::Automation::ShuttersControl::shutters->getIsDay 175 | && !$FHEM::Automation::ShuttersControl::shutters->getIfInShading 176 | && $FHEM::Automation::ShuttersControl::shutters->getLastPos == 177 | $FHEM::Automation::ShuttersControl::shutters->getShadingPos ) 178 | { 179 | $targetPos = $FHEM::Automation::ShuttersControl::shutters->getOpenPos; 180 | } 181 | else { 182 | $targetPos = $FHEM::Automation::ShuttersControl::shutters->getLastPos; 183 | } 184 | 185 | if ( !$FHEM::Automation::ShuttersControl::shutters->getIsDay 186 | && $FHEM::Automation::ShuttersControl::shutters->getShuttersPlace ne 187 | 'awning' ) 188 | { 189 | $targetPos = ( 190 | $FHEM::Automation::ShuttersControl::shutters->getPrivacyDownStatus 191 | == 2 192 | ? $FHEM::Automation::ShuttersControl::shutters->getPrivacyDownPos 193 | : $FHEM::Automation::ShuttersControl::shutters->getClosedPos 194 | ); 195 | } 196 | 197 | $FHEM::Automation::ShuttersControl::shutters->setRainProtectionStatus( 198 | 'unprotected'); 199 | 200 | $FHEM::Automation::ShuttersControl::shutters->setDriveCmd($targetPos) 201 | if ( IsAfterShuttersTimeBlocking($shuttersDev) ); 202 | 203 | return; 204 | } 205 | 206 | 1; 207 | -------------------------------------------------------------------------------- /lib/FHEM/Automation/ShuttersControl/Roommate.pm: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # Developed with VSCodium and richterger perl plugin 4 | # 5 | # (c) 2018-2025 Copyright: Marko Oldenburg (fhemdevelopment at cooltux dot net) 6 | # All rights reserved 7 | # 8 | # Special thanks goes to: 9 | # - Bernd (Cluni) this module is based on the logic of his script "Rollladensteuerung für HM/ROLLO inkl. Abschattung und Komfortfunktionen in Perl" (https://forum.fhem.de/index.php/topic,73964.0.html) 10 | # - Beta-User for many tests, many suggestions and good discussions 11 | # - pc1246 write english commandref 12 | # - FunkOdyssey commandref style 13 | # - sledge fix many typo in commandref 14 | # - many User that use with modul and report bugs 15 | # - Christoph (christoph.kaiser.in) Patch that expand RegEx for Window Events 16 | # - Julian (Loredo) expand Residents Events for new Residents functions 17 | # - Christoph (Christoph Morrison) for fix Commandref, many suggestions and good discussions 18 | # 19 | # 20 | # This script is free software; you can redistribute it and/or modify 21 | # it under the terms of the GNU General Public License as published by 22 | # the Free Software Foundation; either version 2 of the License,or 23 | # any later version. 24 | # 25 | # The GNU General Public License can be found at 26 | # http://www.gnu.org/copyleft/gpl.html. 27 | # A copy is found in the textfile GPL.txt and important notices to the license 28 | # from the author is found in LICENSE.txt distributed with these scripts. 29 | # 30 | # This script is distributed in the hope that it will be useful, 31 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 32 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 33 | # GNU General Public License for more details. 34 | # 35 | # 36 | # $Id$ 37 | # 38 | ############################################################################### 39 | 40 | ## Klasse ASC_Roommate ## 41 | package FHEM::Automation::ShuttersControl::Roommate; 42 | 43 | use strict; 44 | use warnings; 45 | use utf8; 46 | 47 | require Exporter; 48 | use base qw(Exporter); 49 | 50 | # our @ISA = qw(Exporter); 51 | our @EXPORT_OK = qw( 52 | getRoommateStatus 53 | getRoommateLastStatus 54 | ); 55 | our %EXPORT_TAGS = ( 56 | ALL => [ 57 | qw( 58 | getRoommateStatus 59 | getRoommateLastStatus 60 | ) 61 | ], 62 | ); 63 | 64 | sub getRoommateStatus { 65 | my $self = shift; 66 | 67 | my $roommate = $self->{roommate}; 68 | 69 | return ::ReadingsVal( $roommate, 70 | $FHEM::Automation::ShuttersControl::shutters->getRoommatesReading, 71 | 'none' ); 72 | } 73 | 74 | sub getRoommateLastStatus { 75 | my $self = shift; 76 | 77 | my $roommate = $self->{roommate}; 78 | my $default = $self->{defaultarg}; 79 | 80 | $default = 'none' if ( !defined($default) ); 81 | return ::ReadingsVal( $roommate, 'lastState', $default ); 82 | } 83 | 84 | 1; 85 | -------------------------------------------------------------------------------- /lib/FHEM/Automation/ShuttersControl/Shading.pm: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # Developed with VSCodium and richterger perl plugin 4 | # 5 | # (c) 2018-2025 Copyright: Marko Oldenburg (fhemdevelopment at cooltux dot net) 6 | # All rights reserved 7 | # 8 | # Special thanks goes to: 9 | # - Bernd (Cluni) this module is based on the logic of his script "Rollladensteuerung für HM/ROLLO inkl. Abschattung und Komfortfunktionen in Perl" (https://forum.fhem.de/index.php/topic,73964.0.html) 10 | # - Beta-User for many tests, many suggestions and good discussions 11 | # - pc1246 write english commandref 12 | # - FunkOdyssey commandref style 13 | # - sledge fix many typo in commandref 14 | # - many User that use with modul and report bugs 15 | # - Christoph (christoph.kaiser.in) Patch that expand RegEx for Window Events 16 | # - Julian (Loredo) expand Residents Events for new Residents functions 17 | # - Christoph (Christoph Morrison) for fix Commandref, many suggestions and good discussions 18 | # 19 | # 20 | # This script is free software; you can redistribute it and/or modify 21 | # it under the terms of the GNU General Public License as published by 22 | # the Free Software Foundation; either version 2 of the License,or 23 | # any later version. 24 | # 25 | # The GNU General Public License can be found at 26 | # http://www.gnu.org/copyleft/gpl.html. 27 | # A copy is found in the textfile GPL.txt and important notices to the license 28 | # from the author is found in LICENSE.txt distributed with these scripts. 29 | # 30 | # This script is distributed in the hope that it will be useful, 31 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 32 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 33 | # GNU General Public License for more details. 34 | # 35 | # 36 | # $Id$ 37 | # 38 | ############################################################################### 39 | 40 | ## unserer packagename 41 | package FHEM::Automation::ShuttersControl::Shading; 42 | 43 | use strict; 44 | use warnings; 45 | use POSIX qw(strftime); 46 | use utf8; 47 | 48 | use FHEM::Automation::ShuttersControl::Helper qw (IsInTime); 49 | 50 | require Exporter; 51 | use base qw(Exporter); 52 | 53 | # our @ISA = qw(Exporter); 54 | our @EXPORT_OK = qw( 55 | CheckASC_ConditionsForShadingFn 56 | ShadingProcessing 57 | ShadingProcessingDriveCommand 58 | ); 59 | our %EXPORT_TAGS = ( 60 | ALL => [ 61 | qw( 62 | CheckASC_ConditionsForShadingFn 63 | ShadingProcessing 64 | ShadingProcessingDriveCommand 65 | ) 66 | ], 67 | ); 68 | 69 | sub CheckASC_ConditionsForShadingFn { 70 | my $hash = shift; 71 | my $value = shift; 72 | 73 | my $error; 74 | 75 | $error .= 76 | ' no valid data from the ASC temperature sensor, is ASC_tempSensor attribut set?' 77 | if ( $FHEM::Automation::ShuttersControl::ascDev->getOutTemp == -100 ); 78 | $error .= ' no twilight device found' 79 | if ( $FHEM::Automation::ShuttersControl::ascDev->_getTwilightDevice eq 80 | 'none' ); 81 | 82 | my $count = 1; 83 | for my $shuttersDev ( @{ $hash->{helper}{shuttersList} } ) { 84 | my %funcHash = ( 85 | hash => $hash, 86 | shuttersdevice => $shuttersDev, 87 | value => $value, 88 | attrEvent => 0, 89 | ); 90 | 91 | ::InternalTimer( 92 | ::gettimeofday() + $count, 93 | 'FHEM::Automation::ShuttersControl::Shading::_CheckShuttersConditionsForShadingFn', 94 | \%funcHash 95 | ); 96 | 97 | $count++; 98 | } 99 | 100 | return ( 101 | defined($error) 102 | ? $error 103 | : 'none' 104 | ); 105 | } 106 | 107 | sub _CheckShuttersConditionsForShadingFn { 108 | my $funcHash = shift; 109 | 110 | my $hash = $funcHash->{hash}; 111 | my $shuttersDev = $funcHash->{shuttersdevice}; 112 | my $value = $funcHash->{value}; 113 | 114 | $FHEM::Automation::ShuttersControl::shutters->setShuttersDev($shuttersDev); 115 | my $shuttersDevHash = $::defs{$shuttersDev}; 116 | my $message = ''; 117 | my $errorMessage; 118 | my $warnMessage; 119 | my $infoMessage; 120 | 121 | if ( $value eq 'off' ) { 122 | $FHEM::Automation::ShuttersControl::shutters->setShadingStatus('out'); 123 | $infoMessage .= ' shading was deactivated ' 124 | . ( $funcHash->{attrEvent} ? 'in the device' : 'globally' ); 125 | $errorMessage .= ''; 126 | ShadingProcessingDriveCommand( $hash, $shuttersDev ); 127 | } 128 | else { 129 | $infoMessage .= ( 130 | $FHEM::Automation::ShuttersControl::shutters->getShadingMode ne 131 | 'off' 132 | && $FHEM::Automation::ShuttersControl::ascDev 133 | ->getAutoShuttersControlShading eq 'on' 134 | && $FHEM::Automation::ShuttersControl::shutters->getOutTemp == 135 | -100 136 | ? ' shading active, global temp sensor is set, but shutters temperature sensor is not set' 137 | : '' 138 | ); 139 | 140 | $warnMessage .= ( 141 | $FHEM::Automation::ShuttersControl::shutters->getShadingMode eq 142 | 'off' 143 | && $FHEM::Automation::ShuttersControl::ascDev 144 | ->getAutoShuttersControlShading eq 'on' 145 | ? ' global shading active but ASC_Shading_Mode attribut is not set or off' 146 | : '' 147 | ); 148 | 149 | $errorMessage .= ( 150 | $FHEM::Automation::ShuttersControl::shutters->getShadingMode ne 151 | 'off' 152 | && $FHEM::Automation::ShuttersControl::ascDev 153 | ->getAutoShuttersControlShading ne 'on' 154 | && $FHEM::Automation::ShuttersControl::ascDev 155 | ->getAutoShuttersControlShading ne 'off' 156 | ? ' ASC_Shading_Mode attribut is set but global shading has errors, look at ASC device ' 157 | . '' 161 | . ::ReadingsVal( $shuttersDev, 'associatedWith', 'ASC device' ) 162 | . '' 163 | : '' 164 | ); 165 | 166 | $errorMessage .= ( 167 | $FHEM::Automation::ShuttersControl::shutters->getBrightness == -1 168 | && $FHEM::Automation::ShuttersControl::shutters->getShadingMode 169 | ne 'off' 170 | ? ' no brightness sensor found, please set ASC_BrightnessSensor attribut' 171 | : '' 172 | ); 173 | } 174 | 175 | $message .= ' ERROR: ' . $errorMessage 176 | if ( defined($errorMessage) 177 | && $errorMessage ne '' ); 178 | 179 | $message .= ' WARN: ' . $warnMessage 180 | if ( defined($warnMessage) 181 | && $warnMessage ne '' 182 | && $errorMessage eq '' ); 183 | 184 | $message .= ' INFO: ' . $infoMessage 185 | if ( defined($infoMessage) 186 | && $infoMessage ne '' 187 | && $errorMessage eq '' ); 188 | 189 | ::readingsBeginUpdate($shuttersDevHash); 190 | ::readingsBulkUpdateIfChanged( $shuttersDevHash, 'ASC_ShadingMessage', 191 | '' . $message . ' ' ); 192 | ::readingsEndUpdate( $shuttersDevHash, 1 ); 193 | 194 | return; 195 | } 196 | 197 | sub ShadingProcessing { 198 | ### angleMinus ist $FHEM::Automation::ShuttersControl::shutters->getShadingAzimuthLeft 199 | ### anglePlus ist $FHEM::Automation::ShuttersControl::shutters->getShadingAzimuthRight 200 | ### winPos ist die Fensterposition $FHEM::Automation::ShuttersControl::shutters->getDirection 201 | my ( $hash, $shuttersDev, $azimuth, $elevation, $outTemp, 202 | $azimuthLeft, $azimuthRight ) 203 | = @_; 204 | 205 | my $name = $hash->{NAME}; 206 | $FHEM::Automation::ShuttersControl::shutters->setShuttersDev($shuttersDev); 207 | my $brightness = 208 | $FHEM::Automation::ShuttersControl::shutters->getBrightnessAverage; 209 | 210 | $FHEM::Automation::ShuttersControl::shutters 211 | ->setShadingBetweenTheTimeSuspend( 212 | ( 213 | IsInTime( 214 | $FHEM::Automation::ShuttersControl::shutters 215 | ->getShadingBetweenTheTime 216 | ) 217 | ? 0 218 | : 1 219 | ) 220 | ); 221 | 222 | FHEM::Automation::ShuttersControl::ASC_Debug( 223 | 'ShadingProcessing: ' 224 | . $FHEM::Automation::ShuttersControl::shutters->getShuttersDev 225 | . ' - Übergebende Werte - Azimuth:' 226 | . $azimuth 227 | . ', Elevation: ' 228 | . $elevation 229 | . ', Brightness: ' 230 | . $brightness 231 | . ', OutTemp: ' 232 | . $outTemp 233 | . ', Azimut Beschattung: ' 234 | . $azimuthLeft 235 | . ', Azimut Endschattung: ' 236 | . $azimuthRight 237 | . ', Ist es nach der Zeitblockadezeit: ' 238 | . ( 239 | FHEM::Automation::ShuttersControl::Helper::IsAfterShuttersTimeBlocking( 240 | $shuttersDev) ? 'JA' : 'NEIN' 241 | ) 242 | . ', Das Rollo ist in der Beschattung und wurde manuell gefahren: ' 243 | . ( 244 | $FHEM::Automation::ShuttersControl::shutters 245 | ->getShadingManualDriveStatus ? 'JA' : 'NEIN' 246 | ) 247 | . ', Ist es nach der Hälfte der Beschattungswartezeit: ' 248 | . ( 249 | ( 250 | int( ::gettimeofday() ) - 251 | $FHEM::Automation::ShuttersControl::shutters 252 | ->getShadingStatusTimestamp 253 | ) < ( 254 | $FHEM::Automation::ShuttersControl::shutters 255 | ->getShadingWaitingPeriod / 2 256 | ) ? 'NEIN' : 'JA' 257 | ) 258 | ); 259 | 260 | ::Log3( $name, 4, 261 | "AutoShuttersControl ($name) - Shading Processing, Rollladen: " 262 | . $shuttersDev 263 | . " Azimuth: " 264 | . $azimuth 265 | . " Elevation: " 266 | . $elevation 267 | . " Brightness: " 268 | . $brightness 269 | . " OutTemp: " 270 | . $outTemp ); 271 | 272 | return 273 | if ( 274 | $azimuth == -1 275 | || $elevation == -1 276 | || $brightness == -1 277 | || $outTemp == -100 278 | || ( 279 | int( ::gettimeofday() ) - 280 | $FHEM::Automation::ShuttersControl::shutters 281 | ->getShadingStatusTimestamp ) < ( 282 | $FHEM::Automation::ShuttersControl::shutters 283 | ->getShadingWaitingPeriod / 2 284 | ) 285 | || $FHEM::Automation::ShuttersControl::shutters 286 | ->getExternalTriggerStatus 287 | || $FHEM::Automation::ShuttersControl::shutters->getShadingMode eq 'off' 288 | || $FHEM::Automation::ShuttersControl::ascDev 289 | ->getAutoShuttersControlShading eq 'off' 290 | || $FHEM::Automation::ShuttersControl::shutters 291 | ->getExternalTriggerStatus 292 | ); 293 | 294 | ::Log3( $name, 4, 295 | "AutoShuttersControl ($name) - Shading Processing, Rollladen: " 296 | . $shuttersDev 297 | . " Nach dem return" ); 298 | 299 | my $getShadingPos = 300 | $FHEM::Automation::ShuttersControl::shutters->getShadingPos; 301 | my $getStatus = $FHEM::Automation::ShuttersControl::shutters->getStatus; 302 | my $oldShadingStatus = 303 | $FHEM::Automation::ShuttersControl::shutters->getShadingStatus; 304 | my $shuttersDevHash = $::defs{$shuttersDev}; 305 | 306 | my $getModeUp = $FHEM::Automation::ShuttersControl::shutters->getModeUp; 307 | my $homemode = $FHEM::Automation::ShuttersControl::shutters->getHomemode; 308 | 309 | FHEM::Automation::ShuttersControl::ASC_Debug( 'ShadingProcessing: ' 310 | . $FHEM::Automation::ShuttersControl::shutters->getShuttersDev 311 | . ' - Alle Werte für die weitere Verarbeitung sind korrekt vorhanden und es wird nun mit der Beschattungsverarbeitung begonnen' 312 | ); 313 | 314 | if ( 315 | ( 316 | $outTemp < $FHEM::Automation::ShuttersControl::shutters 317 | ->getShadingMinOutsideTemperature - 4 318 | || $azimuth < $azimuthLeft 319 | || $azimuth > $azimuthRight 320 | || ( !$FHEM::Automation::ShuttersControl::shutters->getIsDay 321 | && $FHEM::Automation::ShuttersControl::shutters 322 | ->getSunriseUnixTime - ( int( ::gettimeofday() ) ) > 7200 ) 323 | ) 324 | && $FHEM::Automation::ShuttersControl::shutters->getShadingStatus ne 325 | 'out' 326 | ) 327 | { 328 | $FHEM::Automation::ShuttersControl::shutters->setShadingStatus('out'); 329 | 330 | FHEM::Automation::ShuttersControl::ASC_Debug( 'ShadingProcessing: ' 331 | . $FHEM::Automation::ShuttersControl::shutters->getShuttersDev 332 | . ' - Es ist Nacht oder die Aussentemperatur unterhalb der Shading Temperatur. Die Beschattung wird Zwangsbeendet' 333 | ); 334 | 335 | ::Log3( $name, 4, 336 | "AutoShuttersControl ($name) - Shading Processing - Der Sonnenstand ist ausserhalb der Winkelangaben oder die Aussentemperatur unterhalb der Shading Temperatur " 337 | ); 338 | } 339 | elsif ($azimuth < $azimuthLeft 340 | || $azimuth > $azimuthRight 341 | || $elevation < 342 | $FHEM::Automation::ShuttersControl::shutters->getShadingMinElevation 343 | || $elevation > 344 | $FHEM::Automation::ShuttersControl::shutters->getShadingMaxElevation 345 | || $brightness < $FHEM::Automation::ShuttersControl::shutters 346 | ->getShadingStateChangeCloudy 347 | || $outTemp < $FHEM::Automation::ShuttersControl::shutters 348 | ->getShadingMinOutsideTemperature - 1 ) 349 | { 350 | $FHEM::Automation::ShuttersControl::shutters->setShadingStatus( 351 | 'out reserved') 352 | if ( $FHEM::Automation::ShuttersControl::shutters->getShadingStatus eq 353 | 'in' 354 | || $FHEM::Automation::ShuttersControl::shutters->getShadingStatus 355 | eq 'in reserved' ); 356 | 357 | if ( 358 | ( 359 | $FHEM::Automation::ShuttersControl::shutters->getShadingStatus 360 | eq 'out reserved' 361 | and ( 362 | int( ::gettimeofday() ) - 363 | $FHEM::Automation::ShuttersControl::shutters 364 | ->getShadingStatusTimestamp ) 365 | ) > $FHEM::Automation::ShuttersControl::shutters 366 | ->getShadingWaitingPeriod 367 | ) 368 | { 369 | $FHEM::Automation::ShuttersControl::shutters->setShadingStatus( 370 | 'out'); 371 | } 372 | 373 | ::Log3( $name, 4, 374 | "AutoShuttersControl ($name) - Shading Processing, Rollladen: " 375 | . $shuttersDev 376 | . " In der Out Abfrage, Shadingwert: " 377 | . $FHEM::Automation::ShuttersControl::shutters->getShadingStatus 378 | . ", Zeitstempel: " 379 | . $FHEM::Automation::ShuttersControl::shutters 380 | ->getShadingStatusTimestamp ); 381 | 382 | FHEM::Automation::ShuttersControl::ASC_Debug( 'ShadingProcessing: ' 383 | . $FHEM::Automation::ShuttersControl::shutters->getShuttersDev 384 | . ' - Einer der Beschattungsbedingungen wird nicht mehr erfüllt und somit wird der Beschattungsstatus um eine Stufe reduziert. Alter Status: ' 385 | . $oldShadingStatus 386 | . ' Neuer Status: ' 387 | . $FHEM::Automation::ShuttersControl::shutters->getShadingStatus 388 | ); 389 | } 390 | elsif ($azimuth > $azimuthLeft 391 | && $azimuth < $azimuthRight 392 | && $elevation > 393 | $FHEM::Automation::ShuttersControl::shutters->getShadingMinElevation 394 | && $elevation < 395 | $FHEM::Automation::ShuttersControl::shutters->getShadingMaxElevation 396 | && $brightness > 397 | $FHEM::Automation::ShuttersControl::shutters->getShadingStateChangeSunny 398 | && $outTemp > $FHEM::Automation::ShuttersControl::shutters 399 | ->getShadingMinOutsideTemperature ) 400 | { 401 | if ( $FHEM::Automation::ShuttersControl::shutters->getShadingStatus eq 402 | 'out' 403 | || $FHEM::Automation::ShuttersControl::shutters->getShadingStatus 404 | eq 'out reserved' ) 405 | { 406 | $FHEM::Automation::ShuttersControl::shutters->setShadingStatus( 407 | 'in reserved'); 408 | 409 | } 410 | 411 | if ( 412 | $FHEM::Automation::ShuttersControl::shutters->getShadingStatus eq 413 | 'in reserved' 414 | and ( 415 | int( ::gettimeofday() ) - 416 | $FHEM::Automation::ShuttersControl::shutters 417 | ->getShadingStatusTimestamp ) > ( 418 | $FHEM::Automation::ShuttersControl::shutters 419 | ->getShadingWaitingPeriod / 2 420 | ) 421 | ) 422 | { 423 | $FHEM::Automation::ShuttersControl::shutters->setShadingStatus( 424 | 'in'); 425 | } 426 | 427 | ::Log3( $name, 4, 428 | "AutoShuttersControl ($name) - Shading Processing, Rollladen: " 429 | . $shuttersDev 430 | . " In der In Abfrage, Shadingwert: " 431 | . $FHEM::Automation::ShuttersControl::shutters->getShadingStatus 432 | . ", Zeitstempel: " 433 | . $FHEM::Automation::ShuttersControl::shutters 434 | ->getShadingStatusTimestamp ); 435 | 436 | FHEM::Automation::ShuttersControl::ASC_Debug( 'ShadingProcessing: ' 437 | . $FHEM::Automation::ShuttersControl::shutters->getShuttersDev 438 | . ' - Alle Beschattungsbedingungen wurden erfüllt und somit wird der Beschattungsstatus um eine Stufe angehoben. Alter Status: ' 439 | . $oldShadingStatus 440 | . ' Neuer Status: ' 441 | . $FHEM::Automation::ShuttersControl::shutters->getShadingStatus 442 | ); 443 | } 444 | 445 | ShadingProcessingDriveCommand( $hash, $shuttersDev ) 446 | if ( 447 | FHEM::Automation::ShuttersControl::Helper::IsAfterShuttersTimeBlocking( 448 | $shuttersDev) 449 | && !$FHEM::Automation::ShuttersControl::shutters 450 | ->getShadingManualDriveStatus 451 | && $FHEM::Automation::ShuttersControl::shutters->getRoommatesStatus ne 452 | 'gotosleep' 453 | && $FHEM::Automation::ShuttersControl::shutters->getRoommatesStatus ne 454 | 'asleep' 455 | && ( 456 | ( 457 | $FHEM::Automation::ShuttersControl::shutters->getShadingStatus 458 | eq 'out' 459 | && $FHEM::Automation::ShuttersControl::shutters 460 | ->getShadingLastStatus eq 'in' 461 | ) 462 | || ( $FHEM::Automation::ShuttersControl::shutters->getShadingStatus 463 | eq 'in' 464 | && $FHEM::Automation::ShuttersControl::shutters 465 | ->getShadingLastStatus eq 'out' ) 466 | ) 467 | && ( $FHEM::Automation::ShuttersControl::shutters->getShadingMode eq 468 | 'always' 469 | || $FHEM::Automation::ShuttersControl::shutters->getShadingMode eq 470 | $homemode ) 471 | && ( 472 | $getModeUp eq 'always' 473 | || $getModeUp eq $homemode 474 | || $getModeUp eq 'off' 475 | || $getModeUp eq 'absent' 476 | || $getModeUp eq 'gone' 477 | || ( $getModeUp eq 'home' 478 | && $homemode ne 'asleep' ) 479 | ) 480 | && ( 481 | ( 482 | ( 483 | int( ::gettimeofday() ) - 484 | $FHEM::Automation::ShuttersControl::shutters 485 | ->getShadingStatusTimestamp 486 | ) < 2 487 | && $FHEM::Automation::ShuttersControl::shutters->getStatus != 488 | $FHEM::Automation::ShuttersControl::shutters->getClosedPos 489 | ) 490 | || ( 491 | !$FHEM::Automation::ShuttersControl::shutters 492 | ->getQueryShuttersPos( 493 | $FHEM::Automation::ShuttersControl::shutters->getShadingPos 494 | ) 495 | && $FHEM::Automation::ShuttersControl::shutters->getIfInShading 496 | ) 497 | || ( !$FHEM::Automation::ShuttersControl::shutters->getIfInShading 498 | && $FHEM::Automation::ShuttersControl::shutters->getStatus == 499 | $FHEM::Automation::ShuttersControl::shutters->getShadingPos ) 500 | || ( !$FHEM::Automation::ShuttersControl::shutters 501 | ->getShadingBetweenTheTimeSuspend 502 | && $FHEM::Automation::ShuttersControl::shutters->getStatus != 503 | $FHEM::Automation::ShuttersControl::shutters->getShadingPos ) 504 | ) 505 | ); 506 | 507 | ::readingsBeginUpdate($shuttersDevHash); 508 | ::readingsBulkUpdate( 509 | $shuttersDevHash, 510 | 'ASC_ShadingMessage', 511 | 'INFO: current shading status is \'' 512 | . $FHEM::Automation::ShuttersControl::shutters->getShadingStatus 513 | . '\'' 514 | . ' - next check in ' 515 | . ( 516 | ( 517 | ( 518 | $FHEM::Automation::ShuttersControl::shutters 519 | ->getShadingLastStatus eq 'out reserved' 520 | || $FHEM::Automation::ShuttersControl::shutters 521 | ->getShadingLastStatus eq 'out' 522 | ) 523 | ? $FHEM::Automation::ShuttersControl::shutters 524 | ->getShadingWaitingPeriod 525 | : $FHEM::Automation::ShuttersControl::shutters 526 | ->getShadingWaitingPeriod / 2 527 | ) 528 | ) / 60 529 | . 'm' 530 | ); 531 | ::readingsEndUpdate( $shuttersDevHash, 1 ); 532 | 533 | return; 534 | } 535 | 536 | sub ShadingProcessingDriveCommand { 537 | my $hash = shift; 538 | my $shuttersDev = shift; 539 | my $marker = shift // 0; 540 | 541 | my $name = $hash->{NAME}; 542 | $FHEM::Automation::ShuttersControl::shutters->setShuttersDev($shuttersDev); 543 | 544 | my $getShadingPos = 545 | $FHEM::Automation::ShuttersControl::shutters->getShadingPos; 546 | my $getStatus = $FHEM::Automation::ShuttersControl::shutters->getStatus; 547 | 548 | $FHEM::Automation::ShuttersControl::shutters->setShadingStatus( 549 | $FHEM::Automation::ShuttersControl::shutters->getShadingStatus ); 550 | 551 | if ( 552 | IsInTime( 553 | $FHEM::Automation::ShuttersControl::shutters 554 | ->getShadingBetweenTheTime 555 | ) 556 | && $FHEM::Automation::ShuttersControl::shutters->getShadingStatus eq 557 | 'in' 558 | && $getShadingPos != $getStatus 559 | && ( 560 | $getStatus != 561 | $FHEM::Automation::ShuttersControl::shutters->getClosedPos 562 | || ( $getStatus == 563 | $FHEM::Automation::ShuttersControl::shutters->getClosedPos 564 | && $marker ) 565 | ) 566 | && ( 567 | $getStatus != 568 | $FHEM::Automation::ShuttersControl::shutters->getSleepPos 569 | || ( $getStatus == 570 | $FHEM::Automation::ShuttersControl::shutters->getSleepPos 571 | && $marker ) 572 | ) 573 | && ( 574 | FHEM::Automation::ShuttersControl::CheckIfShuttersWindowRecOpen( 575 | $shuttersDev) != 2 576 | || $FHEM::Automation::ShuttersControl::shutters->getShuttersPlace 577 | ne 'terrace' 578 | ) 579 | ) 580 | { 581 | $FHEM::Automation::ShuttersControl::shutters->setLastDrive( 582 | 'shading in'); 583 | FHEM::Automation::ShuttersControl::ShuttersCommandSet( $hash, 584 | $shuttersDev, $getShadingPos ); 585 | 586 | FHEM::Automation::ShuttersControl::ASC_Debug( 587 | 'ShadingProcessingDriveCommand: ' 588 | . $FHEM::Automation::ShuttersControl::shutters->getShuttersDev 589 | . ' - Der aktuelle Beschattungsstatus ist: ' 590 | . $FHEM::Automation::ShuttersControl::shutters->getShadingStatus 591 | . ' und somit wird nun in die Position: ' 592 | . $getShadingPos 593 | . ' zum Beschatten gefahren' ); 594 | 595 | $FHEM::Automation::ShuttersControl::shutters->setShadingLastPos( 596 | $getShadingPos); 597 | } 598 | elsif ( 599 | $FHEM::Automation::ShuttersControl::shutters->getShadingStatus eq 'out' 600 | && $getShadingPos == $getStatus ) 601 | { 602 | $FHEM::Automation::ShuttersControl::shutters->setLastDrive( 603 | 'shading out'); 604 | 605 | FHEM::Automation::ShuttersControl::ShuttersCommandSet( 606 | $hash, 607 | $shuttersDev, 608 | ( 609 | ( 610 | $getShadingPos == 611 | $FHEM::Automation::ShuttersControl::shutters->getLastPos 612 | || $getShadingPos == 613 | $FHEM::Automation::ShuttersControl::shutters 614 | ->getShadingLastPos 615 | ) 616 | ? $FHEM::Automation::ShuttersControl::shutters->getOpenPos 617 | : ( 618 | $FHEM::Automation::ShuttersControl::shutters 619 | ->getQueryShuttersPos( 620 | $FHEM::Automation::ShuttersControl::shutters->getLastPos 621 | ) 622 | ? ( 623 | $FHEM::Automation::ShuttersControl::shutters 624 | ->getLastPos == 625 | $FHEM::Automation::ShuttersControl::shutters 626 | ->getSleepPos 627 | ? $FHEM::Automation::ShuttersControl::shutters 628 | ->getOpenPos 629 | : $FHEM::Automation::ShuttersControl::shutters 630 | ->getLastPos 631 | ) 632 | : $FHEM::Automation::ShuttersControl::shutters->getOpenPos 633 | ) 634 | ) 635 | ) 636 | if ( $FHEM::Automation::ShuttersControl::shutters->getIsDay 637 | || $FHEM::Automation::ShuttersControl::shutters->getShuttersPlace 638 | eq 'awning' ); 639 | 640 | FHEM::Automation::ShuttersControl::ASC_Debug( 641 | 'ShadingProcessingDriveCommand: ' 642 | . $FHEM::Automation::ShuttersControl::shutters->getShuttersDev 643 | . ' - Der aktuelle Beschattungsstatus ist: ' 644 | . $FHEM::Automation::ShuttersControl::shutters->getShadingStatus 645 | . ' und somit wird nun in die Position: ' 646 | . $getShadingPos 647 | . ' zum beenden der Beschattung gefahren' ); 648 | } 649 | 650 | ::Log3( $name, 4, 651 | "AutoShuttersControl ($name) - Shading Processing - In der Routine zum fahren der Rollläden, Shading Wert: " 652 | . $FHEM::Automation::ShuttersControl::shutters->getShadingStatus ); 653 | 654 | FHEM::Automation::ShuttersControl::ASC_Debug( 655 | 'ShadingProcessingDriveCommand: ' 656 | . $FHEM::Automation::ShuttersControl::shutters->getShuttersDev 657 | . ' - Der aktuelle Beschattungsstatus ist: ' 658 | . $FHEM::Automation::ShuttersControl::shutters->getShadingStatus 659 | . ', Beschattungsstatus Zeitstempel: ' 660 | . strftime( 661 | "%Y.%m.%d %T", 662 | localtime( 663 | $FHEM::Automation::ShuttersControl::shutters 664 | ->getShadingStatusTimestamp 665 | ) 666 | ) 667 | ); 668 | 669 | return; 670 | } 671 | 672 | 1; 673 | -------------------------------------------------------------------------------- /lib/FHEM/Automation/ShuttersControl/Shutters.pm: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # Developed with VSCodium and richterger perl plugin 4 | # 5 | # (c) 2018-2025 Copyright: Marko Oldenburg (fhemdevelopment at cooltux dot net) 6 | # All rights reserved 7 | # 8 | # Special thanks goes to: 9 | # - Bernd (Cluni) this module is based on the logic of his script "Rollladensteuerung für HM/ROLLO inkl. Abschattung und Komfortfunktionen in Perl" (https://forum.fhem.de/index.php/topic,73964.0.html) 10 | # - Beta-User for many tests, many suggestions and good discussions 11 | # - pc1246 write english commandref 12 | # - FunkOdyssey commandref style 13 | # - sledge fix many typo in commandref 14 | # - many User that use with modul and report bugs 15 | # - Christoph (christoph.kaiser.in) Patch that expand RegEx for Window Events 16 | # - Julian (Loredo) expand Residents Events for new Residents functions 17 | # - Christoph (Christoph Morrison) for fix Commandref, many suggestions and good discussions 18 | # 19 | # 20 | # This script is free software; you can redistribute it and/or modify 21 | # it under the terms of the GNU General Public License as published by 22 | # the Free Software Foundation; either version 2 of the License,or 23 | # any later version. 24 | # 25 | # The GNU General Public License can be found at 26 | # http://www.gnu.org/copyleft/gpl.html. 27 | # A copy is found in the textfile GPL.txt and important notices to the license 28 | # from the author is found in LICENSE.txt distributed with these scripts. 29 | # 30 | # This script is distributed in the hope that it will be useful, 31 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 32 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 33 | # GNU General Public License for more details. 34 | # 35 | # 36 | # $Id$ 37 | # 38 | ############################################################################### 39 | 40 | ###################################### 41 | ###################################### 42 | ########## Begin der Klassendeklarierungen für OOP (Objektorientierte Programmierung) ######################### 43 | ## Klasse Rolläden (Shutters) und die Subklassen Attr und Readings ## 44 | ## desweiteren wird noch die Klasse ASC_Roommate mit eingebunden 45 | 46 | package FHEM::Automation::ShuttersControl::Shutters; 47 | 48 | use strict; 49 | use warnings; 50 | use utf8; 51 | 52 | use FHEM::Automation::ShuttersControl::Shutters::Readings; 53 | use FHEM::Automation::ShuttersControl::Shutters::Attr; 54 | use FHEM::Automation::ShuttersControl::Roommate qw (:ALL); 55 | use FHEM::Automation::ShuttersControl::Window; 56 | 57 | use base 58 | qw(FHEM::Automation::ShuttersControl::Shutters::Readings FHEM::Automation::ShuttersControl::Shutters::Attr FHEM::Automation::ShuttersControl::Roommate FHEM::Automation::ShuttersControl::Window); 59 | 60 | sub new { 61 | my $class = shift; 62 | my $self = { 63 | shuttersDev => undef, 64 | defaultarg => undef, 65 | roommate => undef, 66 | }; 67 | 68 | bless $self, $class; 69 | return $self; 70 | } 71 | 72 | sub setShuttersDev { 73 | my $self = shift; 74 | my $shuttersDev = shift; 75 | 76 | $self->{shuttersDev} = $shuttersDev if ( defined($shuttersDev) ); 77 | return $self->{shuttersDev}; 78 | } 79 | 80 | sub getShuttersDev { 81 | my $self = shift; 82 | 83 | return $self->{shuttersDev}; 84 | } 85 | 86 | sub setAttrUpdateChanges { 87 | my ( $self, $attr, $value ) = @_; 88 | 89 | $self->{ $self->{shuttersDev} }{AttrUpdateChanges}{$attr} = $value; 90 | return; 91 | } 92 | 93 | sub setHardLockOut { 94 | my $self = shift; 95 | my $cmd = shift; 96 | 97 | if ( $FHEM::Automation::ShuttersControl::shutters->getLockOut eq 'hard' 98 | && $FHEM::Automation::ShuttersControl::shutters->getLockOutCmd ne 99 | 'none' ) 100 | { 101 | ::CommandSet( undef, $self->{shuttersDev} . ' inhibit ' . $cmd ) 102 | if ( $FHEM::Automation::ShuttersControl::shutters->getLockOutCmd eq 103 | 'inhibit' ); 104 | ::CommandSet( undef, 105 | $self->{shuttersDev} . ' ' 106 | . ( $cmd eq 'on' ? 'blocked' : 'unblocked' ) ) 107 | if ( $FHEM::Automation::ShuttersControl::shutters->getLockOutCmd eq 108 | 'blocked' ); 109 | ::CommandSet( undef, 110 | $self->{shuttersDev} . ' ' 111 | . ( $cmd eq 'on' ? 'protectionOn' : 'protectionOff' ) ) 112 | if ( $FHEM::Automation::ShuttersControl::shutters->getLockOutCmd eq 113 | 'protected' ); 114 | } 115 | return; 116 | } 117 | 118 | sub setNoDelay { 119 | my $self = shift; 120 | my $noDelay = shift; 121 | 122 | $self->{ $self->{shuttersDev} }{noDelay} = $noDelay; 123 | return; 124 | } 125 | 126 | sub setSelfDefenseAbsent { 127 | my ( $self, $timerrun, $active, $timerhash ) = @_; 128 | 129 | $self->{ $self->{shuttersDev} }{selfDefenseAbsent}{timerrun} = $timerrun; 130 | $self->{ $self->{shuttersDev} }{selfDefenseAbsent}{active} = $active; 131 | $self->{ $self->{shuttersDev} }{selfDefenseAbsent}{timerhash} = $timerhash 132 | if ( defined($timerhash) ); 133 | return; 134 | } 135 | 136 | sub setDriveCmd { 137 | my $self = shift; 138 | my $posValue = shift; 139 | 140 | my $offSet; 141 | my $offSetStart; 142 | 143 | if ( 144 | ( 145 | $FHEM::Automation::ShuttersControl::shutters->getPartyMode eq 'on' 146 | && $FHEM::Automation::ShuttersControl::ascDev->getPartyMode eq 'on' 147 | ) 148 | || ( 149 | $FHEM::Automation::ShuttersControl::shutters->getAdv 150 | && !$FHEM::Automation::ShuttersControl::shutters 151 | ->getQueryShuttersPos( 152 | $posValue) 153 | && !$FHEM::Automation::ShuttersControl::shutters->getAdvDelay 154 | && !$FHEM::Automation::ShuttersControl::shutters 155 | ->getExternalTriggerStatus 156 | && !$FHEM::Automation::ShuttersControl::shutters 157 | ->getSelfDefenseState 158 | ) 159 | ) 160 | { 161 | $FHEM::Automation::ShuttersControl::shutters->setDelayCmd($posValue); 162 | $FHEM::Automation::ShuttersControl::ascDev->setDelayCmdReading; 163 | $FHEM::Automation::ShuttersControl::shutters->setNoDelay(0); 164 | 165 | FHEM::Automation::ShuttersControl::ASC_Debug( 'setDriveCmd: ' 166 | . $FHEM::Automation::ShuttersControl::shutters->getShuttersDev 167 | . ' - Die Fahrt wird zurückgestellt. Grund kann ein geöffnetes Fenster sein oder ein aktivierter Party Modus oder Weihnachtszeit' 168 | ); 169 | } 170 | else { 171 | $FHEM::Automation::ShuttersControl::shutters->setAdvDelay(0) 172 | if ( $FHEM::Automation::ShuttersControl::shutters->getAdvDelay ); 173 | $FHEM::Automation::ShuttersControl::shutters->setDelayCmd('none') 174 | if ( $FHEM::Automation::ShuttersControl::shutters->getDelayCmd ne 175 | 'none' ) 176 | ; # setzt den Wert auf none da der Rolladen nun gesteuert werden kann. 177 | $FHEM::Automation::ShuttersControl::shutters->setExternalTriggerStatus( 178 | 0) 179 | if ( $FHEM::Automation::ShuttersControl::shutters 180 | ->getExternalTriggerStatus ); 181 | 182 | ### antifreeze Routine 183 | if ( $FHEM::Automation::ShuttersControl::shutters->getAntiFreezeStatus > 184 | 0 ) 185 | { 186 | if ( $FHEM::Automation::ShuttersControl::shutters 187 | ->getAntiFreezeStatus != 1 ) 188 | { 189 | 190 | $posValue = 191 | $FHEM::Automation::ShuttersControl::shutters->getStatus; 192 | $FHEM::Automation::ShuttersControl::shutters->setLastDrive( 193 | 'no drive - antifreeze defense'); 194 | $FHEM::Automation::ShuttersControl::shutters 195 | ->setLastDriveReading; 196 | $FHEM::Automation::ShuttersControl::ascDev->setStateReading; 197 | } 198 | elsif ( $posValue == 199 | $FHEM::Automation::ShuttersControl::shutters->getClosedPos ) 200 | { 201 | $posValue = $FHEM::Automation::ShuttersControl::shutters 202 | ->getAntiFreezePos; 203 | $FHEM::Automation::ShuttersControl::shutters->setLastDrive( 204 | $FHEM::Automation::ShuttersControl::shutters->getLastDrive 205 | . ' - antifreeze mode' ); 206 | } 207 | } 208 | 209 | my %h = ( 210 | shuttersDev => $self->{shuttersDev}, 211 | posValue => $posValue, 212 | ); 213 | 214 | $offSet = $FHEM::Automation::ShuttersControl::shutters->getDelay 215 | if ( $FHEM::Automation::ShuttersControl::shutters->getDelay > -1 ); 216 | $offSet = $FHEM::Automation::ShuttersControl::ascDev->getShuttersOffset 217 | if ( $FHEM::Automation::ShuttersControl::shutters->getDelay < 0 ); 218 | $offSetStart = 219 | $FHEM::Automation::ShuttersControl::shutters->getDelayStart; 220 | 221 | if ( $FHEM::Automation::ShuttersControl::shutters->getSelfDefenseAbsent 222 | && !$FHEM::Automation::ShuttersControl::shutters 223 | ->getSelfDefenseAbsentTimerrun 224 | && $FHEM::Automation::ShuttersControl::shutters->getSelfDefenseMode 225 | ne 'off' 226 | && $FHEM::Automation::ShuttersControl::shutters->getSelfDefenseState 227 | && $FHEM::Automation::ShuttersControl::ascDev->getSelfDefense eq 228 | 'on' ) 229 | { 230 | ::InternalTimer( 231 | ::gettimeofday() + 232 | $FHEM::Automation::ShuttersControl::shutters 233 | ->getSelfDefenseAbsentDelay, 234 | \&FHEM::Automation::ShuttersControl::SetCmdFn, \%h 235 | ); 236 | $FHEM::Automation::ShuttersControl::shutters->setSelfDefenseAbsent( 237 | 1, 0, \%h ); 238 | } 239 | elsif ( $offSetStart > 0 240 | && !$FHEM::Automation::ShuttersControl::shutters->getNoDelay ) 241 | { 242 | ::InternalTimer( 243 | ::gettimeofday() + int( 244 | rand($offSet) + 245 | $FHEM::Automation::ShuttersControl::shutters 246 | ->getDelayStart 247 | ), 248 | \&FHEM::Automation::ShuttersControl::SetCmdFn, 249 | \%h 250 | ); 251 | 252 | FHEM::Automation::ShuttersControl::ASC_Debug( 'FnSetDriveCmd: ' 253 | . $FHEM::Automation::ShuttersControl::shutters->getShuttersDev 254 | . ' - versetztes fahren' ); 255 | } 256 | elsif ($offSetStart < 1 257 | || $FHEM::Automation::ShuttersControl::shutters->getNoDelay ) 258 | { 259 | FHEM::Automation::ShuttersControl::SetCmdFn( \%h ); 260 | FHEM::Automation::ShuttersControl::ASC_Debug( 'FnSetDriveCmd: ' 261 | . $FHEM::Automation::ShuttersControl::shutters->getShuttersDev 262 | . ' - NICHT versetztes fahren' ); 263 | } 264 | 265 | FHEM::Automation::ShuttersControl::ASC_Debug( 266 | 'FnSetDriveCmd: ' 267 | . $FHEM::Automation::ShuttersControl::shutters->getShuttersDev 268 | . ' - NoDelay: ' 269 | . ( 270 | $FHEM::Automation::ShuttersControl::shutters->getNoDelay 271 | ? 'JA' 272 | : 'NEIN' 273 | ) 274 | ); 275 | $FHEM::Automation::ShuttersControl::shutters->setNoDelay(0); 276 | } 277 | 278 | return; 279 | } 280 | 281 | sub setSunsetUnixTime { 282 | my $self = shift; 283 | my $unixtime = shift; 284 | 285 | $self->{ $self->{shuttersDev} }{sunsettime} = $unixtime; 286 | return; 287 | } 288 | 289 | sub setSunset { 290 | my $self = shift; 291 | my $value = shift; 292 | 293 | $self->{ $self->{shuttersDev} }{sunset} = $value; 294 | return; 295 | } 296 | 297 | sub setSunriseUnixTime { 298 | my $self = shift; 299 | my $unixtime = shift; 300 | 301 | $self->{ $self->{shuttersDev} }{sunrisetime} = $unixtime; 302 | return; 303 | } 304 | 305 | sub setSunrise { 306 | my $self = shift; 307 | my $value = shift; 308 | 309 | $self->{ $self->{shuttersDev} }{sunrise} = $value; 310 | return; 311 | } 312 | 313 | sub setDelayCmd { 314 | my $self = shift; 315 | my $posValue = shift; 316 | 317 | $self->{ $self->{shuttersDev} }{delayCmd} = $posValue; 318 | return; 319 | } 320 | 321 | sub setLastDrive { 322 | my $self = shift; 323 | my $lastDrive = shift; 324 | 325 | $self->{ $self->{shuttersDev} }{lastDrive} = $lastDrive; 326 | return; 327 | } 328 | 329 | sub setPosSetCmd { 330 | my $self = shift; 331 | my $posSetCmd = shift; 332 | 333 | $self->{ $self->{shuttersDev} }{posSetCmd} = $posSetCmd; 334 | return; 335 | } 336 | 337 | sub setLastDriveReading { 338 | my $self = shift; 339 | my $shuttersDevHash = $::defs{ $self->{shuttersDev} }; 340 | 341 | my %h = ( 342 | devHash => $shuttersDevHash, 343 | lastDrive => $FHEM::Automation::ShuttersControl::shutters->getLastDrive, 344 | ); 345 | 346 | ::InternalTimer( ::gettimeofday() + 0.1, 347 | \&FHEM::Automation::ShuttersControl::setShuttersLastDriveDelayed, \%h ); 348 | return; 349 | } 350 | 351 | sub setLastPos { 352 | 353 | # letzte ermittelte Position bevor die Position des Rolladen über ASC geändert wurde 354 | my $self = shift; 355 | my $position = shift; 356 | 357 | $self->{ $self->{shuttersDev} }{lastPos}{VAL} = $position 358 | if ( defined($position) ); 359 | $self->{ $self->{shuttersDev} }{lastPos}{TIME} = int( ::gettimeofday() ) 360 | if ( defined( $self->{ $self->{shuttersDev} }{lastPos} ) ); 361 | return; 362 | } 363 | 364 | sub setLastManPos { 365 | my $self = shift; 366 | my $position = shift; 367 | 368 | $self->{ $self->{shuttersDev} }{lastManPos}{VAL} = $position 369 | if ( defined($position) ); 370 | $self->{ $self->{shuttersDev} }{lastManPos}{TIME} = int( ::gettimeofday() ) 371 | if ( defined( $self->{ $self->{shuttersDev} }{lastManPos} ) 372 | && defined( $self->{ $self->{shuttersDev} }{lastManPos}{TIME} ) ); 373 | $self->{ $self->{shuttersDev} }{lastManPos}{TIME} = 374 | int( ::gettimeofday() ) - 86400 375 | if ( defined( $self->{ $self->{shuttersDev} }{lastManPos} ) 376 | && !defined( $self->{ $self->{shuttersDev} }{lastManPos}{TIME} ) ); 377 | return; 378 | } 379 | 380 | sub setDefault { 381 | my $self = shift; 382 | my $defaultarg = shift; 383 | 384 | $self->{defaultarg} = $defaultarg if ( defined($defaultarg) ); 385 | return $self->{defaultarg}; 386 | } 387 | 388 | sub setRoommate { 389 | my $self = shift; 390 | my $roommate = shift; 391 | 392 | $self->{roommate} = $roommate if ( defined($roommate) ); 393 | return $self->{roommate}; 394 | } 395 | 396 | sub setInTimerFuncHash { 397 | my $self = shift; 398 | my $inTimerFuncHash = shift; 399 | 400 | $self->{ $self->{shuttersDev} }{inTimerFuncHash} = $inTimerFuncHash 401 | if ( defined($inTimerFuncHash) ); 402 | return; 403 | } 404 | 405 | sub setPrivacyDownStatus { 406 | my $self = shift; 407 | my $statusValue = shift; 408 | 409 | $self->{ $self->{shuttersDev} }->{privacyDownStatus} = $statusValue; 410 | return; 411 | } 412 | 413 | sub setPrivacyUpStatus { 414 | my $self = shift; 415 | my $statusValue = shift; 416 | 417 | $self->{ $self->{shuttersDev} }->{privacyUpStatus} = $statusValue; 418 | return; 419 | } 420 | 421 | sub setSelfDefenseState { 422 | my $self = shift; 423 | my $value = shift; 424 | 425 | $self->{ $self->{shuttersDev} }{selfDefenseState} = $value; 426 | return; 427 | } 428 | 429 | sub setAdvDelay { 430 | my $self = shift; 431 | my $advDelay = shift; 432 | 433 | $self->{ $self->{shuttersDev} }->{AdvDelay} = $advDelay; 434 | return; 435 | } 436 | 437 | sub setWindProtectionStatus { # Werte protected, unprotected 438 | my $self = shift; 439 | my $value = shift; 440 | 441 | $self->{ $self->{shuttersDev} }->{ASC_WindParameters}->{VAL} = $value 442 | if ( defined($value) ); 443 | 444 | return; 445 | } 446 | 447 | sub setRainProtectionStatus { # Werte protected, unprotected 448 | my $self = shift; 449 | my $value = shift; 450 | 451 | $self->{ $self->{shuttersDev} }->{RainProtection}->{VAL} = $value 452 | if ( defined($value) ); 453 | return; 454 | } 455 | 456 | sub setRainUnprotectionDelayObj { 457 | my $self = shift; 458 | my $value = shift; 459 | 460 | $self->{ $self->{shuttersDev} }->{RainProtection}->{UNPROTECTIONDELAYOBJVAL} 461 | = $value 462 | if ( defined($value) ); 463 | return; 464 | } 465 | 466 | sub setExternalTriggerStatus { 467 | my $self = shift; 468 | my $value = shift; 469 | 470 | $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger}->{event} = $value 471 | if ( defined($value) ); 472 | 473 | return; 474 | } 475 | 476 | sub getExternalTriggerStatus { 477 | my $self = shift; 478 | 479 | return ( 480 | ( 481 | defined( 482 | $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger}->{event} 483 | ) 484 | and 485 | $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger}->{event} 486 | ) ? 1 : 0 487 | ); 488 | } 489 | 490 | sub getHomemode { 491 | my $self = shift; 492 | 493 | my $homemode = 494 | $FHEM::Automation::ShuttersControl::shutters->getRoommatesStatus; 495 | $homemode = $FHEM::Automation::ShuttersControl::ascDev->getResidentsStatus 496 | if ( $homemode eq 'none' ); 497 | return $homemode; 498 | } 499 | 500 | sub getAdvDelay { 501 | my $self = shift; 502 | 503 | return ( 504 | defined( $self->{ $self->{shuttersDev} }->{AdvDelay} ) 505 | ? $self->{ $self->{shuttersDev} }->{AdvDelay} 506 | : 0 507 | ); 508 | } 509 | 510 | sub getPrivacyDownStatus { 511 | my $self = shift; 512 | 513 | return ( 514 | defined( $self->{ $self->{shuttersDev} }->{privacyDownStatus} ) 515 | ? $self->{ $self->{shuttersDev} }->{privacyDownStatus} 516 | : undef 517 | ); 518 | } 519 | 520 | sub getPrivacyUpStatus { 521 | my $self = shift; 522 | 523 | return ( 524 | defined( $self->{ $self->{shuttersDev} }->{privacyUpStatus} ) 525 | ? $self->{ $self->{shuttersDev} }->{privacyUpStatus} 526 | : undef 527 | ); 528 | } 529 | 530 | sub getAttrUpdateChanges { 531 | my $self = shift; 532 | my $attr = shift; 533 | 534 | return ( 535 | defined( $self->{ $self->{shuttersDev} }{AttrUpdateChanges} ) 536 | && defined( 537 | $self->{ $self->{shuttersDev} }{AttrUpdateChanges}{$attr} ) 538 | ? $self->{ $self->{shuttersDev} }{AttrUpdateChanges}{$attr} 539 | : 'none' 540 | ); 541 | } 542 | 543 | sub getIsDay { 544 | my $self = shift; 545 | 546 | return FHEM::Automation::ShuttersControl::Helper::_IsDay( 547 | $self->{shuttersDev} ); 548 | } 549 | 550 | sub getAntiFreezeStatus { 551 | use POSIX qw(strftime); 552 | my $self = shift; 553 | my $daytime = strftime( "%P", localtime() ); 554 | $daytime = ( 555 | defined($daytime) && $daytime 556 | ? $daytime 557 | : ( strftime( "%H", localtime() ) < 12 ? 'am' : 'pm' ) 558 | ); 559 | my $outTemp = $FHEM::Automation::ShuttersControl::ascDev->getOutTemp; 560 | 561 | # $outTemp = $FHEM::Automation::ShuttersControl::shutters->getOutTemp if ( $FHEM::Automation::ShuttersControl::shutters->getOutTemp != -100 ); sollte raus das der Sensor im Rollo auch ein Innentemperatursensor sein kann. 562 | 563 | if ( $FHEM::Automation::ShuttersControl::shutters->getAntiFreeze ne 'off' 564 | && $outTemp <= 565 | $FHEM::Automation::ShuttersControl::ascDev->getFreezeTemp ) 566 | { 567 | 568 | if ( $FHEM::Automation::ShuttersControl::shutters->getAntiFreeze eq 569 | 'soft' ) 570 | { 571 | return 1; 572 | } 573 | elsif ( $FHEM::Automation::ShuttersControl::shutters->getAntiFreeze eq 574 | $daytime ) 575 | { 576 | return 2; 577 | } 578 | elsif ( $FHEM::Automation::ShuttersControl::shutters->getAntiFreeze eq 579 | 'hard' ) 580 | { 581 | return 3; 582 | } 583 | } 584 | else { return 0; } 585 | } 586 | 587 | sub getShuttersPosCmdValueNegate { 588 | my $self = shift; 589 | 590 | return ( $FHEM::Automation::ShuttersControl::shutters->getOpenPos < 591 | $FHEM::Automation::ShuttersControl::shutters->getClosedPos ? 1 : 0 ); 592 | } 593 | 594 | sub getQueryShuttersPos 595 | { # Es wird geschaut ob die aktuelle Position des Rollos unterhalb der Zielposition ist 596 | my $self = shift; 597 | my $posValue = shift; # wenn dem so ist wird 1 zurück gegeben ansonsten 0 598 | 599 | return ( 600 | $FHEM::Automation::ShuttersControl::shutters 601 | ->getShuttersPosCmdValueNegate 602 | ? $FHEM::Automation::ShuttersControl::shutters->getStatus > $posValue 603 | : $FHEM::Automation::ShuttersControl::shutters->getStatus < $posValue 604 | ); 605 | } 606 | 607 | sub getPosSetCmd { 608 | my $self = shift; 609 | 610 | return ( 611 | defined( $self->{ $self->{shuttersDev} }{posSetCmd} ) 612 | ? $self->{ $self->{shuttersDev} }{posSetCmd} 613 | : $FHEM::Automation::ShuttersControl::shutters->getPosCmd 614 | ); 615 | } 616 | 617 | sub getNoDelay { 618 | my $self = shift; 619 | 620 | return $self->{ $self->{shuttersDev} }{noDelay}; 621 | } 622 | 623 | sub getSelfDefenseState { 624 | my $self = shift; 625 | 626 | return ( 627 | defined( $self->{ $self->{shuttersDev} }{selfDefenseState} ) 628 | ? $self->{ $self->{shuttersDev} }{selfDefenseState} 629 | : 0 630 | ); 631 | } 632 | 633 | sub getSelfDefenseAbsent { 634 | my $self = shift; 635 | 636 | return $self->{ $self->{shuttersDev} }{selfDefenseAbsent}{active}; 637 | } 638 | 639 | sub getSelfDefenseAbsentTimerrun { 640 | my $self = shift; 641 | 642 | return $self->{ $self->{shuttersDev} }{selfDefenseAbsent}{timerrun}; 643 | } 644 | 645 | sub getSelfDefenseAbsentTimerhash { 646 | my $self = shift; 647 | 648 | return ( 649 | defined( 650 | $self->{ $self->{shuttersDev} }{selfDefenseAbsent}{timerhash} 651 | ) 652 | ? $self->{ $self->{shuttersDev} }{selfDefenseAbsent}{timerhash} 653 | : undef 654 | ); 655 | } 656 | 657 | sub getLastDrive { 658 | my $self = shift; 659 | 660 | $self->{ $self->{shuttersDev} }{lastDrive} = 661 | ::ReadingsVal( $self->{shuttersDev}, 'ASC_ShuttersLastDrive', 'none' ) 662 | if ( !defined( $self->{ $self->{shuttersDev} }{lastDrive} ) ); 663 | 664 | return $self->{ $self->{shuttersDev} }{lastDrive}; 665 | } 666 | 667 | sub getLastPos 668 | { # letzte ermittelte Position bevor die Position des Rolladen über ASC geändert wurde 669 | my $self = shift; 670 | 671 | return ( 672 | defined( $self->{ $self->{shuttersDev} }{lastPos} ) 673 | && defined( $self->{ $self->{shuttersDev} }{lastPos}{VAL} ) 674 | ? $self->{ $self->{shuttersDev} }{lastPos}{VAL} 675 | : 50 676 | ); 677 | } 678 | 679 | sub getLastPosTimestamp { 680 | my $self = shift; 681 | 682 | return ( 683 | defined( $self->{ $self->{shuttersDev} } ) 684 | && defined( $self->{ $self->{shuttersDev} }{lastPos} ) 685 | && defined( $self->{ $self->{shuttersDev} }{lastPos}{TIME} ) 686 | ? $self->{ $self->{shuttersDev} }{lastPos}{TIME} 687 | : 0 688 | ); 689 | } 690 | 691 | sub getLastManPos 692 | { # letzte ermittelte Position bevor die Position des Rolladen manuell (nicht über ASC) geändert wurde 693 | my $self = shift; 694 | 695 | return ( 696 | defined( $self->{ $self->{shuttersDev} }{lastManPos} ) 697 | && defined( $self->{ $self->{shuttersDev} }{lastManPos}{VAL} ) 698 | ? $self->{ $self->{shuttersDev} }{lastManPos}{VAL} 699 | : 50 700 | ); 701 | } 702 | 703 | sub getLastManPosTimestamp { 704 | my $self = shift; 705 | 706 | return ( 707 | defined( $self->{ $self->{shuttersDev} } ) 708 | && defined( $self->{ $self->{shuttersDev} }{lastManPos} ) 709 | && defined( $self->{ $self->{shuttersDev} }{lastManPos}{TIME} ) 710 | ? $self->{ $self->{shuttersDev} }{lastManPos}{TIME} 711 | : 0 712 | ); 713 | } 714 | 715 | sub getInTimerFuncHash { 716 | my $self = shift; 717 | 718 | return $self->{ $self->{shuttersDev} }{inTimerFuncHash}; 719 | } 720 | 721 | sub getWindProtectionStatus { # Werte protected, unprotected 722 | my $self = shift; 723 | 724 | return ( 725 | ( 726 | defined( $self->{ $self->{shuttersDev} }->{ASC_WindParameters} ) 727 | && defined( 728 | $self->{ $self->{shuttersDev} }->{ASC_WindParameters}->{VAL} 729 | ) 730 | ) 731 | ? $self->{ $self->{shuttersDev} }->{ASC_WindParameters}->{VAL} 732 | : 'unprotected' 733 | ); 734 | } 735 | 736 | sub getRainProtectionStatus { # Werte protected, unprotected 737 | my $self = shift; 738 | 739 | return ( 740 | ( 741 | defined( $self->{ $self->{shuttersDev} }->{RainProtection} ) 742 | && defined( 743 | $self->{ $self->{shuttersDev} }->{RainProtection}->{VAL} 744 | ) 745 | ) 746 | ? $self->{ $self->{shuttersDev} }->{RainProtection}->{VAL} 747 | : 'unprotected' 748 | ); 749 | } 750 | 751 | sub getRainUnprotectionDelayObj { 752 | my $self = shift; 753 | 754 | return ( 755 | ( 756 | defined( $self->{ $self->{shuttersDev} }->{RainProtection} ) 757 | && defined( 758 | $self->{ $self->{shuttersDev} }->{RainProtection} 759 | ->{UNPROTECTIONDELAYOBJVAL} 760 | ) 761 | ) 762 | ? $self->{ $self->{shuttersDev} }->{RainProtection} 763 | ->{UNPROTECTIONDELAYOBJVAL} 764 | : 'none' 765 | ); 766 | } 767 | 768 | sub getSunsetUnixTime { 769 | my $self = shift; 770 | 771 | return $self->{ $self->{shuttersDev} }{sunsettime}; 772 | } 773 | 774 | sub getSunset { 775 | my $self = shift; 776 | 777 | return ( 778 | defined( $self->{ $self->{shuttersDev} }{sunset} ) 779 | ? $self->{ $self->{shuttersDev} }{sunset} 780 | : 0 781 | ); 782 | } 783 | 784 | sub getSunriseUnixTime { 785 | my $self = shift; 786 | 787 | return $self->{ $self->{shuttersDev} }{sunrisetime}; 788 | } 789 | 790 | sub getSunrise { 791 | my $self = shift; 792 | 793 | return ( 794 | defined( $self->{ $self->{shuttersDev} }{sunrise} ) 795 | ? $self->{ $self->{shuttersDev} }{sunrise} 796 | : 0 797 | ); 798 | } 799 | 800 | sub getRoommatesStatus { 801 | my $self = shift; 802 | 803 | my $loop = 0; 804 | my @roState; 805 | my %statePrio = ( 806 | 'asleep' => 1, 807 | 'gotosleep' => 2, 808 | 'awoken' => 3, 809 | 'home' => 4, 810 | 'absent' => 5, 811 | 'gone' => 6, 812 | 'none' => 7 813 | ); 814 | my $minPrio = 10; 815 | 816 | for my $ro ( 817 | split( 818 | ",", $FHEM::Automation::ShuttersControl::shutters->getRoommates 819 | ) 820 | ) 821 | { 822 | $FHEM::Automation::ShuttersControl::shutters->setRoommate($ro); 823 | my $currentPrio = 824 | $statePrio{ $FHEM::Automation::ShuttersControl::shutters 825 | ->getRoommateStatus }; 826 | $minPrio = $currentPrio if ( $minPrio > $currentPrio ); 827 | } 828 | 829 | my %revStatePrio = reverse %statePrio; 830 | return $revStatePrio{$minPrio}; 831 | } 832 | 833 | sub getRoommatesLastStatus { 834 | my $self = shift; 835 | 836 | my $loop = 0; 837 | my @roState; 838 | my %statePrio = ( 839 | 'asleep' => 1, 840 | 'gotosleep' => 2, 841 | 'awoken' => 3, 842 | 'home' => 6, 843 | 'absent' => 5, 844 | 'gone' => 4, 845 | 'none' => 7 846 | ); 847 | my $minPrio = 10; 848 | 849 | for my $ro ( 850 | split( 851 | ",", $FHEM::Automation::ShuttersControl::shutters->getRoommates 852 | ) 853 | ) 854 | { 855 | $FHEM::Automation::ShuttersControl::shutters->setRoommate($ro); 856 | my $currentPrio = 857 | $statePrio{ $FHEM::Automation::ShuttersControl::shutters 858 | ->getRoommateLastStatus }; 859 | $minPrio = $currentPrio if ( $minPrio > $currentPrio ); 860 | } 861 | 862 | my %revStatePrio = reverse %statePrio; 863 | return $revStatePrio{$minPrio}; 864 | } 865 | 866 | sub getOutTemp { 867 | my $self = shift; 868 | 869 | return ::ReadingsVal( 870 | $FHEM::Automation::ShuttersControl::shutters->_getTempSensor, 871 | $FHEM::Automation::ShuttersControl::shutters->getTempSensorReading, 872 | -100 ); 873 | } 874 | 875 | sub getIdleDetection { 876 | my $self = shift; 877 | 878 | return ::ReadingsVal( 879 | $self->{shuttersDev}, 880 | $FHEM::Automation::ShuttersControl::shutters->_getIdleDetectionReading, 881 | 'none' 882 | ); 883 | } 884 | 885 | ### Begin Beschattung Objekt mit Daten befüllen 886 | sub setShadingStatus { 887 | my $self = shift; 888 | my $value = shift; ### Werte für value = in, out, in reserved, out reserved 889 | 890 | # Es wird durch das return die ShadingWaitingTime nicht mehr beachtet, Bugmeldung von Bernd Griemsmann 891 | # return 892 | # if ( defined($value) 893 | # && exists( $self->{ $self->{shuttersDev} }{ShadingStatus}{VAL} ) 894 | # && $self->{ $self->{shuttersDev} }{ShadingStatus}{VAL} eq $value ); 895 | 896 | $FHEM::Automation::ShuttersControl::shutters->setShadingLastStatus( 897 | ( $value eq 'in' ? 'out' : 'in' ) ) 898 | if ( $value eq 'in' 899 | || $value eq 'out' ); 900 | 901 | $self->{ $self->{shuttersDev} }{ShadingStatus}{VAL} = $value 902 | if ( defined($value) ); 903 | $self->{ $self->{shuttersDev} }{ShadingStatus}{TIME} = 904 | int( ::gettimeofday() ) 905 | if ( defined( $self->{ $self->{shuttersDev} }{ShadingStatus} ) ); 906 | 907 | return; 908 | } 909 | 910 | sub setShadingLastStatus { 911 | my $self = shift; 912 | my $value = shift; ### Werte für value = in, out 913 | 914 | return 915 | if ( defined($value) 916 | && exists( $self->{ $self->{shuttersDev} }{ShadingLastStatus}{VAL} ) 917 | && $self->{ $self->{shuttersDev} }{ShadingLastStatus}{VAL} eq $value ); 918 | 919 | $self->{ $self->{shuttersDev} }{ShadingLastStatus}{VAL} = $value 920 | if ( defined($value) ); 921 | $self->{ $self->{shuttersDev} }{ShadingLastStatus}{TIME} = 922 | int( ::gettimeofday() ) 923 | if ( defined( $self->{ $self->{shuttersDev} }{ShadingLastStatus} ) ); 924 | $self->{ $self->{shuttersDev} }{ShadingManualDriveStatus}{VAL} = 0 925 | if ( $value eq 'out' ); 926 | 927 | return; 928 | } 929 | 930 | sub setShadingManualDriveStatus { 931 | my $self = shift; 932 | my $value = shift; ### Werte für value = 0, 1 933 | 934 | $self->{ $self->{shuttersDev} }{ShadingManualDriveStatus}{VAL} = $value 935 | if ( defined($value) ); 936 | 937 | return; 938 | } 939 | 940 | sub setShadingLastPos { 941 | my $self = shift; 942 | my $value = shift; 943 | 944 | $self->{ $self->{shuttersDev} }{ShadingLastPos}{VAL} = $value 945 | if ( defined($value) ); 946 | 947 | return; 948 | } 949 | 950 | sub setShadingBetweenTheTimeSuspend { # Werte für value = 0, 1 951 | my $self = shift; 952 | my $value = shift; 953 | 954 | $self->{ $self->{shuttersDev} }{ShadingBetweenTheTimeSuspend}{VAL} = $value 955 | if ( defined($value) ); 956 | 957 | return; 958 | } 959 | 960 | sub setPushBrightnessInArray { 961 | my $self = shift; 962 | my $value = shift; 963 | 964 | unshift( 965 | @{ $self->{ $self->{shuttersDev} }->{BrightnessAverageArray}->{VAL} }, 966 | $value 967 | ); 968 | pop( @{ $self->{ $self->{shuttersDev} }->{BrightnessAverageArray}->{VAL} } ) 969 | if ( 970 | scalar( 971 | @{ 972 | $self->{ $self->{shuttersDev} }->{BrightnessAverageArray}->{VAL} 973 | } 974 | ) > $FHEM::Automation::ShuttersControl::shutters 975 | ->getMaxBrightnessAverageArrayObjects 976 | ); 977 | 978 | return; 979 | } 980 | 981 | sub getBrightnessAverage { 982 | use FHEM::Automation::ShuttersControl::Helper qw (AverageBrightness); 983 | 984 | my $self = shift; 985 | 986 | return AverageBrightness( 987 | @{ $self->{ $self->{shuttersDev} }->{BrightnessAverageArray}->{VAL} } ) 988 | if ( 989 | ref( $self->{ $self->{shuttersDev} }->{BrightnessAverageArray}->{VAL} ) 990 | eq 'ARRAY' 991 | && scalar( 992 | @{ 993 | $self->{ $self->{shuttersDev} }->{BrightnessAverageArray}->{VAL} 994 | } 995 | ) > 0 996 | ); 997 | 998 | return; 999 | } 1000 | 1001 | sub getShadingStatus { # Werte für value = in, out, in reserved, out reserved 1002 | my $self = shift; 1003 | 1004 | return ( 1005 | defined( $self->{ $self->{shuttersDev} }{ShadingStatus} ) 1006 | && defined( $self->{ $self->{shuttersDev} }{ShadingStatus}{VAL} ) 1007 | ? $self->{ $self->{shuttersDev} }{ShadingStatus}{VAL} 1008 | : 'out' 1009 | ); 1010 | } 1011 | 1012 | sub getShadingBetweenTheTimeSuspend { # Werte für value = 0, 1 1013 | my $self = shift; 1014 | 1015 | return ( 1016 | defined( 1017 | $self->{ $self->{shuttersDev} }{ShadingBetweenTheTimeSuspend} 1018 | ) 1019 | && defined( 1020 | $self->{ $self->{shuttersDev} }{ShadingBetweenTheTimeSuspend}{VAL} 1021 | ) 1022 | ? $self->{ $self->{shuttersDev} }{ShadingBetweenTheTimeSuspend}{VAL} 1023 | : 0 1024 | ); 1025 | } 1026 | 1027 | sub getShadingLastStatus { # Werte für value = in, out 1028 | my $self = shift; 1029 | 1030 | return ( 1031 | defined( $self->{ $self->{shuttersDev} }{ShadingLastStatus} ) 1032 | && defined( $self->{ $self->{shuttersDev} }{ShadingLastStatus}{VAL} ) 1033 | ? $self->{ $self->{shuttersDev} }{ShadingLastStatus}{VAL} 1034 | : 'out' 1035 | ); 1036 | } 1037 | 1038 | sub getShadingManualDriveStatus { # Werte für value = 0, 1 1039 | my $self = shift; 1040 | 1041 | return ( 1042 | defined( $self->{ $self->{shuttersDev} }{ShadingManualDriveStatus} ) 1043 | && defined( 1044 | $self->{ $self->{shuttersDev} }{ShadingManualDriveStatus}{VAL} 1045 | ) 1046 | ? $self->{ $self->{shuttersDev} }{ShadingManualDriveStatus}{VAL} 1047 | : 0 1048 | ); 1049 | } 1050 | 1051 | sub getIfInShading { 1052 | my $self = shift; 1053 | 1054 | return ( 1055 | ( 1056 | $FHEM::Automation::ShuttersControl::shutters->getShadingMode ne 1057 | 'off' 1058 | && $FHEM::Automation::ShuttersControl::shutters 1059 | ->getShadingLastStatus eq 'out' 1060 | ) ? 1 : 0 1061 | ); 1062 | } 1063 | 1064 | sub getShadingStatusTimestamp { 1065 | my $self = shift; 1066 | 1067 | return ( 1068 | defined( $self->{ $self->{shuttersDev} } ) 1069 | && defined( $self->{ $self->{shuttersDev} }{ShadingStatus} ) 1070 | && defined( $self->{ $self->{shuttersDev} }{ShadingStatus}{TIME} ) 1071 | ? $self->{ $self->{shuttersDev} }{ShadingStatus}{TIME} 1072 | : 0 1073 | ); 1074 | } 1075 | 1076 | sub getShadingLastStatusTimestamp { 1077 | my $self = shift; 1078 | 1079 | return ( 1080 | defined( $self->{ $self->{shuttersDev} } ) 1081 | && defined( $self->{ $self->{shuttersDev} }{ShadingLastStatus} ) 1082 | && defined( $self->{ $self->{shuttersDev} }{ShadingLastStatus}{TIME} ) 1083 | ? $self->{ $self->{shuttersDev} }{ShadingLastStatus}{TIME} 1084 | : 0 1085 | ); 1086 | } 1087 | 1088 | sub getShadingLastPos { 1089 | my $self = shift; 1090 | 1091 | return ( 1092 | defined( $self->{ $self->{shuttersDev} }{ShadingLastPos} ) 1093 | && defined( $self->{ $self->{shuttersDev} }{ShadingLastPos}{VAL} ) 1094 | ? $self->{ $self->{shuttersDev} }{ShadingLastPos}{VAL} 1095 | : $FHEM::Automation::ShuttersControl::shutters->getShadingPos 1096 | ); 1097 | } 1098 | 1099 | ### Ende Beschattung 1100 | 1101 | 1; 1102 | -------------------------------------------------------------------------------- /lib/FHEM/Automation/ShuttersControl/Shutters/Readings.pm: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # Developed with VSCodium and richterger perl plugin 4 | # 5 | # (c) 2018-2025 Copyright: Marko Oldenburg (fhemdevelopment at cooltux dot net) 6 | # All rights reserved 7 | # 8 | # Special thanks goes to: 9 | # - Bernd (Cluni) this module is based on the logic of his script "Rollladensteuerung für HM/ROLLO inkl. Abschattung und Komfortfunktionen in Perl" (https://forum.fhem.de/index.php/topic,73964.0.html) 10 | # - Beta-User for many tests, many suggestions and good discussions 11 | # - pc1246 write english commandref 12 | # - FunkOdyssey commandref style 13 | # - sledge fix many typo in commandref 14 | # - many User that use with modul and report bugs 15 | # - Christoph (christoph.kaiser.in) Patch that expand RegEx for Window Events 16 | # - Julian (Loredo) expand Residents Events for new Residents functions 17 | # - Christoph (Christoph Morrison) for fix Commandref, many suggestions and good discussions 18 | # 19 | # 20 | # This script is free software; you can redistribute it and/or modify 21 | # it under the terms of the GNU General Public License as published by 22 | # the Free Software Foundation; either version 2 of the License,or 23 | # any later version. 24 | # 25 | # The GNU General Public License can be found at 26 | # http://www.gnu.org/copyleft/gpl.html. 27 | # A copy is found in the textfile GPL.txt and important notices to the license 28 | # from the author is found in LICENSE.txt distributed with these scripts. 29 | # 30 | # This script is distributed in the hope that it will be useful, 31 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 32 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 33 | # GNU General Public License for more details. 34 | # 35 | # 36 | # $Id$ 37 | # 38 | ############################################################################### 39 | 40 | ## Subklasse Readings von ASC_Shutters ## 41 | package FHEM::Automation::ShuttersControl::Shutters::Readings; 42 | 43 | use strict; 44 | use warnings; 45 | use utf8; 46 | 47 | sub getBrightness { 48 | my $self = shift; 49 | 50 | return ::ReadingsNum( 51 | $FHEM::Automation::ShuttersControl::shutters->_getBrightnessSensor, 52 | $FHEM::Automation::ShuttersControl::shutters->getBrightnessReading, 53 | -1 ); 54 | } 55 | 56 | sub getWindStatus { 57 | my $self = shift; 58 | 59 | return ::ReadingsVal( 60 | $FHEM::Automation::ShuttersControl::ascDev->_getWindSensor, 61 | $FHEM::Automation::ShuttersControl::ascDev->getWindSensorReading, -1 ); 62 | } 63 | 64 | sub getStatus { 65 | my $self = shift; 66 | 67 | return ::ReadingsNum( $self->{shuttersDev}, 68 | $FHEM::Automation::ShuttersControl::shutters->getPosCmd, 0 ); 69 | } 70 | 71 | sub getDelayCmd { 72 | my $self = shift; 73 | 74 | return $self->{ $self->{shuttersDev} }{delayCmd}; 75 | } 76 | 77 | sub getASCenable { 78 | my $self = shift; 79 | 80 | return ::ReadingsVal( $self->{shuttersDev}, 'ASC_Enable', 'on' ); 81 | } 82 | 83 | 1; 84 | -------------------------------------------------------------------------------- /lib/FHEM/Automation/ShuttersControl/Window.pm: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # Developed with VSCodium and richterger perl plugin 4 | # 5 | # (c) 2018-2025 Copyright: Marko Oldenburg (fhemdevelopment at cooltux dot net) 6 | # All rights reserved 7 | # 8 | # Special thanks goes to: 9 | # - Bernd (Cluni) this module is based on the logic of his script "Rollladensteuerung für HM/ROLLO inkl. Abschattung und Komfortfunktionen in Perl" (https://forum.fhem.de/index.php/topic,73964.0.html) 10 | # - Beta-User for many tests, many suggestions and good discussions 11 | # - pc1246 write english commandref 12 | # - FunkOdyssey commandref style 13 | # - sledge fix many typo in commandref 14 | # - many User that use with modul and report bugs 15 | # - Christoph (christoph.kaiser.in) Patch that expand RegEx for Window Events 16 | # - Julian (Loredo) expand Residents Events for new Residents functions 17 | # - Christoph (Christoph Morrison) for fix Commandref, many suggestions and good discussions 18 | # 19 | # 20 | # This script is free software; you can redistribute it and/or modify 21 | # it under the terms of the GNU General Public License as published by 22 | # the Free Software Foundation; either version 2 of the License,or 23 | # any later version. 24 | # 25 | # The GNU General Public License can be found at 26 | # http://www.gnu.org/copyleft/gpl.html. 27 | # A copy is found in the textfile GPL.txt and important notices to the license 28 | # from the author is found in LICENSE.txt distributed with these scripts. 29 | # 30 | # This script is distributed in the hope that it will be useful, 31 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 32 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 33 | # GNU General Public License for more details. 34 | # 35 | # 36 | # $Id$ 37 | # 38 | ############################################################################### 39 | 40 | ## Klasse Fenster (Window) und die Subklassen Attr und Readings ## 41 | package FHEM::Automation::ShuttersControl::Window; 42 | 43 | use strict; 44 | use warnings; 45 | use utf8; 46 | 47 | use FHEM::Automation::ShuttersControl::Window::Attr; 48 | use FHEM::Automation::ShuttersControl::Window::Readings; 49 | 50 | use base 51 | qw(FHEM::Automation::ShuttersControl::Window::Attr FHEM::Automation::ShuttersControl::Window::Readings); 52 | 53 | 1; 54 | -------------------------------------------------------------------------------- /lib/FHEM/Automation/ShuttersControl/Window/Attr.pm: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # Developed with VSCodium and richterger perl plugin 4 | # 5 | # (c) 2018-2025 Copyright: Marko Oldenburg (fhemdevelopment at cooltux dot net) 6 | # All rights reserved 7 | # 8 | # Special thanks goes to: 9 | # - Bernd (Cluni) this module is based on the logic of his script "Rollladensteuerung für HM/ROLLO inkl. Abschattung und Komfortfunktionen in Perl" (https://forum.fhem.de/index.php/topic,73964.0.html) 10 | # - Beta-User for many tests, many suggestions and good discussions 11 | # - pc1246 write english commandref 12 | # - FunkOdyssey commandref style 13 | # - sledge fix many typo in commandref 14 | # - many User that use with modul and report bugs 15 | # - Christoph (christoph.kaiser.in) Patch that expand RegEx for Window Events 16 | # - Julian (Loredo) expand Residents Events for new Residents functions 17 | # - Christoph (Christoph Morrison) for fix Commandref, many suggestions and good discussions 18 | # 19 | # 20 | # This script is free software; you can redistribute it and/or modify 21 | # it under the terms of the GNU General Public License as published by 22 | # the Free Software Foundation; either version 2 of the License,or 23 | # any later version. 24 | # 25 | # The GNU General Public License can be found at 26 | # http://www.gnu.org/copyleft/gpl.html. 27 | # A copy is found in the textfile GPL.txt and important notices to the license 28 | # from the author is found in LICENSE.txt distributed with these scripts. 29 | # 30 | # This script is distributed in the hope that it will be useful, 31 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 32 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 33 | # GNU General Public License for more details. 34 | # 35 | # 36 | # $Id$ 37 | # 38 | ############################################################################### 39 | 40 | ## Subklasse Attr von Klasse ASC_Window ## 41 | package FHEM::Automation::ShuttersControl::Window::Attr; 42 | 43 | use strict; 44 | use warnings; 45 | use utf8; 46 | 47 | sub setSubTyp { 48 | my $self = shift; 49 | my $attrVal = shift; 50 | 51 | _setAttributs( $self->{shuttersDev}, 'ASC_WindowRec_subType', $attrVal ); 52 | 53 | return; 54 | } 55 | 56 | sub getSubTyp { 57 | my $self = shift; 58 | 59 | return ::AttrVal( $self->{shuttersDev}, 'ASC_WindowRec_subType', 60 | 'twostate' ); 61 | } 62 | 63 | sub setWinDev { 64 | my $self = shift; 65 | my $attrVal = shift; 66 | 67 | _setAttributs( $self->{shuttersDev}, 'ASC_WindowRec', $attrVal ); 68 | 69 | return; 70 | } 71 | 72 | sub _getWinDev { 73 | my $self = shift; 74 | 75 | return $self->{ $self->{shuttersDev} }->{ASC_WindowRec}->{device} 76 | if ( 77 | exists( 78 | $self->{ $self->{shuttersDev} }->{ASC_WindowRec}->{LASTGETTIME} 79 | ) 80 | && ( ::gettimeofday() - 81 | $self->{ $self->{shuttersDev} }->{ASC_WindowRec}->{LASTGETTIME} ) < 82 | 2 83 | ); 84 | $self->{ $self->{shuttersDev} }->{ASC_WindowRec}->{LASTGETTIME} = 85 | int( ::gettimeofday() ); 86 | my ( $device, $reading ) = 87 | FHEM::Automation::ShuttersControl::Helper::GetAttrValues( 88 | $self->{shuttersDev}, 'ASC_WindowRec', 'none' ); 89 | 90 | ### erwartetes Ergebnis 91 | # DEVICE:READING VALUEACTIVE:VALUEINACTIVE POSACTIVE:POSINACTIVE 92 | 93 | $self->{ $self->{shuttersDev} }->{ASC_WindowRec}->{device} = 94 | $device; 95 | $self->{ $self->{shuttersDev} }->{ASC_WindowRec}->{reading} = 96 | ( $reading ne 'none' ? $reading : 'state' ); 97 | 98 | return $self->{ $self->{shuttersDev} }->{ASC_WindowRec}->{device}; 99 | } 100 | 101 | sub getWinDevReading { 102 | my $self = shift; 103 | 104 | return $self->{ $self->{shuttersDev} }->{ASC_WindowRec}->{reading} 105 | if ( 106 | exists( 107 | $self->{ $self->{shuttersDev} }->{ASC_WindowRec}->{LASTGETTIME} 108 | ) 109 | && ( ::gettimeofday() - 110 | $self->{ $self->{shuttersDev} }->{ASC_WindowRec}->{LASTGETTIME} ) < 111 | 2 112 | ); 113 | $FHEM::Automation::ShuttersControl::shutters->_getWinDev; 114 | 115 | return $self->{ $self->{shuttersDev} }->{ASC_WindowRec}->{reading}; 116 | } 117 | 118 | 1; 119 | -------------------------------------------------------------------------------- /lib/FHEM/Automation/ShuttersControl/Window/Readings.pm: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # Developed with VSCodium and richterger perl plugin 4 | # 5 | # (c) 2018-2025 Copyright: Marko Oldenburg (fhemdevelopment at cooltux dot net) 6 | # All rights reserved 7 | # 8 | # Special thanks goes to: 9 | # - Bernd (Cluni) this module is based on the logic of his script "Rollladensteuerung für HM/ROLLO inkl. Abschattung und Komfortfunktionen in Perl" (https://forum.fhem.de/index.php/topic,73964.0.html) 10 | # - Beta-User for many tests, many suggestions and good discussions 11 | # - pc1246 write english commandref 12 | # - FunkOdyssey commandref style 13 | # - sledge fix many typo in commandref 14 | # - many User that use with modul and report bugs 15 | # - Christoph (christoph.kaiser.in) Patch that expand RegEx for Window Events 16 | # - Julian (Loredo) expand Residents Events for new Residents functions 17 | # - Christoph (Christoph Morrison) for fix Commandref, many suggestions and good discussions 18 | # 19 | # 20 | # This script is free software; you can redistribute it and/or modify 21 | # it under the terms of the GNU General Public License as published by 22 | # the Free Software Foundation; either version 2 of the License,or 23 | # any later version. 24 | # 25 | # The GNU General Public License can be found at 26 | # http://www.gnu.org/copyleft/gpl.html. 27 | # A copy is found in the textfile GPL.txt and important notices to the license 28 | # from the author is found in LICENSE.txt distributed with these scripts. 29 | # 30 | # This script is distributed in the hope that it will be useful, 31 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 32 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 33 | # GNU General Public License for more details. 34 | # 35 | # 36 | # $Id$ 37 | # 38 | ############################################################################### 39 | 40 | ## Subklasse Readings von Klasse ASC_Window ## 41 | package FHEM::Automation::ShuttersControl::Window::Readings; 42 | 43 | use strict; 44 | use warnings; 45 | use utf8; 46 | 47 | sub getWinStatus { 48 | my $self = shift; 49 | 50 | return ::ReadingsVal( 51 | $FHEM::Automation::ShuttersControl::shutters->_getWinDev, 52 | $FHEM::Automation::ShuttersControl::shutters->getWinDevReading, 53 | 'closed' ); 54 | } 55 | 56 | 1; 57 | --------------------------------------------------------------------------------