mirror of
https://github.com/mtan93/SmartThingsPublic.git
synced 2026-04-26 14:16:20 +01:00
Compare commits
1002 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d2cf46a6aa | |||
| 5b39a9f840 | |||
| 7f61feaebc | |||
| 7a467df659 | |||
| 538eb057ce | |||
| 2ff9486790 | |||
| 5429986e81 | |||
| 6514087a1a | |||
| 0f2b8c18d2 | |||
| ce0363fa43 | |||
| e5739fd425 | |||
| 6448a5bc7c | |||
| fd620977bb | |||
| a308bff574 | |||
| 068cfaeaad | |||
| fb55349db0 | |||
| 476d3caa38 | |||
| 9b621c9a7b | |||
| 619b3499c8 | |||
| 3ec8be708a | |||
| 34b2210134 | |||
| 8abb82ecae | |||
| 55da70cd7c | |||
| 80a5a41f7e | |||
| b4276c05e0 | |||
| 1db3765a9c | |||
| 264e822c9f | |||
| e4642e300f | |||
| b4eed54ddd | |||
| b2b03604a7 | |||
| 2b05817843 | |||
| 1f6a27f381 | |||
| 157bc3ef56 | |||
| 096f4f767f | |||
| c15a21b8bf | |||
| c65c9cc185 | |||
| daefec9d1f | |||
| a28c90e492 | |||
| 664b300b37 | |||
| 2b6d978d13 | |||
| 8197097e1d | |||
| 4644362465 | |||
| 2c25e293c0 | |||
| 63d8e6444b | |||
| 24f63a514a | |||
| 36fe6428ab | |||
| 2bc44e0205 | |||
| 24d079db7c | |||
| 283ed425d8 | |||
| 1545707ae3 | |||
| 2fd8cf1416 | |||
| 7f3a99d889 | |||
| a397fe9fc3 | |||
| f83500fbf8 | |||
| a297e79b0e | |||
| 69d52093dc | |||
| fda743a801 | |||
| f7a5ea4820 | |||
| d51ec9e518 | |||
| fe4a5239c7 | |||
| ae41b4adbe | |||
| bdcaf175f0 | |||
| ba10869dd5 | |||
| 6f411e1a3e | |||
| 4cc41d9d9b | |||
| 66875170f4 | |||
| 9e80a188df | |||
| ec781b18be | |||
| 43bedd41a8 | |||
| f75e8a6b2d | |||
| ce10bcf2cd | |||
| 0c8de4402b | |||
| a112d4b00e | |||
| 515fab9fa4 | |||
| 100e696d02 | |||
| 3e988ce657 | |||
| fe887121d3 | |||
| 7375abf9c0 | |||
| 00224c2d0b | |||
| e985f38cf4 | |||
| a79e0f70fd | |||
| f05daf2f34 | |||
| f26b9ce6b2 | |||
| ac4c353287 | |||
| ed40ca7017 | |||
| 7aa8be4322 | |||
| 23a0b26cb9 | |||
| 00fc9e1ab3 | |||
| 3b2d955c55 | |||
| 44facec5df | |||
| 9f944df598 | |||
| e3c1442278 | |||
| 59bfdc9b06 | |||
| e274f2d3fe | |||
| 5e23c8e700 | |||
| 10c1d6f715 | |||
| 55e92b2ad6 | |||
| 18343ae4b8 | |||
| 6c4da81cd4 | |||
| 09e890091a | |||
| 2fb3294ce1 | |||
| 973d347d2f | |||
| a2afb4cb1b | |||
| 693f2c1060 | |||
| 74ae369143 | |||
| afa7784999 | |||
| 0e9abb0cd2 | |||
| 123de9aae4 | |||
| e91907c30a | |||
| 237e226697 | |||
| 3b48629546 | |||
| d28414c1e8 | |||
| f79db67153 | |||
| 8c7cb54934 | |||
| 213d71da09 | |||
| b7288b5beb | |||
| 364154e8a7 | |||
| c51e035ff2 | |||
| 23cfae20b3 | |||
| 5e7ded1f73 | |||
| 36b4d48056 | |||
| 03b9f08eed | |||
| fbdaeea9ae | |||
| 9fa9dee606 | |||
| 122a7d4146 | |||
| 32eb95f7d7 | |||
| 343ec9d856 | |||
| 1f09a22176 | |||
| b1b356f370 | |||
| c5455321d1 | |||
| e6ca3d8ddf | |||
| 9aaab9b11d | |||
| cbd15ae9cc | |||
| fdd330abdf | |||
| df29effc00 | |||
| 668f71a217 | |||
| 6fae023f7a | |||
| 78a509e8f5 | |||
| 42d31f29cc | |||
| 9b4f6974de | |||
| ea5344f9c8 | |||
| b5e1d652fd | |||
| a03e8f20c5 | |||
| ce52af0376 | |||
| 6908733a5c | |||
| e0d307f6b5 | |||
| a06dba0b90 | |||
| 0ec8cba885 | |||
| bcfece27c4 | |||
| 26f9690190 | |||
| eca8fda0f2 | |||
| ce07c065c8 | |||
| 640f9413c3 | |||
| 1c52f80eae | |||
| de4d52a28b | |||
| 6892965cf1 | |||
| 17ec6270d6 | |||
| d233a65ef5 | |||
| b36a985d92 | |||
| 8a3c9edf0a | |||
| a560c5b040 | |||
| 3ee374028f | |||
| 7ac7bd3034 | |||
| f734c5490b | |||
| b93a05d450 | |||
| f5186a41c7 | |||
| c505f95e7a | |||
| 173c34150a | |||
| f6b850500e | |||
| 4dac7b5379 | |||
| a79d56e467 | |||
| e2d8af48a8 | |||
| 0f00c3c7c0 | |||
| 0a4d56be04 | |||
| 1326881142 | |||
| d30494172f | |||
| 2678480244 | |||
| b5e8a46143 | |||
| 6237dbd179 | |||
| 65f5597ccc | |||
| fced2d7c61 | |||
| 74552420ba | |||
| be0c16c76d | |||
| 89f1302c99 | |||
| 16cb20685c | |||
| 30d8e6d835 | |||
| 6d0f9d101d | |||
| 4ba55e7f0a | |||
| 8a41fb6090 | |||
| 79c254cfac | |||
| 72248b0004 | |||
| d8b35b23ea | |||
| 9a53e12427 | |||
| 7a7a08ea6e | |||
| 950a33dc74 | |||
| 2ae163b10b | |||
| e3168793bd | |||
| 0baa986c61 | |||
| 8484f18a0e | |||
| 3c4d86bb31 | |||
| 1f69ab6634 | |||
| b0ac006781 | |||
| ef1ebc8347 | |||
| aa1f2f21e8 | |||
| cb6377886d | |||
| 7a605373d6 | |||
| 90fb9251a6 | |||
| 195e0babb2 | |||
| 065715f296 | |||
| a544e2f019 | |||
| 10acb76b34 | |||
| 4fc046f57f | |||
| ff2e70b011 | |||
| 79e2789f68 | |||
| a777c298ca | |||
| 94a87e5c7f | |||
| 22be8ef2e8 | |||
| 2f20a339c3 | |||
| 65ae2c0ddf | |||
| 7e806275ce | |||
| 1ed57aab45 | |||
| 4eea7ff90f | |||
| b2264538c9 | |||
| 2f786f7ecd | |||
| f45ab69045 | |||
| 91762f6a46 | |||
| b55c650637 | |||
| e391ee5f53 | |||
| ab79ceb857 | |||
| 7b1b9a46bc | |||
| a9a0d296ee | |||
| 905096b381 | |||
| e23bed148d | |||
| 3b7dd3dd91 | |||
| ca404bc2a2 | |||
| 44702cd5fe | |||
| 993f8199d6 | |||
| ccfe5dabdf | |||
| f054cb4de1 | |||
| d47a4de072 | |||
| 4c5787fff0 | |||
| b2f90954ae | |||
| 8a9c38d38e | |||
| 28c0cc9619 | |||
| cb6304530e | |||
| fe5a965f6f | |||
| 72c75882cf | |||
| a006799ad3 | |||
| 2610f00a82 | |||
| 6381580e44 | |||
| 79aebafdc4 | |||
| 1c83a27c40 | |||
| 4a66eca03c | |||
| 31c037e7ab | |||
| d6c85436d2 | |||
| e822e7137e | |||
| 967e1798d5 | |||
| 6ef49e92bb | |||
| e528b61ace | |||
| a583a25ef3 | |||
| a192b75e4c | |||
| f97a0a4072 | |||
| dd0aba3dc9 | |||
| e787afd165 | |||
| 12be259779 | |||
| 379e70b343 | |||
| 9cb0ce716b | |||
| 2151e2dd3e | |||
| 400c55f4ba | |||
| 023b9aad2d | |||
| ccb7b6e49d | |||
| 34f77a2989 | |||
| 318cdedaec | |||
| 011a5ddc74 | |||
| 649ed033d0 | |||
| e687e76b3e | |||
| 1d2fe8af22 | |||
| 6e94220e9e | |||
| e54a8644c3 | |||
| 0d4b681971 | |||
| 0aabce9fa3 | |||
| 843d8800ac | |||
| bcc680ee5d | |||
| 245e85f850 | |||
| af16720528 | |||
| c6d6ba85f5 | |||
| 51832c8db2 | |||
| f001eb0792 | |||
| 81550ee25c | |||
| 1cc9d8a90b | |||
| bfd2b6c0fa | |||
| 9b6e7d3be8 | |||
| 7c5734b752 | |||
| 2a3c393534 | |||
| 91763e7b4d | |||
| 1263b72a72 | |||
| bf45430061 | |||
| 054ccbeffe | |||
| 5cb84a269d | |||
| 6e28d83e96 | |||
| 2d82b05f90 | |||
| 1611fd0144 | |||
| c416c39ac4 | |||
| bc0f849dad | |||
| 459e69607b | |||
| fc312286a2 | |||
| cfdc61d72a | |||
| 0c26d75792 | |||
| bf491270a9 | |||
| 871d75aea6 | |||
| 3905d48235 | |||
| d91c02b970 | |||
| e019d22aff | |||
| 900ab9f70e | |||
| a8f95cc0b9 | |||
| e8d205c775 | |||
| 06e4b7d9f0 | |||
| 16d7da81f1 | |||
| 1800ea2bad | |||
| f164b8832c | |||
| 2d3fa22e07 | |||
| 54a4620c9b | |||
| 8e6d009d67 | |||
| d8c89f6c6a | |||
| ddc15172d6 | |||
| c27904acfb | |||
| 1e02387387 | |||
| 65d4a811b0 | |||
| db4f161e5d | |||
| ff6e543a2e | |||
| de1894bfbf | |||
| 0846b6f34c | |||
| d0f8ec87bd | |||
| 1383ab1e07 | |||
| d4f21b95d7 | |||
| be2e19e406 | |||
| 54da556c17 | |||
| 8611d2e2d2 | |||
| c650047f31 | |||
| a15ca97988 | |||
| 41adc9777a | |||
| f334f6505a | |||
| ded7501b84 | |||
| eb4d5dcfb8 | |||
| 6385443f20 | |||
| fd1ad51880 | |||
| 550214ceb5 | |||
| a36500a216 | |||
| 445c115c14 | |||
| 9900e532a4 | |||
| 7648fd4a17 | |||
| a5d0c1d80a | |||
| 9686f3770b | |||
| de37d0c813 | |||
| bd3367fe0e | |||
| 30511d74af | |||
| f0f02a2c00 | |||
| 61356ec8a7 | |||
| 57d20e2fca | |||
| 3216f63cc0 | |||
| 7cbc2d1780 | |||
| 5ad20fbd2a | |||
| a17971d68c | |||
| 076ffecd19 | |||
| 52357e4c50 | |||
| 03a7991279 | |||
| f969027191 | |||
| 8db0556696 | |||
| 5607a3e346 | |||
| bd44027038 | |||
| 490ec329cb | |||
| 3109049122 | |||
| 930c4ed914 | |||
| 259516f21f | |||
| b7a08a88e0 | |||
| c028515fcd | |||
| 751c98d123 | |||
| 5b874e8f3a | |||
| ef8611d2ea | |||
| 9e10405527 | |||
| 648dee90b6 | |||
| 32ceaff54d | |||
| 5b1da30a47 | |||
| 76e139153a | |||
| a4bc248006 | |||
| e7eb461b4e | |||
| 0a82077b24 | |||
| 083ed7cc9a | |||
| 38ef9e5c77 | |||
| 6a71615ca5 | |||
| 9939591005 | |||
| d7f2bc1d79 | |||
| 3c5d727d4c | |||
| bbad6dfa7a | |||
| df6c815aa4 | |||
| d16ac00eb6 | |||
| 1941f56007 | |||
| f34df19a65 | |||
| af40246655 | |||
| 20239ca982 | |||
| b20c0e371f | |||
| 60756e6dc6 | |||
| ee2e1ee04f | |||
| e443cb641c | |||
| b9993a9bf2 | |||
| 092971c786 | |||
| a8ee927893 | |||
| 51979f0030 | |||
| 61d1205e7d | |||
| 1dfd1818b4 | |||
| 1de73b643c | |||
| e5c21ef720 | |||
| fcb504f57e | |||
| b9229c6ef8 | |||
| 91a9856a32 | |||
| a84ffdde91 | |||
| 3034cc8bcb | |||
| 918e9d9397 | |||
| 0c040120cc | |||
| 6c84c052cb | |||
| f017bff6ef | |||
| 65bb10d6d6 | |||
| 3f93de247b | |||
| 2b7af3ef8d | |||
| cf9d123aa0 | |||
| 8e37b1fce7 | |||
| 439dd634bd | |||
| 1db5f75ec5 | |||
| 7978f45996 | |||
| 0ab657d5f2 | |||
| 3d88fc0413 | |||
| ede1296b6b | |||
| 470cdc7d97 | |||
| 9bc3ff5103 | |||
| bae79192c5 | |||
| 0ae836b023 | |||
| 0b4d555d33 | |||
| 0f8beee455 | |||
| 6ffdc02ef1 | |||
| 6beb8bb50c | |||
| 83a9df6557 | |||
| af8590ab01 | |||
| 9599397db8 | |||
| f7dbabb6c8 | |||
| 7016e234d2 | |||
| cf119b1d15 | |||
| 3e88f3c4bd | |||
| 8ca20ce87e | |||
| c1d520a578 | |||
| c0bb0554d8 | |||
| b6790729c6 | |||
| 3675332b75 | |||
| 7431346187 | |||
| 6aa0ff97b3 | |||
| bd1ace96de | |||
| 40c4520d08 | |||
| 1f69a42341 | |||
| 969852602c | |||
| 4115d8c65f | |||
| 492315b78a | |||
| 40acb36009 | |||
| 0a040aa51b | |||
| 8986c4f5d6 | |||
| 58d8a7dac5 | |||
| a98d3dc2d6 | |||
| 3a377ba147 | |||
| 2d25a0e63f | |||
| 633a179074 | |||
| 49bc42b4ab | |||
| d258c46aee | |||
| 8a66742bb5 | |||
| add519433c | |||
| f6dcaf6d09 | |||
| b07b34f66c | |||
| 96659f0a73 | |||
| 699f80e9f7 | |||
| d21dfc09fe | |||
| d196125092 | |||
| 44088d626a | |||
| 2966c4d5a1 | |||
| 3343273d40 | |||
| 5c70da54a4 | |||
| 687c64d29d | |||
| c9d1b168f7 | |||
| 2f87309fdf | |||
| 37524f17b2 | |||
| 47522facc7 | |||
| 4363661157 | |||
| 330b41941a | |||
| 26d286e0a0 | |||
| ef2323f1b1 | |||
| 51452bc095 | |||
| b7b29d8dbc | |||
| b8111e8760 | |||
| 24ea8269a3 | |||
| 20df244dca | |||
| 583d42df13 | |||
| f1309b2ee2 | |||
| ec1ae2d0b1 | |||
| 5e48e710d4 | |||
| 07c5a3533f | |||
| 72b2016b7d | |||
| a9aee8fd96 | |||
| 5c015cf678 | |||
| cf1a46e309 | |||
| 7c5438880d | |||
| d9888b3184 | |||
| b582c3d832 | |||
| 1ff77dc608 | |||
| afbec02217 | |||
| 434a72bd13 | |||
| 3fba7c9422 | |||
| b63d4a9156 | |||
| 6eb29ad019 | |||
| 711cdc3ebf | |||
| f58a1ef589 | |||
| db5237ca33 | |||
| 7791c68a8a | |||
| db4140ffd6 | |||
| c15b1e88e1 | |||
| ac422076c8 | |||
| 94f57dd249 | |||
| c11c146690 | |||
| 9a5d506668 | |||
| 723ef7e7e6 | |||
| 84c72de640 | |||
| 570454e6c3 | |||
| a5d95fb025 | |||
| b12df3f360 | |||
| 50696902cf | |||
| 409658e899 | |||
| 1068a553f5 | |||
| bbdf9ff02a | |||
| 9dac541473 | |||
| a6cc506803 | |||
| aba8a7ad4b | |||
| b4c912ab80 | |||
| f5b7dfd4eb | |||
| 4b44460b0b | |||
| 3e0306e912 | |||
| 2c2d75ae37 | |||
| 61ef40831c | |||
| 19169748df | |||
| 0f5a2c5e21 | |||
| 6dbb61536b | |||
| 84323afa04 | |||
| 04a7627c21 | |||
| 12b09acfa8 | |||
| 9e8ad0dfdf | |||
| 80eb1e43b9 | |||
| af383de368 | |||
| 427fa88ed8 | |||
| 57514944d5 | |||
| 823efed562 | |||
| 540db429f3 | |||
| 0c3a5de661 | |||
| 989f08708b | |||
| 60e09c56b7 | |||
| 9f5eb7b85a | |||
| 62b37f5c3d | |||
| 64e4ccc517 | |||
| c17830ab56 | |||
| aa890ae3d5 | |||
| 8d701b9fea | |||
| c7f78a69e4 | |||
| 80500207a8 | |||
| 29db335e1c | |||
| 55b5b7d03d | |||
| 730ccccd45 | |||
| 6a1a2b0ed9 | |||
| 719b24ecd6 | |||
| 9d5ab3bfc8 | |||
| aae7f23a22 | |||
| 218cc43520 | |||
| 5b0ca4b815 | |||
| 9ddc020f04 | |||
| aab3b8d7f8 | |||
| a0ccf35eaa | |||
| 9fbbaec8f6 | |||
| e4c1824afd | |||
| 797a58cb68 | |||
| c428267d63 | |||
| 02f30cf425 | |||
| fea802ffce | |||
| 6400d26f4a | |||
| 5e3aaa3270 | |||
| f5c3997679 | |||
| 81cf1179ef | |||
| 7113d7470e | |||
| 79d20b0edb | |||
| b6d862fdd4 | |||
| d58084c438 | |||
| dbfaef3e69 | |||
| 40ed88e7fd | |||
| 1d6e22dc16 | |||
| 30993aa218 | |||
| 2f8ed277ff | |||
| 1d180ac487 | |||
| 230541a145 | |||
| 8c4f7edc83 | |||
| 4f188581df | |||
| 71880e2644 | |||
| 0b7bb40474 | |||
| 8d920ea072 | |||
| e373b6f92e | |||
| 43a1ae6371 | |||
| 60a98e3074 | |||
| a441b94a33 | |||
| ced03d746d | |||
| 5341d0d06f | |||
| 2a58d7ff62 | |||
| 260917d515 | |||
| c1478d3e96 | |||
| 8b9bff15dc | |||
| 75c1ede16c | |||
| a7acc384a2 | |||
| c6998e5f1d | |||
| f95e906d6e | |||
| a6c7ab49b6 | |||
| 4891e3b947 | |||
| ae91f9bff5 | |||
| bb87ad2cf0 | |||
| 5dff03fb69 | |||
| 629d768575 | |||
| dd7c6b90d5 | |||
| 4523498dab | |||
| e89e45e000 | |||
| 78ec280e83 | |||
| 1f144d36e4 | |||
| f5bd580c9e | |||
| d5329dbde3 | |||
| 48818cfb06 | |||
| 079919260b | |||
| 570922e2ac | |||
| 53ed9b4d2b | |||
| 7149a81c85 | |||
| 30274f0cd7 | |||
| 8869cd3af0 | |||
| fb0caa6446 | |||
| 3d05d42cb8 | |||
| 3184615e87 | |||
| 0f70362e0a | |||
| bc817f8530 | |||
| 01b8399893 | |||
| 81318bafac | |||
| 60c2006bfc | |||
| 1e4f1223e7 | |||
| b78bce55b2 | |||
| 01593c3973 | |||
| 6862785d6c | |||
| 763d7411e2 | |||
| c703543f36 | |||
| 5db6ecda3e | |||
| 43b836f413 | |||
| 006b5e7bea | |||
| 62c8c19805 | |||
| 48e9a4bd6a | |||
| 07a4c0decc | |||
| 6aa09bb052 | |||
| 2f889de11a | |||
| 5584020e96 | |||
| 4ef2e694c2 | |||
| 826993cc45 | |||
| ae3306928b | |||
| 8777ec5f6d | |||
| 91eb59a10d | |||
| 324ac13afb | |||
| 878eb66b8b | |||
| 8dfc270c2d | |||
| 614573a15c | |||
| 9c7b0875ba | |||
| 7568cbf781 | |||
| 1858c280a5 | |||
| 6b7d0968f6 | |||
| 159d3acf4f | |||
| e8101630a3 | |||
| f5ba78b221 | |||
| 19b8a7eeb9 | |||
| 1b37d649a5 | |||
| dedb0f8465 | |||
| 06acc13575 | |||
| c051d719cc | |||
| 1e54b93b0c | |||
| bac37f9ca2 | |||
| f0ecb65c09 | |||
| 1c0ddd2571 | |||
| b7e0cbda09 | |||
| f80e094bd9 | |||
| ce9ac624d0 | |||
| f3f5cc42c9 | |||
| 313fe8b734 | |||
| 0d693386d1 | |||
| d1aee1e874 | |||
| 3528e7da51 | |||
| fe2fbc3b97 | |||
| 5c2e06c98d | |||
| 26df619b4f | |||
| af2ea04442 | |||
| 383f72580a | |||
| 090a306939 | |||
| d0a16c10b2 | |||
| faa65f204d | |||
| bacd335991 | |||
| 740e5e096c | |||
| aac2f9b177 | |||
| 048eb77e64 | |||
| dadec937fa | |||
| 78aa6691c4 | |||
| 315918dc6f | |||
| a22f71bc29 | |||
| 8eeb29a8a7 | |||
| 3d84bca3d7 | |||
| 46f47128bd | |||
| 9c8398b7a0 | |||
| cdf5d21e8f | |||
| 5e6b4f74e0 | |||
| 276f7d3b43 | |||
| ce12ad5013 | |||
| beed783d19 | |||
| 7f347638d5 | |||
| 1f8ce734e7 | |||
| 17bf040c7e | |||
| d5b8db99a2 | |||
| 6ad4f0990c | |||
| f1c3f5942b | |||
| 212c9c4179 | |||
| 4898006e4e | |||
| b1c318ef36 | |||
| 8eb6001f9f | |||
| d3eb7f756f | |||
| b95ba37364 | |||
| 87f8755faf | |||
| 555a9f5ab4 | |||
| 0744384dbf | |||
| 97e0e9d0f8 | |||
| 655e756b1b | |||
| 7ce7ad86bd | |||
| d90e15ee31 | |||
| cfe25607ac | |||
| f251042954 | |||
| 33df9b1ff1 | |||
| 24c64608a9 | |||
| dbc2a1e45c | |||
| 92cc8afdf7 | |||
| e545842f7c | |||
| c8bda222cb | |||
| 17014dd248 | |||
| 555edf623a | |||
| feb6ba0e24 | |||
| 9d65150bf7 | |||
| 99d6e9f668 | |||
| a35f271a8e | |||
| fd4969981f | |||
| 1ec110155d | |||
| 79b90d741f | |||
| 6009bc52ab | |||
| 33a8fe108e | |||
| fadc496e1f | |||
| 910694f1d1 | |||
| fa9ebed998 | |||
| 0a2f2bffc2 | |||
| 8dc36eb8f6 | |||
| d0929ab89e | |||
| df6646103a | |||
| 014affe1ea | |||
| 53fc948b00 | |||
| f389e925d2 | |||
| ef47ec9393 | |||
| 62d800e99a | |||
| a79c9c1ade | |||
| 4505ca85b2 | |||
| 3c0c050b3a | |||
| 2cd915ba77 | |||
| 4866ecd204 | |||
| f0071aad6d | |||
| 0d4a00ae2b | |||
| 90384d0852 | |||
| 47183ebbff | |||
| d68f70b3dd | |||
| e1b1479cfc | |||
| 16e4954f10 | |||
| a1b375c929 | |||
| 929f8e1a44 | |||
| 4f97d1a3ef | |||
| 255185ee8c | |||
| ad50582e92 | |||
| 6de6704502 | |||
| a5bc475cc1 | |||
| 4fd5cc5d70 | |||
| 236c37290e | |||
| 7beb2e3905 | |||
| d17bc1869f | |||
| 534118a47a | |||
| c7396349f1 | |||
| 089cc1a5dd | |||
| 7bfa0304af | |||
| 842f39e9ff | |||
| dd308f6d8f | |||
| 1a72158a9a | |||
| 94ab309335 | |||
| f4571289a5 | |||
| b9b0cc6b37 | |||
| 34ad221f5d | |||
| 7d8acd5dd6 | |||
| dba8ea7b99 | |||
| 49eec58de2 | |||
| f2d635ab44 | |||
| a7cd9e072b | |||
| b70706f150 | |||
| 0d0a3f5ebb | |||
| be7fad76fc | |||
| 1674dc7339 | |||
| f0e87fa5e9 | |||
| 1b385afa5b | |||
| b5843acc38 | |||
| 863c49ffd4 | |||
| 4e5d1f6ad0 | |||
| 2f0d8d814b | |||
| a86eba494f | |||
| 2549372bb7 | |||
| 38cdde7479 | |||
| 853f616cc8 | |||
| 2b3a4e1278 | |||
| 825e693efd | |||
| 686c8f7337 | |||
| 11f4e42fe9 | |||
| bc459ae178 | |||
| 1392b6e1a5 | |||
| 3db96faa00 | |||
| 399fbcb676 | |||
| eed1ced71b | |||
| d080833d5c | |||
| e998528e8e | |||
| 3472ee329d | |||
| 577b127287 | |||
| d85566bb98 | |||
| 5f41af35e2 | |||
| e1a5b4dd27 | |||
| a2baa37901 | |||
| 922ab45343 | |||
| 962774996e | |||
| d79594cbcb | |||
| bf8fe4cad7 | |||
| 65752ce378 | |||
| 95f08aeb3d | |||
| cd7bc1b262 | |||
| be7f6a76a9 | |||
| 1ddd0632c9 | |||
| 53d0957383 | |||
| 10e5b7e9d7 | |||
| fc38c534f9 | |||
| 90e6dc91eb | |||
| 2e502024a6 | |||
| b4a4d83ce7 | |||
| ef29820fa1 | |||
| fd47bcb8a8 | |||
| 972599b1b5 | |||
| f5d3cca6a0 | |||
| 6d3ae11e44 | |||
| dd63e76dfb | |||
| 7d6f37d98f | |||
| a015742d65 | |||
| 3ee8f86aa3 | |||
| 9b285ec93b | |||
| 23f66e3caa | |||
| 7a44c59581 | |||
| 4d343d9bcf | |||
| 777f8f7e20 | |||
| de6d84acd2 | |||
| eac48382e8 | |||
| d1a910f11f | |||
| 9f09a4b0b2 | |||
| 3c47fe7b60 | |||
| 45a0822e9b | |||
| 8cc87f3858 | |||
| e818695947 | |||
| bbba20288e | |||
| ff9dd3f6e2 | |||
| 4ad0a6fd9d | |||
| a94a62d34c | |||
| e861d3c256 | |||
| 7adff88d0f | |||
| ad1f1b2dc9 | |||
| 8d8b039dda | |||
| c875547942 | |||
| 1676a9c381 | |||
| 49d293e749 | |||
| 5d1b033486 | |||
| 31f77513da | |||
| 98d7829d1a | |||
| c6f706e47a | |||
| 532afd7336 | |||
| ac7f1a0c66 | |||
| cb26f055d7 | |||
| 34107f935e | |||
| cc2d19e951 | |||
| 031a15ec86 | |||
| fc2db2575d | |||
| fd549631e6 | |||
| 417c246d61 | |||
| 038d770691 | |||
| ce28ec2039 | |||
| 0f1781c02e | |||
| 4ce6ee0890 | |||
| f8050a5cd5 | |||
| d44dac448b | |||
| 67c20abcba | |||
| d56e132896 | |||
| 009ec2539d | |||
| ff0860cbe1 | |||
| ecfb99974b | |||
| aa3a18f421 | |||
| c2f18a91be | |||
| fc6b14b85e | |||
| 0c1208928f | |||
| 02d9963fab | |||
| f131fb71cf | |||
| 22185c5440 | |||
| 9c27ed6cb7 | |||
| 35edaa19c7 | |||
| dc09201866 | |||
| 6afcbf8f70 | |||
| 2894d52efa | |||
| a21f9f177c | |||
| 02f968b8cb | |||
| 32f0385e30 | |||
| b105d9d80e | |||
| 9bfad5d6a4 | |||
| 85a335d365 | |||
| 40e6778e31 | |||
| feba6643a6 | |||
| 49c893771d | |||
| d73f4c2ded | |||
| 13a056ec8d | |||
| bd0ccd0c21 | |||
| d34508c19d | |||
| a8e118fe83 | |||
| 072cc066b6 | |||
| 17562c96ae | |||
| f55452d1c6 | |||
| 14b5fd41b8 | |||
| 0f4d7bd520 | |||
| a95fbf2612 | |||
| 0f60ca61cb | |||
| 293a73136e | |||
| 3b56fb4a2f | |||
| 26a0f6f939 | |||
| 8de3276ce6 | |||
| f77c5810c6 | |||
| 9fc5f14dd7 | |||
| 55d7a4a263 | |||
| cca1eccce6 | |||
| 56eef9cf22 | |||
| b33d621696 | |||
| 45b78eff8d | |||
| a133406b6e | |||
| bd62962ee1 | |||
| f1e54c8a5c | |||
| a5da182bf4 | |||
| a4a48fddd2 | |||
| 2bd18859b9 | |||
| 32f8d2d944 | |||
| e1de599668 | |||
| 0e01cbed06 | |||
| 566425c531 | |||
| bf476940e9 | |||
| ab2ba8104d | |||
| a219f37035 | |||
| 8821c68e9c | |||
| 27c05f4e5b | |||
| 7571c1b980 | |||
| bb65c4ce14 | |||
| 69ae9973da | |||
| 36c0af82fe | |||
| eba1f16ee1 | |||
| f397691fdb | |||
| 9a5be2c5db | |||
| 39ac9f9a8c | |||
| c353eeae17 | |||
| 467c6ff055 | |||
| 5beacf0ef2 | |||
| e7448e7908 | |||
| 973c16f088 | |||
| 77f880af6e | |||
| 1c4386a67b | |||
| 88dd510e72 | |||
| e278a3b57d | |||
| 7786df3262 | |||
| 5ac08e5a92 | |||
| b05d956d95 | |||
| 6cdb80db1f | |||
| 4db99824af | |||
| d9f224fa6e | |||
| 72b51d50bc | |||
| b2e245bd85 | |||
| 9a9854cf92 | |||
| 1e27ff5d4a | |||
| 37f1726ee6 | |||
| d17cadc4c7 | |||
| d5ea735df7 | |||
| e150ea4a59 | |||
| 91c01dc643 |
@@ -1,10 +1,10 @@
|
|||||||
# SmartThings Public Github Repo
|
# SmartThings Public GitHub Repo
|
||||||
|
|
||||||
An official list of SmartApps and Device Types from SmartThings.
|
An official list of SmartApps and Device Types from SmartThings.
|
||||||
|
|
||||||
Here are some links to help you get started coding right away:
|
Here are some links to help you get started coding right away:
|
||||||
|
|
||||||
* [Github-specific Documentation](http://docs.smartthings.com/en/latest/tools-and-ide/github-integration.html)
|
* [GitHub-specific Documentation](http://docs.smartthings.com/en/latest/tools-and-ide/github-integration.html)
|
||||||
* [Full Documentation](http://docs.smartthings.com)
|
* [Full Documentation](http://docs.smartthings.com)
|
||||||
* [IDE & Simulator](http://ide.smartthings.com)
|
* [IDE & Simulator](http://ide.smartthings.com)
|
||||||
* [Community Forums](http://community.smartthings.com)
|
* [Community Forums](http://community.smartthings.com)
|
||||||
|
|||||||
+30
-2
@@ -9,7 +9,7 @@ apply plugin: 'smartthings-slack'
|
|||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath "com.smartthings.deployment:executable-deployment-scripts:1.0.7"
|
classpath "com.smartthings.deployment:executable-deployment-scripts:1.0.11"
|
||||||
}
|
}
|
||||||
repositories {
|
repositories {
|
||||||
mavenLocal()
|
mavenLocal()
|
||||||
@@ -19,7 +19,7 @@ buildscript {
|
|||||||
username smartThingsArtifactoryUserName
|
username smartThingsArtifactoryUserName
|
||||||
password smartThingsArtifactoryPassword
|
password smartThingsArtifactoryPassword
|
||||||
}
|
}
|
||||||
url "http://artifactory.smartthings.com/libs-release-local"
|
url "https://artifactory.smartthings.com/libs-release-local"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -27,9 +27,37 @@ buildscript {
|
|||||||
repositories {
|
repositories {
|
||||||
mavenLocal()
|
mavenLocal()
|
||||||
jcenter()
|
jcenter()
|
||||||
|
maven {
|
||||||
|
credentials {
|
||||||
|
username smartThingsArtifactoryUserName
|
||||||
|
password smartThingsArtifactoryPassword
|
||||||
|
}
|
||||||
|
url "https://artifactory.smartthings.com/libs-release-local"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
devicetypes {
|
||||||
|
groovy {
|
||||||
|
srcDirs = ['devicetypes']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
smartapps {
|
||||||
|
groovy {
|
||||||
|
srcDirs = ['smartapps']
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
devicetypesCompile 'org.codehaus.groovy:groovy-all:2.4.7'
|
||||||
|
devicetypesCompile 'smartthings:appengine-z-wave:0.1.2'
|
||||||
|
devicetypesCompile 'smartthings:appengine-zigbee:0.1.11'
|
||||||
|
smartappsCompile 'org.codehaus.groovy:groovy-all:2.4.7'
|
||||||
|
smartappsCompile 'smartthings:appengine-common:0.1.8'
|
||||||
|
smartappsCompile 'org.codehaus.groovy.modules.http-builder:http-builder:0.7.1'
|
||||||
|
smartappsCompile 'org.grails:grails-web:2.3.11'
|
||||||
|
smartappsCompile 'org.json:json:20140107'
|
||||||
}
|
}
|
||||||
|
|
||||||
slackSendMessage {
|
slackSendMessage {
|
||||||
|
|||||||
+3
-1
@@ -5,7 +5,9 @@ machine:
|
|||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
override:
|
override:
|
||||||
- echo "Nothing to do."
|
- ./gradlew dependencies -PsmartThingsArtifactoryUserName="$ARTIFACTORY_USERNAME" -PsmartThingsArtifactoryPassword="$ARTIFACTORY_PASSWORD"
|
||||||
|
post:
|
||||||
|
- ./gradlew compileSmartappsGroovy compileDevicetypesGroovy -PsmartThingsArtifactoryUserName="$ARTIFACTORY_USERNAME" -PsmartThingsArtifactoryPassword="$ARTIFACTORY_PASSWORD"
|
||||||
|
|
||||||
test:
|
test:
|
||||||
override:
|
override:
|
||||||
|
|||||||
+2
-2
@@ -23,8 +23,8 @@ metadata {
|
|||||||
|
|
||||||
tiles {
|
tiles {
|
||||||
standardTile("acceleration", "device.acceleration", width: 2, height: 2) {
|
standardTile("acceleration", "device.acceleration", width: 2, height: 2) {
|
||||||
state("inactive", label:'${name}', icon:"st.motion.acceleration.inactive", backgroundColor:"#ffffff")
|
state("inactive", label:'${name}', icon:"st.motion.acceleration.inactive", backgroundColor:"#cccccc")
|
||||||
state("active", label:'${name}', icon:"st.motion.acceleration.active", backgroundColor:"#53a7c0")
|
state("active", label:'${name}', icon:"st.motion.acceleration.active", backgroundColor:"#00A0DC")
|
||||||
}
|
}
|
||||||
|
|
||||||
main "acceleration"
|
main "acceleration"
|
||||||
|
|||||||
+2
-2
@@ -23,8 +23,8 @@ metadata {
|
|||||||
|
|
||||||
tiles {
|
tiles {
|
||||||
standardTile("contact", "device.contact", width: 2, height: 2) {
|
standardTile("contact", "device.contact", width: 2, height: 2) {
|
||||||
state("closed", label:'${name}', icon:"st.contact.contact.closed", backgroundColor:"#79b821")
|
state("closed", label:'${name}', icon:"st.contact.contact.closed", backgroundColor:"#00A0DC")
|
||||||
state("open", label:'${name}', icon:"st.contact.contact.open", backgroundColor:"#ffa81e")
|
state("open", label:'${name}', icon:"st.contact.contact.open", backgroundColor:"#e86d13")
|
||||||
}
|
}
|
||||||
main "contact"
|
main "contact"
|
||||||
details "contact"
|
details "contact"
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ metadata {
|
|||||||
tiles {
|
tiles {
|
||||||
standardTile("toggle", "device.lock", width: 2, height: 2) {
|
standardTile("toggle", "device.lock", width: 2, height: 2) {
|
||||||
state "unlocked", label:'unlocked', action:"lock.lock", icon:"st.locks.lock.unlocked", backgroundColor:"#ffffff"
|
state "unlocked", label:'unlocked', action:"lock.lock", icon:"st.locks.lock.unlocked", backgroundColor:"#ffffff"
|
||||||
state "locked", label:'locked', action:"lock.unlock", icon:"st.locks.lock.locked", backgroundColor:"#79b821"
|
state "locked", label:'locked', action:"lock.unlock", icon:"st.locks.lock.locked", backgroundColor:"#00A0DC"
|
||||||
}
|
}
|
||||||
standardTile("lock", "device.lock", inactiveLabel: false, decoration: "flat") {
|
standardTile("lock", "device.lock", inactiveLabel: false, decoration: "flat") {
|
||||||
state "default", label:'lock', action:"lock.lock", icon:"st.locks.lock.locked"
|
state "default", label:'lock', action:"lock.lock", icon:"st.locks.lock.locked"
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ metadata {
|
|||||||
tiles {
|
tiles {
|
||||||
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
|
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
|
||||||
state "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff", nextState: "on"
|
state "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff", nextState: "on"
|
||||||
state "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#79b821"
|
state "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#00A0DC"
|
||||||
}
|
}
|
||||||
main "switch"
|
main "switch"
|
||||||
details "switch"
|
details "switch"
|
||||||
|
|||||||
+1
-1
@@ -24,7 +24,7 @@ metadata {
|
|||||||
tiles {
|
tiles {
|
||||||
standardTile("motion", "device.motion", width: 2, height: 2) {
|
standardTile("motion", "device.motion", width: 2, height: 2) {
|
||||||
state("inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#ffffff")
|
state("inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#ffffff")
|
||||||
state("active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#53a7c0")
|
state("active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#00A0DC")
|
||||||
}
|
}
|
||||||
main "motion"
|
main "motion"
|
||||||
details "motion"
|
details "motion"
|
||||||
|
|||||||
+1
-1
@@ -24,7 +24,7 @@ metadata {
|
|||||||
tiles {
|
tiles {
|
||||||
standardTile("presence", "device.presence", width: 2, height: 2) {
|
standardTile("presence", "device.presence", width: 2, height: 2) {
|
||||||
state("not present", label:'not present', icon:"st.presence.tile.not-present", backgroundColor:"#ffffff")
|
state("not present", label:'not present', icon:"st.presence.tile.not-present", backgroundColor:"#ffffff")
|
||||||
state("present", label:'present', icon:"st.presence.tile.present", backgroundColor:"#53a7c0")
|
state("present", label:'present', icon:"st.presence.tile.present", backgroundColor:"#00A0DC")
|
||||||
}
|
}
|
||||||
main "presence"
|
main "presence"
|
||||||
details "presence"
|
details "presence"
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ metadata {
|
|||||||
tiles {
|
tiles {
|
||||||
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
|
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
|
||||||
state "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff"
|
state "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff"
|
||||||
state "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#79b821"
|
state "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#00A0DC"
|
||||||
}
|
}
|
||||||
main "switch"
|
main "switch"
|
||||||
details "switch"
|
details "switch"
|
||||||
|
|||||||
@@ -35,8 +35,8 @@ metadata {
|
|||||||
tiles {
|
tiles {
|
||||||
standardTile("switch", "device.switch", width: 2, height: 2) {
|
standardTile("switch", "device.switch", width: 2, height: 2) {
|
||||||
state "off", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
state "off", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
state "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"turningOff"
|
state "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#00A0DC", nextState:"turningOff"
|
||||||
state "turningOn", label:'${name}', icon:"st.switches.switch.on", backgroundColor:"#79b821"
|
state "turningOn", label:'${name}', icon:"st.switches.switch.on", backgroundColor:"#00A0DC"
|
||||||
state "turningOff", label:'${name}', icon:"st.switches.switch.off", backgroundColor:"#ffffff"
|
state "turningOff", label:'${name}', icon:"st.switches.switch.off", backgroundColor:"#ffffff"
|
||||||
}
|
}
|
||||||
controlTile("levelSliderControl", "device.level", "slider", height: 2, width: 1, inactiveLabel: false) {
|
controlTile("levelSliderControl", "device.level", "slider", height: 2, width: 1, inactiveLabel: false) {
|
||||||
|
|||||||
@@ -79,8 +79,8 @@ metadata {
|
|||||||
standardTile("mode", "device.thermostatMode", inactiveLabel: false, decoration: "flat") {
|
standardTile("mode", "device.thermostatMode", inactiveLabel: false, decoration: "flat") {
|
||||||
state "off", label:'${name}', action:"thermostat.emergencyHeat", backgroundColor:"#ffffff"
|
state "off", label:'${name}', action:"thermostat.emergencyHeat", backgroundColor:"#ffffff"
|
||||||
state "emergencyHeat", label:'${name}', action:"thermostat.heat", backgroundColor:"#e86d13"
|
state "emergencyHeat", label:'${name}', action:"thermostat.heat", backgroundColor:"#e86d13"
|
||||||
state "heat", label:'${name}', action:"thermostat.cool", backgroundColor:"#ffc000"
|
state "heat", label:'${name}', action:"thermostat.cool", backgroundColor:"#e86d13"
|
||||||
state "cool", label:'${name}', action:"thermostat.off", backgroundColor:"#269bd2"
|
state "cool", label:'${name}', action:"thermostat.off", backgroundColor:"#00A0DC"
|
||||||
}
|
}
|
||||||
standardTile("fanMode", "device.thermostatFanMode", inactiveLabel: false, decoration: "flat") {
|
standardTile("fanMode", "device.thermostatFanMode", inactiveLabel: false, decoration: "flat") {
|
||||||
state "fanAuto", label:'${name}', action:"thermostat.fanOn", backgroundColor:"#ffffff"
|
state "fanAuto", label:'${name}', action:"thermostat.fanOn", backgroundColor:"#ffffff"
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ metadata {
|
|||||||
tiles {
|
tiles {
|
||||||
standardTile("water", "device.water", width: 2, height: 2) {
|
standardTile("water", "device.water", width: 2, height: 2) {
|
||||||
state "dry", icon:"st.alarm.water.dry", backgroundColor:"#ffffff"
|
state "dry", icon:"st.alarm.water.dry", backgroundColor:"#ffffff"
|
||||||
state "wet", icon:"st.alarm.water.wet", backgroundColor:"#53a7c0"
|
state "wet", icon:"st.alarm.water.wet", backgroundColor:"#00A0DC"
|
||||||
}
|
}
|
||||||
|
|
||||||
main "water"
|
main "water"
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ metadata {
|
|||||||
|
|
||||||
tiles {
|
tiles {
|
||||||
standardTile("presence", "device.presence", width: 2, height: 2, canChangeBackground: true) {
|
standardTile("presence", "device.presence", width: 2, height: 2, canChangeBackground: true) {
|
||||||
state("present", labelIcon:"st.presence.tile.present", backgroundColor:"#53a7c0")
|
state("present", labelIcon:"st.presence.tile.present", backgroundColor:"#00A0DC")
|
||||||
state("not present", labelIcon:"st.presence.tile.not-present", backgroundColor:"#ffffff")
|
state("not present", labelIcon:"st.presence.tile.not-present", backgroundColor:"#ffffff")
|
||||||
}
|
}
|
||||||
valueTile("inRange", "device.inRangeFriendly", inactiveLabel: true, height:1, width:3, decoration: "flat") {
|
valueTile("inRange", "device.inRangeFriendly", inactiveLabel: true, height:1, width:3, decoration: "flat") {
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ metadata {
|
|||||||
// Main
|
// Main
|
||||||
standardTile("main", "device.status", width: 1, height: 1, canChangeIcon: true) {
|
standardTile("main", "device.status", width: 1, height: 1, canChangeIcon: true) {
|
||||||
state "paused", label:'Paused', action:"music Player.play", icon:"st.Electronics.electronics19", nextState:"playing", backgroundColor:"#ffffff"
|
state "paused", label:'Paused', action:"music Player.play", icon:"st.Electronics.electronics19", nextState:"playing", backgroundColor:"#ffffff"
|
||||||
state "playing", label:'Playing', action:"music Player.pause", icon:"st.Electronics.electronics19", nextState:"paused", backgroundColor:"#79b821"
|
state "playing", label:'Playing', action:"music Player.pause", icon:"st.Electronics.electronics19", nextState:"paused", backgroundColor:"#00A0DC"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Row 1
|
// Row 1
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
metadata {
|
metadata {
|
||||||
definition (name: "Netatmo Additional Module", namespace: "dianoga", author: "Brian Steere") {
|
definition (name: "Netatmo Additional Module", namespace: "dianoga", author: "Brian Steere") {
|
||||||
|
capability "Sensor"
|
||||||
capability "Relative Humidity Measurement"
|
capability "Relative Humidity Measurement"
|
||||||
capability "Temperature Measurement"
|
capability "Temperature Measurement"
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
metadata {
|
metadata {
|
||||||
definition (name: "Netatmo Basestation", namespace: "dianoga", author: "Brian Steere") {
|
definition (name: "Netatmo Basestation", namespace: "dianoga", author: "Brian Steere") {
|
||||||
|
capability "Sensor"
|
||||||
capability "Relative Humidity Measurement"
|
capability "Relative Humidity Measurement"
|
||||||
capability "Temperature Measurement"
|
capability "Temperature Measurement"
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
metadata {
|
metadata {
|
||||||
definition (name: "Netatmo Outdoor Module", namespace: "dianoga", author: "Brian Steere") {
|
definition (name: "Netatmo Outdoor Module", namespace: "dianoga", author: "Brian Steere") {
|
||||||
|
capability "Sensor"
|
||||||
capability "Relative Humidity Measurement"
|
capability "Relative Humidity Measurement"
|
||||||
capability "Temperature Measurement"
|
capability "Temperature Measurement"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,8 @@
|
|||||||
*/
|
*/
|
||||||
metadata {
|
metadata {
|
||||||
definition (name: "Netatmo Rain", namespace: "dianoga", author: "Brian Steere") {
|
definition (name: "Netatmo Rain", namespace: "dianoga", author: "Brian Steere") {
|
||||||
|
capability "Sensor"
|
||||||
|
|
||||||
attribute "rain", "number"
|
attribute "rain", "number"
|
||||||
attribute "rainSumHour", "number"
|
attribute "rainSumHour", "number"
|
||||||
attribute "rainSumDay", "number"
|
attribute "rainSumDay", "number"
|
||||||
|
|||||||
@@ -0,0 +1,426 @@
|
|||||||
|
// Express Controls EZMultiPli Multi-sensor
|
||||||
|
// Motion Sensor - Temperature - Light level - 8 Color Indicator LED - Z-Wave Range Extender - Wall Powered
|
||||||
|
// driver for SmartThings
|
||||||
|
// The EZMultiPli is also known as the HSM200 from HomeSeer.com
|
||||||
|
//
|
||||||
|
// 2017-04-10 - DrZwave (with help from Don Kirker) - changed fingerprint to the new format, lowered the OnTime
|
||||||
|
// and other parameters to be "more in line with ST user expectations", get the luminance in LUX so it reports in lux all the time.
|
||||||
|
// 2016-10-06 - erocm1231 - Added "updated" method to run when configuration options are changed. Depending on model of unit, luminance is being
|
||||||
|
// reported as a relative percentace or as a lux value. Added the option to configure this in the handler.
|
||||||
|
// 2016-01-28 - erocm1231 - Changed the configuration method to use scaledConfiguration so that it properly formatted negative numbers.
|
||||||
|
// Also, added configurationGet and a configurationReport method so that config values can be verified.
|
||||||
|
// 2015-12-04 - erocm1231 - added range value to preferences as suggested by @Dela-Rick.
|
||||||
|
// 2015-11-26 - erocm1231 - Fixed null condition error when adding as a new device.
|
||||||
|
// 2015-11-24 - erocm1231 - Added refresh command. Made a few changes to how the handler maps colors to the LEDs. Fixed
|
||||||
|
// the device not having its on/off status updated when colors are changed.
|
||||||
|
// 2015-11-23 - erocm1231 - Changed the look to match SmartThings v2 devices.
|
||||||
|
// 2015-11-21 - erocm1231 - Made code much more efficient. Also made it compatible when setColor is passed a hex value.
|
||||||
|
// Mapping of special colors: Soft White - Default - Yellow, White - Concentrate - White,
|
||||||
|
// Daylight - Energize - Teal, Warm White - Relax - Yellow
|
||||||
|
// 2015-11-19 - erocm1231 - Fixed a couple incorrect colors, changed setColor to be more compatible with other apps
|
||||||
|
// 2015-11-18 - erocm1231 - Added to setColor for compatibility with Smart Lighting
|
||||||
|
// v0.1.0 - DrZWave - chose better icons, Got color LED to work - first fully functional version
|
||||||
|
// v0.0.9 - jrs - got the temp and luminance to work. Motion works. Debugging the color wheel.
|
||||||
|
// v0.0.8 - DrZWave 2/25/2015 - change the color control to be tiles since there are only 8 colors.
|
||||||
|
// v0.0.7 - jrs - 02/23/2015 - Jim Sulin
|
||||||
|
|
||||||
|
metadata {
|
||||||
|
definition (name: "EZmultiPli", namespace: "DrZWave", author: "Eric Ryherd", oauth: true) {
|
||||||
|
capability "Actuator"
|
||||||
|
capability "Sensor"
|
||||||
|
capability "Motion Sensor"
|
||||||
|
capability "Temperature Measurement"
|
||||||
|
capability "Illuminance Measurement"
|
||||||
|
capability "Switch"
|
||||||
|
capability "Color Control"
|
||||||
|
capability "Configuration"
|
||||||
|
capability "Refresh"
|
||||||
|
|
||||||
|
fingerprint mfr: "001E", prod: "0004", model: "0001" // new format for Fingerprint which is unique for every certified Z-Wave product
|
||||||
|
} // end definition
|
||||||
|
|
||||||
|
simulator {
|
||||||
|
// messages the device returns in response to commands it receives
|
||||||
|
status "motion" : "command: 7105000000FF07, payload: 07"
|
||||||
|
status "no motion" : "command: 7105000000FF07, payload: 00"
|
||||||
|
|
||||||
|
for (int i = 0; i <= 100; i += 20) {
|
||||||
|
status "temperature ${i}F": new physicalgraph.zwave.Zwave().sensorMultilevelV5.sensorMultilevelReport(
|
||||||
|
scaledSensorValue: i, precision: 1, sensorType: 1, scale: 1).incomingMessage()
|
||||||
|
}
|
||||||
|
for (int i = 0; i <= 100; i += 20) {
|
||||||
|
status "luminance ${i} %": new physicalgraph.zwave.Zwave().sensorMultilevelV5.sensorMultilevelReport(
|
||||||
|
scaledSensorValue: i, precision: 0, sensorType: 3).incomingMessage()
|
||||||
|
}
|
||||||
|
|
||||||
|
} //end simulator
|
||||||
|
|
||||||
|
|
||||||
|
tiles (scale: 2){
|
||||||
|
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
||||||
|
tileAttribute ("device.switch", key: "PRIMARY_CONTROL", icon: "st.Lighting.light18") {
|
||||||
|
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#79b821", nextState:"turningOff"
|
||||||
|
attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
|
attributeState "turningOn", label:'${name}', icon:"st.switches.light.on", backgroundColor:"#79b821"
|
||||||
|
attributeState "turningOff", label:'${name}', icon:"st.switches.light.off", backgroundColor:"#ffffff"
|
||||||
|
}
|
||||||
|
tileAttribute ("device.color", key: "COLOR_CONTROL") {
|
||||||
|
attributeState "color", action:"setColor"
|
||||||
|
}
|
||||||
|
tileAttribute ("statusText", key: "SECONDARY_CONTROL") {
|
||||||
|
attributeState "statusText", label:'${currentValue}'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
standardTile("motion", "device.motion", width: 2, height: 2, canChangeIcon: true, canChangeBackground: true) {
|
||||||
|
state "active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#53a7c0"
|
||||||
|
state "inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#ffffff"
|
||||||
|
}
|
||||||
|
valueTile("temperature", "device.temperature", width: 2, height: 2) {
|
||||||
|
state "temperature", label:'${currentValue}°', unit:"F", icon:"", // would be better if the units would switch to the desired units of the system (imperial or metric)
|
||||||
|
backgroundColors:[
|
||||||
|
[value: 0, color: "#1010ff"], // blue=cold
|
||||||
|
[value: 65, color: "#a0a0f0"],
|
||||||
|
[value: 70, color: "#e0e050"],
|
||||||
|
[value: 75, color: "#f0d030"], // yellow
|
||||||
|
[value: 80, color: "#fbf020"],
|
||||||
|
[value: 85, color: "#fbdc01"],
|
||||||
|
[value: 90, color: "#fb3a01"],
|
||||||
|
[value: 95, color: "#fb0801"] // red=hot
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
// icons to use would be st.Weather.weather2 or st.alarm.temperature.normal - see http://scripts.3dgo.net/smartthings/icons/ for a list of icons
|
||||||
|
valueTile("illuminance", "device.illuminance", width: 2, height: 2, inactiveLabel: false) {
|
||||||
|
// jrs 4/7/2015 - Null on display
|
||||||
|
//state "luminosity", label:'${currentValue} ${unit}'
|
||||||
|
state "luminosity", label:'${currentValue}', unit:'${currentValue}', icon:"",
|
||||||
|
backgroundColors:[
|
||||||
|
[value: 25, color: "#404040"],
|
||||||
|
[value: 50, color: "#808080"],
|
||||||
|
[value: 75, color: "#a0a0a0"],
|
||||||
|
[value: 90, color: "#e0e0e0"],
|
||||||
|
//lux measurement values
|
||||||
|
[value: 150, color: "#404040"],
|
||||||
|
[value: 300, color: "#808080"],
|
||||||
|
[value: 600, color: "#a0a0a0"],
|
||||||
|
[value: 900, color: "#e0e0e0"]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
||||||
|
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
|
||||||
|
}
|
||||||
|
standardTile("configure", "device.configure", inactiveLabel: false, width: 2, height: 2, decoration: "flat") {
|
||||||
|
state "configure", label:'', action:"configuration.configure", icon:"st.secondary.configure"
|
||||||
|
}
|
||||||
|
|
||||||
|
main (["temperature","motion", "switch"])
|
||||||
|
details(["switch", "motion", "temperature", "illuminance", "refresh", "configure"])
|
||||||
|
} // end tiles
|
||||||
|
|
||||||
|
preferences {
|
||||||
|
input "OnTime", "number", title: "No Motion Interval", description: "N minutes lights stay on after no motion detected [0, 1-127]", range: "0..127", defaultValue: 2, displayDuringSetup: true, required: false
|
||||||
|
input "OnLevel", "number", title: "Dimmer Onlevel", description: "Dimmer OnLevel for associated node 2 lights [-1, 0, 1-99]", range: "-1..99", defaultValue: -1, displayDuringSetup: true, required: false
|
||||||
|
input "LiteMin", "number", title: "Luminance Report Frequency", description: "Luminance report sent every N minutes [0-127]", range: "0..127", defaultValue: 6, displayDuringSetup: true, required: false
|
||||||
|
input "TempMin", "number", title: "Temperature Report Frequency", description: "Temperature report sent every N minutes [0-127]", range: "0..127", defaultValue: 6, displayDuringSetup: true, required: false
|
||||||
|
input "TempAdj", "number", title: "Temperature Calibration", description: "Adjust temperature up/down N tenths of a degree F [(-127)-(+128)]", range: "-127..128", defaultValue: 0, displayDuringSetup: true, required: false
|
||||||
|
input("lum", "enum", title:"Illuminance Measurement", description: "Percent or Lux", defaultValue: 2 ,required: false, displayDuringSetup: true, options:
|
||||||
|
[1:"Percent",
|
||||||
|
2:"Lux"])
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end metadata
|
||||||
|
|
||||||
|
|
||||||
|
// Parse incoming device messages from device to generate events
|
||||||
|
def parse(String description){
|
||||||
|
//log.debug "==> New Zwave Event: ${description}"
|
||||||
|
def result = []
|
||||||
|
def cmd = zwave.parse(description, [0x31: 5]) // 0x31=SensorMultilevel which we force to be version 5
|
||||||
|
if (cmd) {
|
||||||
|
def cmdData = zwaveEvent(cmd)
|
||||||
|
if (cmdData != [:])
|
||||||
|
result << createEvent(cmdData)
|
||||||
|
}
|
||||||
|
|
||||||
|
def statusTextmsg = ""
|
||||||
|
if (device.currentState('temperature') != null && device.currentState('illuminance') != null) {
|
||||||
|
statusTextmsg = "${device.currentState('temperature').value} ° - ${device.currentState('illuminance').value} ${(lum == "" || lum == null || lum == 1) ? "%" : "LUX"}"
|
||||||
|
sendEvent("name":"statusText", "value":statusTextmsg, displayed:false)
|
||||||
|
}
|
||||||
|
if (result != [null] && result != []) log.debug "Parse returned ${result}"
|
||||||
|
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Event Generation
|
||||||
|
def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd){
|
||||||
|
def map = [:]
|
||||||
|
switch (cmd.sensorType) {
|
||||||
|
case 0x01: // SENSOR_TYPE_TEMPERATURE_VERSION_1
|
||||||
|
def cmdScale = cmd.scale == 1 ? "F" : "C"
|
||||||
|
map.value = convertTemperatureIfNeeded(cmd.scaledSensorValue, cmdScale, cmd.precision)
|
||||||
|
map.unit = getTemperatureScale()
|
||||||
|
map.name = "temperature"
|
||||||
|
log.debug "Temperature report"
|
||||||
|
break;
|
||||||
|
case 0x03 : // SENSOR_TYPE_LUMINANCE_VERSION_1
|
||||||
|
map.value = cmd.scaledSensorValue.toInteger().toString()
|
||||||
|
if(lum == "" || lum == null || lum == 1) map.unit = "%"
|
||||||
|
else map.unit = "lux"
|
||||||
|
map.name = "illuminance"
|
||||||
|
log.debug "Luminance report"
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return map
|
||||||
|
}
|
||||||
|
|
||||||
|
def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) {
|
||||||
|
log.debug "${device.displayName} parameter '${cmd.parameterNumber}' with a byte size of '${cmd.size}' is set to '${cmd.configurationValue}'"
|
||||||
|
}
|
||||||
|
|
||||||
|
def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) {
|
||||||
|
def map = [:]
|
||||||
|
if (cmd.notificationType==0x07) { // NOTIFICATION_TYPE_BURGLAR
|
||||||
|
if (cmd.event==0x07 || cmd.event==0x08) {
|
||||||
|
map.name = "motion"
|
||||||
|
map.value = "active"
|
||||||
|
map.descriptionText = "$device.displayName motion detected"
|
||||||
|
log.debug "motion recognized"
|
||||||
|
} else if (cmd.event==0) {
|
||||||
|
map.name = "motion"
|
||||||
|
map.value = "inactive"
|
||||||
|
map.descriptionText = "$device.displayName no motion detected"
|
||||||
|
log.debug "No motion recognized"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (map.name != "motion") {
|
||||||
|
log.debug "unmatched parameters for cmd: ${cmd.toString()}}"
|
||||||
|
}
|
||||||
|
return map
|
||||||
|
}
|
||||||
|
|
||||||
|
def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) {
|
||||||
|
if (cmd.value == 0 && device.latestState("color").value != "#ffffff") {
|
||||||
|
sendEvent(name: "color", value: "#ffffff", displayed: true)
|
||||||
|
}
|
||||||
|
[name: "switch", value: cmd.value ? "on" : "off", type: "digital"]
|
||||||
|
}
|
||||||
|
|
||||||
|
def updated()
|
||||||
|
{
|
||||||
|
log.debug "updated() is being called"
|
||||||
|
|
||||||
|
def cmds = configure()
|
||||||
|
|
||||||
|
if (cmds != []) response(cmds)
|
||||||
|
}
|
||||||
|
|
||||||
|
def on() {
|
||||||
|
log.debug "Turning Light 'on'"
|
||||||
|
delayBetween([
|
||||||
|
zwave.basicV1.basicSet(value: 0xFF).format(),
|
||||||
|
zwave.basicV1.basicGet().format()
|
||||||
|
], 500)
|
||||||
|
}
|
||||||
|
|
||||||
|
def off() {
|
||||||
|
log.debug "Turning Light 'off'"
|
||||||
|
delayBetween([
|
||||||
|
zwave.basicV1.basicSet(value: 0x00).format(),
|
||||||
|
zwave.basicV1.basicGet().format()
|
||||||
|
], 500)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def setColor(value) {
|
||||||
|
log.debug "setColor() : ${value}"
|
||||||
|
def myred
|
||||||
|
def mygreen
|
||||||
|
def myblue
|
||||||
|
def hexValue
|
||||||
|
def cmds = []
|
||||||
|
|
||||||
|
if ( value.level == 1 && value.saturation > 20) {
|
||||||
|
def rgb = huesatToRGB(value.hue as Integer, 100)
|
||||||
|
myred = rgb[0] >=128 ? 255 : 0
|
||||||
|
mygreen = rgb[1] >=128 ? 255 : 0
|
||||||
|
myblue = rgb[2] >=128 ? 255 : 0
|
||||||
|
}
|
||||||
|
else if ( value.level > 1 ) {
|
||||||
|
def rgb = huesatToRGB(value.hue as Integer, value.saturation as Integer)
|
||||||
|
myred = rgb[0] >=128 ? 255 : 0
|
||||||
|
mygreen = rgb[1] >=128 ? 255 : 0
|
||||||
|
myblue = rgb[2] >=128 ? 255 : 0
|
||||||
|
}
|
||||||
|
else if (value.hex) {
|
||||||
|
def rgb = value.hex.findAll(/[0-9a-fA-F]{2}/).collect { Integer.parseInt(it, 16) }
|
||||||
|
myred = rgb[0] >=128 ? 255 : 0
|
||||||
|
mygreen = rgb[1] >=128 ? 255 : 0
|
||||||
|
myblue = rgb[2] >=128 ? 255 : 0
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
myred=value.red >=128 ? 255 : 0 // the EZMultiPli has just on/off for each of the 3 channels RGB so convert the 0-255 value into 0 or 255.
|
||||||
|
mygreen=value.green >=128 ? 255 : 0
|
||||||
|
myblue=value.blue>=128 ? 255 : 0
|
||||||
|
}
|
||||||
|
//log.debug "Red: ${myred} Green: ${mygreen} Blue: ${myblue}"
|
||||||
|
//cmds << zwave.colorControlV1.stateSet(stateDataLength: 3, VariantGroup1: [0x02, myred], VariantGroup2:[ 0x03, mygreen], VariantGroup3:[0x04,myblue]).format() // ST support for this command as of 2015/02/23 does not support the color IDs so this command cannot be used.
|
||||||
|
// So instead we'll use these commands to hack around the lack of support of the above command
|
||||||
|
cmds << zwave.basicV1.basicSet(value: 0x00).format() // As of 2015/02/23 ST is not supporting stateSet properly but found this hack that works.
|
||||||
|
if (myred!=0) {
|
||||||
|
cmds << zwave.colorControlV1.startCapabilityLevelChange(capabilityId: 0x02, startState: myred, ignoreStartState: True, updown: True).format()
|
||||||
|
cmds << zwave.colorControlV1.stopStateChange(capabilityId: 0x02).format()
|
||||||
|
}
|
||||||
|
if (mygreen!=0) {
|
||||||
|
cmds << zwave.colorControlV1.startCapabilityLevelChange(capabilityId: 0x03, startState: mygreen, ignoreStartState: True, updown: True).format()
|
||||||
|
cmds << zwave.colorControlV1.stopStateChange(capabilityId: 0x03).format()
|
||||||
|
}
|
||||||
|
if (myblue!=0) {
|
||||||
|
cmds << zwave.colorControlV1.startCapabilityLevelChange(capabilityId: 0x04, startState: myblue, ignoreStartState: True, updown: True).format()
|
||||||
|
cmds << zwave.colorControlV1.stopStateChange(capabilityId: 0x04).format()
|
||||||
|
}
|
||||||
|
cmds << zwave.basicV1.basicGet().format()
|
||||||
|
hexValue = rgbToHex([r:myred, g:mygreen, b:myblue])
|
||||||
|
if(hexValue) sendEvent(name: "color", value: hexValue, displayed: true)
|
||||||
|
delayBetween(cmds, 100)
|
||||||
|
}
|
||||||
|
|
||||||
|
def zwaveEvent(physicalgraph.zwave.Command cmd) {
|
||||||
|
// Handles all Z-Wave commands we aren't interested in
|
||||||
|
[:]
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensure we are passing acceptable param values for LiteMin & TempMin configs
|
||||||
|
def checkLiteTempInput(value) {
|
||||||
|
if (value == null) {
|
||||||
|
value=60
|
||||||
|
}
|
||||||
|
def liteTempVal = value.toInteger()
|
||||||
|
switch (liteTempVal) {
|
||||||
|
case { it < 0 }:
|
||||||
|
return 60 // bad value, set to default
|
||||||
|
break
|
||||||
|
case { it > 127 }:
|
||||||
|
return 127 // bad value, greater then MAX, set to MAX
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
return liteTempVal // acceptable value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensure we are passing acceptable param value for OnTime config
|
||||||
|
def checkOnTimeInput(value) {
|
||||||
|
if (value == null) {
|
||||||
|
value=10
|
||||||
|
}
|
||||||
|
def onTimeVal = value.toInteger()
|
||||||
|
switch (onTimeVal) {
|
||||||
|
case { it < 0 }:
|
||||||
|
return 10 // bad value set to default
|
||||||
|
break
|
||||||
|
case { it > 127 }:
|
||||||
|
return 127 // bad value, greater then MAX, set to MAX
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
return onTimeVal // acceptable value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensure we are passing acceptable param value for OnLevel config
|
||||||
|
def checkOnLevelInput(value) {
|
||||||
|
if (value == null) {
|
||||||
|
value=99
|
||||||
|
}
|
||||||
|
def onLevelVal = value.toInteger()
|
||||||
|
switch (onLevelVal) {
|
||||||
|
case { it < -1 }:
|
||||||
|
return -1 // bad value set to default
|
||||||
|
break
|
||||||
|
case { it > 99 }:
|
||||||
|
return 99 // bad value, greater then MAX, set to MAX
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
return onLevelVal // acceptable value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ensure we are passing an acceptable param value for TempAdj configs
|
||||||
|
def checkTempAdjInput(value) {
|
||||||
|
if (value == null) {
|
||||||
|
value=0
|
||||||
|
}
|
||||||
|
def tempAdjVal = value.toInteger()
|
||||||
|
switch (tempAdjVal) {
|
||||||
|
case { it < -127 }:
|
||||||
|
return 0 // bad value, set to default
|
||||||
|
break
|
||||||
|
case { it > 128 }:
|
||||||
|
return 128 // bad value, greater then MAX, set to MAX
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
return tempAdjVal // acceptable value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def refresh() {
|
||||||
|
def cmd = []
|
||||||
|
cmd << zwave.switchColorV3.switchColorGet().format()
|
||||||
|
cmd << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType:1, scale:1).format()
|
||||||
|
cmd << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType:3, scale:1).format()
|
||||||
|
cmd << zwave.basicV1.basicGet().format()
|
||||||
|
delayBetween(cmd, 1000)
|
||||||
|
}
|
||||||
|
|
||||||
|
def configure() {
|
||||||
|
log.debug "OnTime=${settings.OnTime} OnLevel=${settings.OnLevel} TempAdj=${settings.TempAdj}"
|
||||||
|
def cmd = delayBetween([
|
||||||
|
zwave.configurationV1.configurationSet(parameterNumber: 1, size: 1, scaledConfigurationValue: checkOnTimeInput(settings.OnTime)).format(),
|
||||||
|
zwave.configurationV1.configurationSet(parameterNumber: 2, size: 1, scaledConfigurationValue: checkOnLevelInput(settings.OnLevel)).format(),
|
||||||
|
zwave.configurationV1.configurationSet(parameterNumber: 3, size: 1, scaledConfigurationValue: checkLiteTempInput(settings.LiteMin)).format(),
|
||||||
|
zwave.configurationV1.configurationSet(parameterNumber: 4, size: 1, scaledConfigurationValue: checkLiteTempInput(settings.TempMin)).format(),
|
||||||
|
zwave.configurationV1.configurationSet(parameterNumber: 5, size: 1, scaledConfigurationValue: checkTempAdjInput(settings.TempAdj)).format(),
|
||||||
|
zwave.configurationV1.configurationGet(parameterNumber: 1).format(),
|
||||||
|
zwave.configurationV1.configurationGet(parameterNumber: 2).format(),
|
||||||
|
zwave.configurationV1.configurationGet(parameterNumber: 3).format(),
|
||||||
|
zwave.configurationV1.configurationGet(parameterNumber: 4).format(),
|
||||||
|
zwave.configurationV1.configurationGet(parameterNumber: 5).format()
|
||||||
|
], 100)
|
||||||
|
//log.debug cmd
|
||||||
|
cmd + refresh()
|
||||||
|
}
|
||||||
|
|
||||||
|
def huesatToRGB(float hue, float sat) {
|
||||||
|
while(hue >= 100) hue -= 100
|
||||||
|
int h = (int)(hue / 100 * 6)
|
||||||
|
float f = hue / 100 * 6 - h
|
||||||
|
int p = Math.round(255 * (1 - (sat / 100)))
|
||||||
|
int q = Math.round(255 * (1 - (sat / 100) * f))
|
||||||
|
int t = Math.round(255 * (1 - (sat / 100) * (1 - f)))
|
||||||
|
switch (h) {
|
||||||
|
case 0: return [255, t, p]
|
||||||
|
case 1: return [q, 255, p]
|
||||||
|
case 2: return [p, 255, t]
|
||||||
|
case 3: return [p, q, 255]
|
||||||
|
case 4: return [t, p, 255]
|
||||||
|
case 5: return [255, p, q]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
def rgbToHex(rgb) {
|
||||||
|
def r = hex(rgb.r)
|
||||||
|
def g = hex(rgb.g)
|
||||||
|
def b = hex(rgb.b)
|
||||||
|
def hexColor = "#${r}${g}${b}"
|
||||||
|
|
||||||
|
hexColor
|
||||||
|
}
|
||||||
|
private hex(value, width=2) {
|
||||||
|
def s = new BigInteger(Math.round(value).toString()).toString(16)
|
||||||
|
while (s.size() < width) {
|
||||||
|
s = "0" + s
|
||||||
|
}
|
||||||
|
s
|
||||||
|
}
|
||||||
@@ -0,0 +1,839 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* Fibaro Dimmer 2 (US)
|
||||||
|
*
|
||||||
|
* github: Eric Maycock (erocm123)
|
||||||
|
* email: erocmail@gmail.com
|
||||||
|
* Date: 2016-07-31 8:03PM
|
||||||
|
* Copyright Eric Maycock
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||||
|
* in compliance with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||||
|
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
|
||||||
|
* for the specific language governing permissions and limitations under the License.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
metadata {
|
||||||
|
definition (name: "Fibaro Dimmer 2", namespace: "erocm123", author: "Eric Maycock") {
|
||||||
|
capability "Actuator"
|
||||||
|
capability "Switch"
|
||||||
|
capability "Switch Level"
|
||||||
|
capability "Refresh"
|
||||||
|
capability "Configuration"
|
||||||
|
capability "Sensor"
|
||||||
|
capability "Polling"
|
||||||
|
capability "Energy Meter"
|
||||||
|
capability "Power Meter"
|
||||||
|
capability "Button"
|
||||||
|
capability "Health Check"
|
||||||
|
|
||||||
|
attribute "needUpdate", "string"
|
||||||
|
|
||||||
|
fingerprint deviceId: "0x1101", inClusters: "0x72,0x86,0x70,0x85,0x8E,0x26,0x7A,0x27,0x73,0xEF,0x26,0x2B"
|
||||||
|
fingerprint deviceId: "0x1101", inClusters: "0x5E,0x20,0x86,0x72,0x26,0x5A,0x59,0x85,0x73,0x98,0x7A,0x56,0x70,0x31,0x32,0x8E,0x60,0x75,0x71,0x27"
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
preferences {
|
||||||
|
input description: "Once you change values on this page, the corner of the \"configuration\" icon will change orange until all configuration parameters are updated.", title: "Settings", displayDuringSetup: false, type: "paragraph", element: "paragraph"
|
||||||
|
generate_preferences(configuration_model())
|
||||||
|
}
|
||||||
|
|
||||||
|
simulator {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
tiles(scale: 2){
|
||||||
|
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
||||||
|
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
||||||
|
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#00a0dc", nextState:"turningOff"
|
||||||
|
attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
|
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#00a0dc", nextState:"turningOff"
|
||||||
|
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
|
}
|
||||||
|
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
|
||||||
|
attributeState "level", action:"switch level.setLevel"
|
||||||
|
}
|
||||||
|
tileAttribute ("statusText", key: "SECONDARY_CONTROL") {
|
||||||
|
attributeState "statusText", label:'${currentValue}'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
||||||
|
state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh"
|
||||||
|
}
|
||||||
|
valueTile("power", "device.power", decoration: "flat", width: 2, height: 2) {
|
||||||
|
state "default", label:'${currentValue} W'
|
||||||
|
}
|
||||||
|
valueTile("energy", "device.energy", decoration: "flat", width: 2, height: 2) {
|
||||||
|
state "default", label:'${currentValue} kWh'
|
||||||
|
}
|
||||||
|
standardTile("reset", "device.energy", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
||||||
|
state "default", label:'reset kWh', action:"reset"
|
||||||
|
}
|
||||||
|
standardTile("configure", "device.needUpdate", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
||||||
|
state "NO" , label:'', action:"configuration.configure", icon:"st.secondary.configure"
|
||||||
|
state "YES", label:'', action:"configuration.configure", icon:"https://github.com/erocm123/SmartThingsPublic/raw/master/devicetypes/erocm123/qubino-flush-1d-relay.src/configure@2x.png"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
main "switch"
|
||||||
|
details (["switch", "power", "energy", "refresh", "configure", "reset"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def parse(String description) {
|
||||||
|
def result = null
|
||||||
|
if (description.startsWith("Err")) {
|
||||||
|
result = createEvent(descriptionText:description, isStateChange:true)
|
||||||
|
} else if (description != "updated") {
|
||||||
|
def cmd = zwave.parse(description, [0x20: 1, 0x84: 1, 0x98: 1, 0x56: 1, 0x60: 3])
|
||||||
|
if (cmd) {
|
||||||
|
result = zwaveEvent(cmd)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def statusTextmsg = ""
|
||||||
|
if (device.currentState('power') && device.currentState('energy')) statusTextmsg = "${device.currentState('power').value} W ${device.currentState('energy').value} kWh"
|
||||||
|
sendEvent(name:"statusText", value:statusTextmsg, displayed:false)
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) {
|
||||||
|
logging("BasicReport: $cmd")
|
||||||
|
def events = []
|
||||||
|
if (cmd.value == 0) {
|
||||||
|
events << createEvent(name: "switch", value: "off")
|
||||||
|
} else if (cmd.value == 255) {
|
||||||
|
events << createEvent(name: "switch", value: "on")
|
||||||
|
} else {
|
||||||
|
events << createEvent(name: "switch", value: "on")
|
||||||
|
events << createEvent(name: "switchLevel", value: cmd.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
def request = update_needed_settings()
|
||||||
|
|
||||||
|
if(request != []){
|
||||||
|
return [response(commands(request)), events]
|
||||||
|
} else {
|
||||||
|
return events
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def zwaveEvent(physicalgraph.zwave.commands.sceneactivationv1.SceneActivationSet cmd) {
|
||||||
|
logging("SceneActivationSet: $cmd")
|
||||||
|
logging("sceneId: $cmd.sceneId")
|
||||||
|
logging("dimmingDuration: $cmd.dimmingDuration")
|
||||||
|
logging("Configuration for preference \"Switch Type\" is set to ${settings."20"}")
|
||||||
|
|
||||||
|
if (settings."20" == "2") {
|
||||||
|
logging("Switch configured as Roller blinds")
|
||||||
|
switch (cmd.sceneId) {
|
||||||
|
// Roller blinds S1
|
||||||
|
case 10: // Turn On (1x click)
|
||||||
|
buttonEvent(1, "pushed")
|
||||||
|
break
|
||||||
|
case 13: // Release
|
||||||
|
buttonEvent(1, "held")
|
||||||
|
break
|
||||||
|
case 14: // 2x click
|
||||||
|
buttonEvent(2, "pushed")
|
||||||
|
break
|
||||||
|
case 17: // Brightening
|
||||||
|
buttonEvent(2, "held")
|
||||||
|
break
|
||||||
|
// Roller blinds S2
|
||||||
|
case 11: // Turn Off
|
||||||
|
buttonEvent(3, "pushed")
|
||||||
|
break
|
||||||
|
case 13: // Release
|
||||||
|
buttonEvent(3, "held")
|
||||||
|
break
|
||||||
|
case 14: // 2x click
|
||||||
|
buttonEvent(4, "pushed")
|
||||||
|
break
|
||||||
|
case 15: // 3x click
|
||||||
|
buttonEvent(5, "pushed")
|
||||||
|
break
|
||||||
|
case 18: // Dimming
|
||||||
|
buttonEvent(4, "held")
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
logging("Unhandled SceneActivationSet: ${cmd}")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
} else if (settings."20" == "1") {
|
||||||
|
logging("Switch configured as Toggle")
|
||||||
|
switch (cmd.sceneId) {
|
||||||
|
// Toggle S1
|
||||||
|
case 10: // Off to On
|
||||||
|
buttonEvent(1, "pushed")
|
||||||
|
break
|
||||||
|
case 11: // On to Off
|
||||||
|
buttonEvent(1, "held")
|
||||||
|
break
|
||||||
|
case 14: // 2x click
|
||||||
|
buttonEvent(2, "pushed")
|
||||||
|
break
|
||||||
|
// Toggle S2
|
||||||
|
case 20: // Off to On
|
||||||
|
buttonEvent(3, "pushed")
|
||||||
|
break
|
||||||
|
case 21: // On to Off
|
||||||
|
buttonEvent(3, "held")
|
||||||
|
break
|
||||||
|
case 24: // 2x click
|
||||||
|
buttonEvent(4, "pushed")
|
||||||
|
break
|
||||||
|
case 25: // 3x click
|
||||||
|
buttonEvent(5, "pushed")
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
logging("Unhandled SceneActivationSet: ${cmd}")
|
||||||
|
break
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (settings."20" == "0") logging("Switch configured as Momentary") else logging("Switch type not configured")
|
||||||
|
switch (cmd.sceneId) {
|
||||||
|
// Momentary S1
|
||||||
|
case 16: // 1x click
|
||||||
|
buttonEvent(1, "pushed")
|
||||||
|
break
|
||||||
|
case 14: // 2x click
|
||||||
|
buttonEvent(2, "pushed")
|
||||||
|
break
|
||||||
|
case 12: // held
|
||||||
|
buttonEvent(1, "held")
|
||||||
|
break
|
||||||
|
case 13: // release
|
||||||
|
buttonEvent(2, "held")
|
||||||
|
break
|
||||||
|
// Momentary S2
|
||||||
|
case 26: // 1x click
|
||||||
|
buttonEvent(3, "pushed")
|
||||||
|
break
|
||||||
|
case 24: // 2x click
|
||||||
|
buttonEvent(4, "pushed")
|
||||||
|
break
|
||||||
|
case 25: // 3x click
|
||||||
|
buttonEvent(5, "pushed")
|
||||||
|
break
|
||||||
|
case 22: // held
|
||||||
|
buttonEvent(3, "held")
|
||||||
|
break
|
||||||
|
case 23: // release
|
||||||
|
buttonEvent(4, "held")
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
logging("Unhandled SceneActivationSet: ${cmd}")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def buttonEvent(button, value) {
|
||||||
|
logging("buttonEvent() Button:$button, Value:$value")
|
||||||
|
createEvent(name: "button", value: value, data: [buttonNumber: button], descriptionText: "$device.displayName button $button was $value", isStateChange: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
def zwaveEvent(physicalgraph.zwave.commands.switchmultilevelv3.SwitchMultilevelReport cmd) {
|
||||||
|
logging(cmd)
|
||||||
|
dimmerEvents(cmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
def dimmerEvents(physicalgraph.zwave.Command cmd) {
|
||||||
|
logging(cmd)
|
||||||
|
def result = []
|
||||||
|
def value = (cmd.value ? "on" : "off")
|
||||||
|
def switchEvent = createEvent(name: "switch", value: value, descriptionText: "$device.displayName was turned $value")
|
||||||
|
result << switchEvent
|
||||||
|
if (cmd.value) {
|
||||||
|
result << createEvent(name: "level", value: cmd.value, unit: "%")
|
||||||
|
}
|
||||||
|
if (switchEvent.isStateChange) {
|
||||||
|
result << response(["delay 3000", zwave.meterV2.meterGet(scale: 2).format()])
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
def zwaveEvent(physicalgraph.zwave.commands.associationv2.AssociationReport cmd) {
|
||||||
|
logging("AssociationReport $cmd")
|
||||||
|
state."association${cmd.groupingIdentifier}" = cmd.nodeId[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) {
|
||||||
|
def encapsulatedCommand = cmd.encapsulatedCommand([0x20: 1, 0x84: 1])
|
||||||
|
if (encapsulatedCommand) {
|
||||||
|
state.sec = 1
|
||||||
|
def result = zwaveEvent(encapsulatedCommand)
|
||||||
|
result = result.collect {
|
||||||
|
if (it instanceof physicalgraph.device.HubAction && !it.toString().startsWith("9881")) {
|
||||||
|
response(cmd.CMD + "00" + it.toString())
|
||||||
|
} else {
|
||||||
|
it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def zwaveEvent(physicalgraph.zwave.commands.crc16encapv1.Crc16Encap cmd) {
|
||||||
|
def versions = [0x31: 5, 0x30: 1, 0x9C: 1, 0x70: 2, 0x85: 2]
|
||||||
|
def version = versions[cmd.commandClass as Integer]
|
||||||
|
def ccObj = version ? zwave.commandClass(cmd.commandClass, version) : zwave.commandClass(cmd.commandClass)
|
||||||
|
def encapsulatedCommand = ccObj?.command(cmd.command)?.parse(cmd.data)
|
||||||
|
if (encapsulatedCommand) {
|
||||||
|
zwaveEvent(encapsulatedCommand)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def zwaveEvent(physicalgraph.zwave.Command cmd) {
|
||||||
|
logging("Unhandled Z-Wave Event: $cmd")
|
||||||
|
}
|
||||||
|
|
||||||
|
def zwaveEvent(physicalgraph.zwave.commands.meterv3.MeterReport cmd) {
|
||||||
|
logging(cmd)
|
||||||
|
if (cmd.meterType == 1) {
|
||||||
|
if (cmd.scale == 0) {
|
||||||
|
return createEvent(name: "energy", value: cmd.scaledMeterValue, unit: "kWh")
|
||||||
|
} else if (cmd.scale == 1) {
|
||||||
|
return createEvent(name: "energy", value: cmd.scaledMeterValue, unit: "kVAh")
|
||||||
|
} else if (cmd.scale == 2) {
|
||||||
|
return createEvent(name: "power", value: Math.round(cmd.scaledMeterValue), unit: "W")
|
||||||
|
} else {
|
||||||
|
return createEvent(name: "electric", value: cmd.scaledMeterValue, unit: ["pulses", "V", "A", "R/Z", ""][cmd.scale - 3])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd){
|
||||||
|
logging("SensorMultilevelReport: $cmd")
|
||||||
|
def map = [:]
|
||||||
|
switch (cmd.sensorType) {
|
||||||
|
case 4:
|
||||||
|
map.name = "power"
|
||||||
|
map.value = cmd.scaledSensorValue.toInteger().toString()
|
||||||
|
map.unit = cmd.scale == 1 ? "Btu/h" : "W"
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
map.descriptionText = cmd.toString()
|
||||||
|
}
|
||||||
|
createEvent(map)
|
||||||
|
}
|
||||||
|
|
||||||
|
def on() {
|
||||||
|
commands([zwave.basicV1.basicSet(value: 0xFF), zwave.basicV1.basicGet()])
|
||||||
|
}
|
||||||
|
|
||||||
|
def off() {
|
||||||
|
commands([zwave.basicV1.basicSet(value: 0x00), zwave.basicV1.basicGet()])
|
||||||
|
}
|
||||||
|
|
||||||
|
def refresh() {
|
||||||
|
logging("$device.displayName refresh()")
|
||||||
|
|
||||||
|
def cmds = []
|
||||||
|
if (state.lastRefresh != null && now() - state.lastRefresh < 5000) {
|
||||||
|
logging("Refresh Double Press")
|
||||||
|
def configuration = parseXml(configuration_model())
|
||||||
|
configuration.Value.each
|
||||||
|
{
|
||||||
|
if ( "${it.@setting_type}" == "zwave" ) {
|
||||||
|
cmds << zwave.configurationV1.configurationGet(parameterNumber: "${it.@index}".toInteger())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cmds << zwave.firmwareUpdateMdV2.firmwareMdGet()
|
||||||
|
} else {
|
||||||
|
cmds << zwave.meterV2.meterGet(scale: 0)
|
||||||
|
cmds << zwave.meterV2.meterGet(scale: 2)
|
||||||
|
cmds << zwave.basicV1.basicGet()
|
||||||
|
}
|
||||||
|
|
||||||
|
state.lastRefresh = now()
|
||||||
|
|
||||||
|
commands(cmds)
|
||||||
|
}
|
||||||
|
|
||||||
|
def ping() {
|
||||||
|
logging("$device.displayName ping()")
|
||||||
|
|
||||||
|
def cmds = []
|
||||||
|
|
||||||
|
cmds << zwave.meterV2.meterGet(scale: 0)
|
||||||
|
cmds << zwave.meterV2.meterGet(scale: 2)
|
||||||
|
cmds << zwave.basicV1.basicGet()
|
||||||
|
|
||||||
|
commands(cmds)
|
||||||
|
}
|
||||||
|
|
||||||
|
def setLevel(level) {
|
||||||
|
if(level > 99) level = 99
|
||||||
|
if(level < 1) level = 1
|
||||||
|
def cmds = []
|
||||||
|
cmds << zwave.basicV1.basicSet(value: level)
|
||||||
|
cmds << zwave.switchMultilevelV1.switchMultilevelGet()
|
||||||
|
|
||||||
|
commands(cmds)
|
||||||
|
}
|
||||||
|
|
||||||
|
def updated()
|
||||||
|
{
|
||||||
|
state.enableDebugging = settings.enableDebugging
|
||||||
|
logging("updated() is being called")
|
||||||
|
sendEvent(name: "checkInterval", value: 2 * 30 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
|
||||||
|
state.needfwUpdate = ""
|
||||||
|
|
||||||
|
def cmds = update_needed_settings()
|
||||||
|
|
||||||
|
sendEvent(name:"needUpdate", value: device.currentValue("needUpdate"), displayed:false, isStateChange: true)
|
||||||
|
|
||||||
|
response(commands(cmds))
|
||||||
|
}
|
||||||
|
|
||||||
|
private command(physicalgraph.zwave.Command cmd) {
|
||||||
|
if (state.sec) {
|
||||||
|
zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format()
|
||||||
|
} else {
|
||||||
|
cmd.format()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private commands(commands, delay=1500) {
|
||||||
|
delayBetween(commands.collect{ command(it) }, delay)
|
||||||
|
}
|
||||||
|
|
||||||
|
def generate_preferences(configuration_model)
|
||||||
|
{
|
||||||
|
def configuration = parseXml(configuration_model)
|
||||||
|
|
||||||
|
configuration.Value.each
|
||||||
|
{
|
||||||
|
switch(it.@type)
|
||||||
|
{
|
||||||
|
case ["byte","short","four"]:
|
||||||
|
input "${it.@index}", "number",
|
||||||
|
title:"${it.@label}\n" + "${it.Help}",
|
||||||
|
range: "${it.@min}..${it.@max}",
|
||||||
|
defaultValue: "${it.@value}",
|
||||||
|
displayDuringSetup: "${it.@displayDuringSetup}"
|
||||||
|
break
|
||||||
|
case "list":
|
||||||
|
def items = []
|
||||||
|
it.Item.each { items << ["${it.@value}":"${it.@label}"] }
|
||||||
|
input "${it.@index}", "enum",
|
||||||
|
title:"${it.@label}\n" + "${it.Help}",
|
||||||
|
defaultValue: "${it.@value}",
|
||||||
|
displayDuringSetup: "${it.@displayDuringSetup}",
|
||||||
|
options: items
|
||||||
|
break
|
||||||
|
case "decimal":
|
||||||
|
input "${it.@index}", "decimal",
|
||||||
|
title:"${it.@label}\n" + "${it.Help}",
|
||||||
|
range: "${it.@min}..${it.@max}",
|
||||||
|
defaultValue: "${it.@value}",
|
||||||
|
displayDuringSetup: "${it.@displayDuringSetup}"
|
||||||
|
break
|
||||||
|
case "boolean":
|
||||||
|
input "${it.@index}", "boolean",
|
||||||
|
title:"${it.@label}\n" + "${it.Help}",
|
||||||
|
defaultValue: "${it.@value}",
|
||||||
|
displayDuringSetup: "${it.@displayDuringSetup}"
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def update_current_properties(cmd)
|
||||||
|
{
|
||||||
|
def currentProperties = state.currentProperties ?: [:]
|
||||||
|
|
||||||
|
currentProperties."${cmd.parameterNumber}" = cmd.configurationValue
|
||||||
|
|
||||||
|
if (settings."${cmd.parameterNumber}" != null)
|
||||||
|
{
|
||||||
|
if (settings."${cmd.parameterNumber}".toInteger() == convertParam("${cmd.parameterNumber}".toInteger(), cmd2Integer(cmd.configurationValue)))
|
||||||
|
{
|
||||||
|
sendEvent(name:"needUpdate", value:"NO", displayed:false, isStateChange: true)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sendEvent(name:"needUpdate", value:"YES", displayed:false, isStateChange: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
state.currentProperties = currentProperties
|
||||||
|
}
|
||||||
|
|
||||||
|
def update_needed_settings()
|
||||||
|
{
|
||||||
|
def cmds = []
|
||||||
|
def currentProperties = state.currentProperties ?: [:]
|
||||||
|
|
||||||
|
def configuration = parseXml(configuration_model())
|
||||||
|
def isUpdateNeeded = "NO"
|
||||||
|
|
||||||
|
if(!state.needfwUpdate || state.needfwUpdate == ""){
|
||||||
|
logging("Requesting device firmware version")
|
||||||
|
cmds << zwave.firmwareUpdateMdV2.firmwareMdGet()
|
||||||
|
}
|
||||||
|
if(!state.association1 || state.association1 == "" || state.association1 == "1"){
|
||||||
|
logging("Setting association group 1")
|
||||||
|
cmds << zwave.associationV2.associationSet(groupingIdentifier:1, nodeId:zwaveHubNodeId)
|
||||||
|
cmds << zwave.associationV2.associationGet(groupingIdentifier:1)
|
||||||
|
}
|
||||||
|
if(!state.association2 || state.association2 == "" || state.association1 == "2"){
|
||||||
|
logging("Setting association group 2")
|
||||||
|
cmds << zwave.associationV2.associationSet(groupingIdentifier:2, nodeId:zwaveHubNodeId)
|
||||||
|
cmds << zwave.associationV2.associationGet(groupingIdentifier:2)
|
||||||
|
}
|
||||||
|
|
||||||
|
configuration.Value.each
|
||||||
|
{
|
||||||
|
if ("${it.@setting_type}" == "zwave"){
|
||||||
|
if (currentProperties."${it.@index}" == null)
|
||||||
|
{
|
||||||
|
if (device.currentValue("currentFirmware") == null || "${it.@fw}".indexOf(device.currentValue("currentFirmware")) >= 0){
|
||||||
|
isUpdateNeeded = "YES"
|
||||||
|
logging("Current value of parameter ${it.@index} is unknown")
|
||||||
|
cmds << zwave.configurationV1.configurationGet(parameterNumber: it.@index.toInteger())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (settings."${it.@index}" != null && convertParam(it.@index.toInteger(), cmd2Integer(currentProperties."${it.@index}")) != settings."${it.@index}".toInteger())
|
||||||
|
{
|
||||||
|
if (device.currentValue("currentFirmware") == null || "${it.@fw}".indexOf(device.currentValue("currentFirmware")) >= 0){
|
||||||
|
isUpdateNeeded = "YES"
|
||||||
|
|
||||||
|
logging("Parameter ${it.@index} will be updated to " + settings."${it.@index}")
|
||||||
|
def convertedConfigurationValue = convertParam(it.@index.toInteger(), settings."${it.@index}".toInteger())
|
||||||
|
cmds << zwave.configurationV1.configurationSet(configurationValue: integer2Cmd(convertedConfigurationValue, it.@byteSize.toInteger()), parameterNumber: it.@index.toInteger(), size: it.@byteSize.toInteger())
|
||||||
|
cmds << zwave.configurationV1.configurationGet(parameterNumber: it.@index.toInteger())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sendEvent(name:"needUpdate", value: isUpdateNeeded, displayed:false, isStateChange: true)
|
||||||
|
return cmds
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert 1 and 2 bytes values to integer
|
||||||
|
*/
|
||||||
|
def cmd2Integer(array) {
|
||||||
|
|
||||||
|
switch(array.size()) {
|
||||||
|
case 1:
|
||||||
|
array[0]
|
||||||
|
break
|
||||||
|
case 2:
|
||||||
|
((array[0] & 0xFF) << 8) | (array[1] & 0xFF)
|
||||||
|
break
|
||||||
|
case 3:
|
||||||
|
((array[0] & 0xFF) << 16) | ((array[1] & 0xFF) << 8) | (array[2] & 0xFF)
|
||||||
|
break
|
||||||
|
case 4:
|
||||||
|
((array[0] & 0xFF) << 24) | ((array[1] & 0xFF) << 16) | ((array[2] & 0xFF) << 8) | (array[3] & 0xFF)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def integer2Cmd(value, size) {
|
||||||
|
switch(size) {
|
||||||
|
case 1:
|
||||||
|
[value]
|
||||||
|
break
|
||||||
|
case 2:
|
||||||
|
def short value1 = value & 0xFF
|
||||||
|
def short value2 = (value >> 8) & 0xFF
|
||||||
|
[value2, value1]
|
||||||
|
break
|
||||||
|
case 3:
|
||||||
|
def short value1 = value & 0xFF
|
||||||
|
def short value2 = (value >> 8) & 0xFF
|
||||||
|
def short value3 = (value >> 16) & 0xFF
|
||||||
|
[value3, value2, value1]
|
||||||
|
break
|
||||||
|
case 4:
|
||||||
|
def short value1 = value & 0xFF
|
||||||
|
def short value2 = (value >> 8) & 0xFF
|
||||||
|
def short value3 = (value >> 16) & 0xFF
|
||||||
|
def short value4 = (value >> 24) & 0xFF
|
||||||
|
[value4, value3, value2, value1]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) {
|
||||||
|
update_current_properties(cmd)
|
||||||
|
logging("${device.displayName} parameter '${cmd.parameterNumber}' with a byte size of '${cmd.size}' is set to '${cmd2Integer(cmd.configurationValue)}'")
|
||||||
|
}
|
||||||
|
|
||||||
|
def zwaveEvent(physicalgraph.zwave.commands.firmwareupdatemdv2.FirmwareMdReport cmd){
|
||||||
|
logging("Firmware Report ${cmd.toString()}")
|
||||||
|
def firmwareVersion
|
||||||
|
switch(cmd.checksum){
|
||||||
|
case "3281":
|
||||||
|
firmwareVersion = "3.08"
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
firmwareVersion = cmd.checksum
|
||||||
|
}
|
||||||
|
state.needfwUpdate = "false"
|
||||||
|
updateDataValue("firmware", firmwareVersion.toString())
|
||||||
|
createEvent(name: "currentFirmware", value: firmwareVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
def configure() {
|
||||||
|
state.enableDebugging = settings.enableDebugging
|
||||||
|
logging("Configuring Device For SmartThings Use")
|
||||||
|
def cmds = []
|
||||||
|
|
||||||
|
cmds = update_needed_settings()
|
||||||
|
|
||||||
|
if (cmds != []) commands(cmds)
|
||||||
|
}
|
||||||
|
|
||||||
|
def convertParam(number, value) {
|
||||||
|
switch (number){
|
||||||
|
case 201:
|
||||||
|
if (value < 0)
|
||||||
|
256 + value
|
||||||
|
else if (value > 100)
|
||||||
|
value - 256
|
||||||
|
else
|
||||||
|
value
|
||||||
|
break
|
||||||
|
case 202:
|
||||||
|
if (value < 0)
|
||||||
|
256 + value
|
||||||
|
else if (value > 100)
|
||||||
|
value - 256
|
||||||
|
else
|
||||||
|
value
|
||||||
|
break
|
||||||
|
case 203:
|
||||||
|
if (value < 0)
|
||||||
|
65536 + value
|
||||||
|
else if (value > 1000)
|
||||||
|
value - 65536
|
||||||
|
else
|
||||||
|
value
|
||||||
|
break
|
||||||
|
case 204:
|
||||||
|
if (value < 0)
|
||||||
|
256 + value
|
||||||
|
else if (value > 100)
|
||||||
|
value - 256
|
||||||
|
else
|
||||||
|
value
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
value
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private def logging(message) {
|
||||||
|
if (state.enableDebugging == null || state.enableDebugging == "true") log.debug "$message"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def configuration_model()
|
||||||
|
{
|
||||||
|
'''
|
||||||
|
<configuration>
|
||||||
|
<Value type="byte" byteSize="1" index="1" label="Minimum brightness level" min="1" max="98" value="1" setting_type="zwave" fw="3.08">
|
||||||
|
<Help>
|
||||||
|
(parameter is set automatically during the calibration process)
|
||||||
|
The parameter can be changed manually after the calibration.
|
||||||
|
Range: 1~98
|
||||||
|
Default: 1
|
||||||
|
</Help>
|
||||||
|
</Value>
|
||||||
|
<Value type="byte" byteSize="1" index="2" label="Maximum brightness level" min="2" max="99" value="99" setting_type="zwave" fw="3.08">
|
||||||
|
<Help>
|
||||||
|
(parameter is set automatically during the calibration process)
|
||||||
|
The parameter can be changed manually after the calibration.
|
||||||
|
Range: 2~99
|
||||||
|
Default: 99
|
||||||
|
</Help>
|
||||||
|
</Value>
|
||||||
|
<Value type="byte" byteSize="1" index="5" label="Automatic control - dimming step size" min="1" max="99" value="1" setting_type="zwave" fw="3.08">
|
||||||
|
<Help>
|
||||||
|
This parameter defines the percentage value of dimming step during the automatic control.
|
||||||
|
Range: 1~99
|
||||||
|
Default: 1
|
||||||
|
</Help>
|
||||||
|
</Value>
|
||||||
|
<Value type="short" byteSize="2" index="6" label="Automatic control - time of a dimming step" min="0" max="255" value="1" setting_type="zwave" fw="3.08">
|
||||||
|
<Help>
|
||||||
|
This parameter defines the time of single dimming step set in parameter 5 during the automatic control.
|
||||||
|
Range: 0~255
|
||||||
|
Default: 1
|
||||||
|
</Help>
|
||||||
|
</Value>
|
||||||
|
<Value type="byte" byteSize="1" index="7" label="Manual control - dimming step size" min="1" max="99" value="1" setting_type="zwave" fw="3.08">
|
||||||
|
<Help>
|
||||||
|
This parameter defines the percentage value of dimming step during the manual control.
|
||||||
|
Range: 1~99
|
||||||
|
Default: 1
|
||||||
|
</Help>
|
||||||
|
</Value>
|
||||||
|
<Value type="short" byteSize="2" index="8" label="Manual control - time of a dimming step" min="0" max="255" value="5" setting_type="zwave" fw="3.08">
|
||||||
|
<Help>
|
||||||
|
This parameter defines the time of single dimming step set in parameter 7 during the manual control.
|
||||||
|
Range: 0~255
|
||||||
|
Default: 5
|
||||||
|
</Help>
|
||||||
|
</Value>
|
||||||
|
<Value type="list" byteSize="1" index="9" label="State of the device after a power failure" min="0" max="1" value="1" setting_type="zwave" fw="3.08">
|
||||||
|
<Help>
|
||||||
|
The Dimmer 2 will return to the last state before power failure.
|
||||||
|
0 - the Dimmer 2 does not save the state before a power failure, it returns to the "off" position
|
||||||
|
1 - the Dimmer 2 restores its state before power failure
|
||||||
|
Range: 0~1
|
||||||
|
Default: 1
|
||||||
|
</Help>
|
||||||
|
<Item label="Off" value="0" />
|
||||||
|
<Item label="Previous State" value="1" />
|
||||||
|
</Value>
|
||||||
|
<Value type="short" byteSize="2" index="10" label="Timer functionality (auto - off)" min="0" max="32767" value="0" setting_type="zwave" fw="3.08">
|
||||||
|
<Help>
|
||||||
|
This parameter allows to automatically switch off the device after specified time (seconds) from switching on the light source.
|
||||||
|
Range: 1~32767
|
||||||
|
Default: 0
|
||||||
|
</Help>
|
||||||
|
</Value>
|
||||||
|
<Value type="byte" byteSize="1" index="19" label="Forced switch on brightness level" min="0" max="99" value="0" setting_type="zwave" fw="3.08">
|
||||||
|
<Help>
|
||||||
|
If the parameter is active, switching on the Dimmer 2 (S1 single click) will always set this brightness level.
|
||||||
|
Range: 0~99
|
||||||
|
Default: 0
|
||||||
|
</Help>
|
||||||
|
</Value>
|
||||||
|
<Value type="list" byteSize="1" index="20" label="Switch type" min="0" max="2" value="0" setting_type="zwave" fw="3.08">
|
||||||
|
<Help>
|
||||||
|
Choose between momentary, toggle and roller blind switch.
|
||||||
|
Range: 0~2
|
||||||
|
Default: 0
|
||||||
|
</Help>
|
||||||
|
<Item label="Momentary" value="0" />
|
||||||
|
<Item label="Toggle" value="1" />
|
||||||
|
<Item label="Roller Blind" value="2" />
|
||||||
|
</Value>
|
||||||
|
<Value type="list" byteSize="1" index="22" label="Assign toggle switch status to the device status " min="0" max="1" value="0" setting_type="zwave" fw="3.08">
|
||||||
|
<Help>
|
||||||
|
By default each change of toggle switch position results in action of Dimmer 2 (switch on/off) regardless the physical connection of contacts.
|
||||||
|
0 - device changes status on switch status change
|
||||||
|
1 - device status is synchronized with switch status
|
||||||
|
Range: 0~1
|
||||||
|
Default: 0
|
||||||
|
</Help>
|
||||||
|
<Item label="Default" value="0" />
|
||||||
|
<Item label="Synchronized" value="1" />
|
||||||
|
</Value>
|
||||||
|
<Value type="list" byteSize="1" index="23" label="Double click option" min="0" max="1" value="1" setting_type="zwave" fw="3.08">
|
||||||
|
<Help>
|
||||||
|
set the brightness level to MAX
|
||||||
|
Range: 0~1
|
||||||
|
Default: 1
|
||||||
|
</Help>
|
||||||
|
<Item label="Disabled" value="0" />
|
||||||
|
<Item label="Enabled" value="1" />
|
||||||
|
</Value>
|
||||||
|
<Value type="list" byteSize="1" index="26" label="The function of 3-way switch" min="0" max="1" value="0" setting_type="zwave" fw="3.08">
|
||||||
|
<Help>
|
||||||
|
Switch no. 2 controls the Dimmer 2 additionally (in 3-way switch mode). Function disabled for parameter 20 set to 2 (roller blind switch).
|
||||||
|
Range: 0~1
|
||||||
|
Default: 0
|
||||||
|
</Help>
|
||||||
|
<Item label="Disabled" value="0" />
|
||||||
|
<Item label="Enabled" value="1" />
|
||||||
|
</Value>
|
||||||
|
<Value type="list" byteSize="1" index="28" label="Scene activation functionality" min="0" max="1" value="1" setting_type="zwave" fw="3.08">
|
||||||
|
<Help>
|
||||||
|
SCENE ID depends on the switch type configurations.
|
||||||
|
Range: 0~1
|
||||||
|
Default: 0
|
||||||
|
</Help>
|
||||||
|
<Item label="Disabled" value="0" />
|
||||||
|
<Item label="Enabled" value="1" />
|
||||||
|
</Value>
|
||||||
|
<Value type="list" byteSize="1" index="29" label="Switch functionality of S1 and S2" min="0" max="1" value="0" setting_type="zwave" fw="3.08">
|
||||||
|
<Help>
|
||||||
|
This parameter allows for switching the role of keys connected to S1 and S2 without changes in connection.
|
||||||
|
Range: 0~1
|
||||||
|
Default: 0
|
||||||
|
</Help>
|
||||||
|
<Item label="Standard" value="0" />
|
||||||
|
<Item label="Switched" value="1" />
|
||||||
|
</Value>
|
||||||
|
<Value type="list" byteSize="1" index="35" label="Auto-calibration after power on" min="0" max="4" value="1" setting_type="zwave" fw="3.08">
|
||||||
|
<Help>
|
||||||
|
This parameter determines the trigger of auto-calibration procedure, e.g. power on, load error, etc.
|
||||||
|
0 - No auto-calibration of the load after power on
|
||||||
|
1 - Auto-calibration performed after first power on
|
||||||
|
2 - Auto-calibration performed after each power on
|
||||||
|
3 - Auto-calibration performed after first power on or after each LOAD ERROR alarm (no load, load failure, burnt out bulb), if parameter 37 is set to 1 also after alarms: SURGE (Dimmer 2 output overvoltage) and OVERCURRENT (Dimmer 2 output overcurrent)
|
||||||
|
4 - Auto-calibration performed after each power on or after each LOAD ERROR alarm (no load, load failure, burnt out bulb), if parameter 37 is set to 1 also after alarms: SURGE (Dimmer 2 output overvoltage) and OVERCURRENT (Dimmer 2 output overcurrent)
|
||||||
|
Range: 0~4
|
||||||
|
Default: 1
|
||||||
|
</Help>
|
||||||
|
<Item label="0" value="0" />
|
||||||
|
<Item label="1" value="1" />
|
||||||
|
<Item label="2" value="2" />
|
||||||
|
<Item label="3" value="3" />
|
||||||
|
<Item label="4" value="4" />
|
||||||
|
</Value>
|
||||||
|
<Value type="short" byteSize="2" index="39" label="Max Power load" min="0" max="350" value="250" setting_type="zwave" fw="3.08">
|
||||||
|
<Help>
|
||||||
|
This parameter defines the maximum load for a dimmer.
|
||||||
|
Range: 0~350
|
||||||
|
Default: 250
|
||||||
|
</Help>
|
||||||
|
</Value>
|
||||||
|
<Value type="byte" byteSize="1" index="50" label="Active power reports" min="0" max="100" value="10" setting_type="zwave" fw="3.08">
|
||||||
|
<Help>
|
||||||
|
The parameter defines the power level change that will result in a new power report being sent. The value is a percentage of the previous report.
|
||||||
|
Range: 0~100
|
||||||
|
Default: 10
|
||||||
|
</Help>
|
||||||
|
</Value>
|
||||||
|
<Value type="short" byteSize="2" index="52" label="Periodic active power and energy reports" min="0" max="32767" value="3600" setting_type="zwave" fw="3.08">
|
||||||
|
<Help>
|
||||||
|
Parameter 52 defines a time period between consecutive reports. Timer is reset and counted from zero after each report.
|
||||||
|
Range: 0~32767
|
||||||
|
Default: 3600
|
||||||
|
</Help>
|
||||||
|
</Value>
|
||||||
|
<Value type="short" byteSize="2" index="53" label="Energy reports" min="0" max="255" value="10" setting_type="zwave" fw="3.08">
|
||||||
|
<Help>
|
||||||
|
Energy level change which will result in sending a new energy report.
|
||||||
|
Range: 0~255
|
||||||
|
Default: 10
|
||||||
|
</Help>
|
||||||
|
</Value>
|
||||||
|
<Value type="list" byteSize="1" index="54" label="Self-measurement" min="0" max="1" value="0" setting_type="zwave" fw="3.08">
|
||||||
|
<Help>
|
||||||
|
The Dimmer 2 may include active power and energy consumed by itself in reports sent to the main controller.
|
||||||
|
Range: 0~1
|
||||||
|
Default: 0
|
||||||
|
</Help>
|
||||||
|
<Item label="Disabled" value="0" />
|
||||||
|
<Item label="Enabled" value="1" />
|
||||||
|
</Value>
|
||||||
|
<Value type="boolean" index="enableDebugging" label="Enable Debug Logging?" value="true" setting_type="preference" fw="3.08">
|
||||||
|
<Help>
|
||||||
|
</Help>
|
||||||
|
</Value>
|
||||||
|
</configuration>
|
||||||
|
'''
|
||||||
|
}
|
||||||
+4
-4
@@ -14,7 +14,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
metadata {
|
metadata {
|
||||||
definition (name: "Fibaro Door/Window Sensor ZW5 with Temperature", namespace: "fibargroup", author: "Fibar Group S.A.") {
|
definition (name: "Fibaro Door/Window Sensor ZW5 with Temperature", namespace: "fibargroup", author: "Fibar Group S.A.", ocfDeviceType: "x.com.st.d.sensor.contact") {
|
||||||
capability "Battery"
|
capability "Battery"
|
||||||
capability "Contact Sensor"
|
capability "Contact Sensor"
|
||||||
capability "Sensor"
|
capability "Sensor"
|
||||||
@@ -34,8 +34,8 @@ metadata {
|
|||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
multiAttributeTile(name:"FGK", type:"lighting", width:6, height:4) {//with generic type secondary control text is not displayed in Android app
|
multiAttributeTile(name:"FGK", type:"lighting", width:6, height:4) {//with generic type secondary control text is not displayed in Android app
|
||||||
tileAttribute("device.contact", key:"PRIMARY_CONTROL") {
|
tileAttribute("device.contact", key:"PRIMARY_CONTROL") {
|
||||||
attributeState("open", icon:"st.contact.contact.open", backgroundColor:"#ffa81e")
|
attributeState("open", icon:"st.contact.contact.open", backgroundColor:"#e86d13")
|
||||||
attributeState("closed", icon:"st.contact.contact.closed", backgroundColor:"#79b821")
|
attributeState("closed", icon:"st.contact.contact.closed", backgroundColor:"#00a0dc")
|
||||||
}
|
}
|
||||||
|
|
||||||
tileAttribute("device.tamper", key:"SECONDARY_CONTROL") {
|
tileAttribute("device.tamper", key:"SECONDARY_CONTROL") {
|
||||||
@@ -44,7 +44,7 @@ metadata {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
valueTile("battery", "device.battery", inactiveLabel: false, , width: 2, height: 2, decoration: "flat") {
|
valueTile("battery", "device.battery", inactiveLabel: false, width: 2, height: 2, decoration: "flat") {
|
||||||
state "battery", label:'${currentValue}% battery', unit:""
|
state "battery", label:'${currentValue}% battery', unit:""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
.st-ignore
|
||||||
|
README.md
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
# Fibaro Door Window Sensor ZW5
|
||||||
|
|
||||||
|
Cloud Execution
|
||||||
|
|
||||||
|
Works with:
|
||||||
|
|
||||||
|
* [Fibaro Door/Window Sensor ZW5](https://www.smartthings.com/works-with-smartthings/sensors/fibaro-doorwindow-sensor)
|
||||||
|
|
||||||
|
## Table of contents
|
||||||
|
|
||||||
|
* [Capabilities](#capabilities)
|
||||||
|
* [Health](#device-health)
|
||||||
|
* [Battery](#battery-specification)
|
||||||
|
* [Troubleshooting](#troubleshooting)
|
||||||
|
|
||||||
|
## Capabilities
|
||||||
|
|
||||||
|
* **Battery** - defines device uses a battery
|
||||||
|
* **Contact Sensor** - can detect contact (possible values: open,closed)
|
||||||
|
* **Sensor** - detects sensor events
|
||||||
|
* **Tamper Alert** - detects tampers
|
||||||
|
* **Configuration** - _configure()_ command called when device is installed or device preferences updated
|
||||||
|
* **Health Check** - indicates ability to get device health notifications
|
||||||
|
|
||||||
|
## Device Health
|
||||||
|
|
||||||
|
Fibaro Door/Window Sensor ZW5 is a Z-wave sleepy device and wakes up every 4 hours.
|
||||||
|
Device-Watch allows 2 check-in misses from device plus some lag time. So Check-in interval = (2*4*60 + 2)mins = 482 mins.
|
||||||
|
|
||||||
|
* __482min__ checkInterval
|
||||||
|
|
||||||
|
## Battery Specification
|
||||||
|
|
||||||
|
One 1/2AA 3.6V battery is required.
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the device is out of range.
|
||||||
|
Pairing needs to be tried again by placing the device closer to the hub.
|
||||||
|
Instructions related to pairing, resetting and removing the device from SmartThings can be found in the following link:
|
||||||
|
* [Fibaro Door/Window Sensor ZW5 Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/204075194-Fibaro-Door-Window-Sensor)
|
||||||
+7
-4
@@ -14,12 +14,13 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
metadata {
|
metadata {
|
||||||
definition (name: "Fibaro Door/Window Sensor ZW5", namespace: "fibargroup", author: "Fibar Group S.A.") {
|
definition (name: "Fibaro Door/Window Sensor ZW5", namespace: "fibargroup", author: "Fibar Group S.A.", ocfDeviceType: "x.com.st.d.sensor.contact") {
|
||||||
capability "Battery"
|
capability "Battery"
|
||||||
capability "Contact Sensor"
|
capability "Contact Sensor"
|
||||||
capability "Sensor"
|
capability "Sensor"
|
||||||
capability "Configuration"
|
capability "Configuration"
|
||||||
capability "Tamper Alert"
|
capability "Tamper Alert"
|
||||||
|
capability "Health Check"
|
||||||
|
|
||||||
fingerprint deviceId: "0x0701", inClusters: "0x5E, 0x85, 0x59, 0x22, 0x20, 0x80, 0x70, 0x56, 0x5A, 0x7A, 0x72, 0x8E, 0x71, 0x73, 0x98, 0x2B, 0x9C, 0x30, 0x86, 0x84", outClusters: ""
|
fingerprint deviceId: "0x0701", inClusters: "0x5E, 0x85, 0x59, 0x22, 0x20, 0x80, 0x70, 0x56, 0x5A, 0x7A, 0x72, 0x8E, 0x71, 0x73, 0x98, 0x2B, 0x9C, 0x30, 0x86, 0x84", outClusters: ""
|
||||||
}
|
}
|
||||||
@@ -31,8 +32,8 @@ metadata {
|
|||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
multiAttributeTile(name:"FGK", type:"lighting", width:6, height:4) {//with generic type secondary control text is not displayed in Android app
|
multiAttributeTile(name:"FGK", type:"lighting", width:6, height:4) {//with generic type secondary control text is not displayed in Android app
|
||||||
tileAttribute("device.contact", key:"PRIMARY_CONTROL") {
|
tileAttribute("device.contact", key:"PRIMARY_CONTROL") {
|
||||||
attributeState("open", icon:"st.contact.contact.open", backgroundColor:"#ffa81e")
|
attributeState("open", icon:"st.contact.contact.open", backgroundColor:"#e86d13")
|
||||||
attributeState("closed", icon:"st.contact.contact.closed", backgroundColor:"#79b821")
|
attributeState("closed", icon:"st.contact.contact.closed", backgroundColor:"#00a0dc")
|
||||||
}
|
}
|
||||||
|
|
||||||
tileAttribute("device.tamper", key:"SECONDARY_CONTROL") {
|
tileAttribute("device.tamper", key:"SECONDARY_CONTROL") {
|
||||||
@@ -41,7 +42,7 @@ metadata {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
valueTile("battery", "device.battery", inactiveLabel: false, , width: 2, height: 2, decoration: "flat") {
|
valueTile("battery", "device.battery", inactiveLabel: false, width: 2, height: 2, decoration: "flat") {
|
||||||
state "battery", label:'${currentValue}% battery', unit:""
|
state "battery", label:'${currentValue}% battery', unit:""
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,6 +200,8 @@ def zwaveEvent(physicalgraph.zwave.commands.deviceresetlocallyv1.DeviceResetLoca
|
|||||||
|
|
||||||
def configure() {
|
def configure() {
|
||||||
log.debug "Executing 'configure'"
|
log.debug "Executing 'configure'"
|
||||||
|
// Device wakes up every 4 hours, this interval allows us to miss one wakeup notification before marking offline
|
||||||
|
sendEvent(name: "checkInterval", value: 8 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
|
||||||
|
|
||||||
def cmds = []
|
def cmds = []
|
||||||
|
|
||||||
|
|||||||
@@ -14,31 +14,33 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
metadata {
|
metadata {
|
||||||
definition (name: "Fibaro Flood Sensor ZW5", namespace: "fibargroup", author: "Fibar Group S.A.") {
|
definition (name: "Fibaro Flood Sensor ZW5", namespace: "fibargroup", author: "Fibar Group S.A.", ocfDeviceType: "x.com.st.d.sensor.moisture") {
|
||||||
capability "Battery"
|
capability "Battery"
|
||||||
capability "Configuration"
|
capability "Configuration"
|
||||||
capability "Sensor"
|
capability "Sensor"
|
||||||
capability "Tamper Alert"
|
capability "Tamper Alert"
|
||||||
capability "Temperature Measurement"
|
capability "Temperature Measurement"
|
||||||
capability "Water Sensor"
|
capability "Water Sensor"
|
||||||
|
capability "Health Check"
|
||||||
|
|
||||||
fingerprint deviceId: "0x0701", inClusters: "0x5E, 0x22, 0x85, 0x59, 0x20, 0x80, 0x70, 0x56, 0x5A, 0x7A, 0x72, 0x8E, 0x71, 0x73, 0x98, 0x9C, 0x31, 0x86", outClusters: ""
|
fingerprint deviceId: "0x0701", inClusters: "0x5E, 0x22, 0x85, 0x59, 0x20, 0x80, 0x70, 0x56, 0x5A, 0x7A, 0x72, 0x8E, 0x71, 0x73, 0x98, 0x9C, 0x31, 0x86", outClusters: ""
|
||||||
|
fingerprint mfr:"010F", prod:"0B01", model:"2002"
|
||||||
|
fingerprint mfr:"010F", prod:"0B01", model:"1002"
|
||||||
}
|
}
|
||||||
|
|
||||||
simulator {
|
simulator {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
multiAttributeTile(name:"FGFS", type:"lighting", width:6, height:4) {//with generic type secondary control text is not displayed in Android app
|
multiAttributeTile(name:"FGFS", type:"lighting", width:6, height:4) {//with generic type secondary control text is not displayed in Android app
|
||||||
tileAttribute("device.water", key:"PRIMARY_CONTROL") {
|
tileAttribute("device.water", key:"PRIMARY_CONTROL") {
|
||||||
attributeState("dry", icon:"st.alarm.water.dry", backgroundColor:"#79b821")
|
attributeState("dry", icon:"st.alarm.water.dry", backgroundColor:"#ffffff")
|
||||||
attributeState("wet", icon:"st.alarm.water.wet", backgroundColor:"#ffa81e")
|
attributeState("wet", icon:"st.alarm.water.wet", backgroundColor:"#00a0dc")
|
||||||
}
|
}
|
||||||
|
|
||||||
tileAttribute("device.tamper", key:"SECONDARY_CONTROL") {
|
tileAttribute("device.tamper", key:"SECONDARY_CONTROL") {
|
||||||
attributeState("active", label:'tamper active', backgroundColor:"#53a7c0")
|
attributeState("active", label:'tamper active', backgroundColor:"#cccccc")
|
||||||
attributeState("inactive", label:'tamper inactive', backgroundColor:"#ffffff")
|
attributeState("inactive", label:'tamper inactive', backgroundColor:"#00A0DC")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,11 +124,9 @@ def zwaveEvent(physicalgraph.zwave.commands.wakeupv2.WakeUpNotification cmd)
|
|||||||
{
|
{
|
||||||
def event = createEvent(descriptionText: "${device.displayName} woke up", displayed: false)
|
def event = createEvent(descriptionText: "${device.displayName} woke up", displayed: false)
|
||||||
def cmds = []
|
def cmds = []
|
||||||
|
// cmds << encap(zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 1, scale: 0))
|
||||||
|
// cmds << "delay 500"
|
||||||
cmds << encap(zwave.batteryV1.batteryGet())
|
cmds << encap(zwave.batteryV1.batteryGet())
|
||||||
cmds << "delay 500"
|
|
||||||
cmds << encap(zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 1, scale: 0))
|
|
||||||
cmds << "delay 1200"
|
|
||||||
cmds << encap(zwave.wakeUpV1.wakeUpNoMoreInformation())
|
|
||||||
[event, response(cmds)]
|
[event, response(cmds)]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,6 +153,19 @@ def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.DeviceSpecifi
|
|||||||
updateDataValue("serialNumber", serialNumber)
|
updateDataValue("serialNumber", serialNumber)
|
||||||
log.debug "${device.displayName} - serial number: ${serialNumber}"
|
log.debug "${device.displayName} - serial number: ${serialNumber}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def response_cmds = []
|
||||||
|
if (!device.currentState("temperature")) {
|
||||||
|
response_cmds << encap(zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 1, scale: 0))
|
||||||
|
}
|
||||||
|
if (!getDataValue("version") && !zwaveInfo.ver) {
|
||||||
|
log.debug "Requesting Version Report"
|
||||||
|
response_cmds << "delay 500"
|
||||||
|
response_cmds << encap(zwave.versionV1.versionGet())
|
||||||
|
}
|
||||||
|
response_cmds << "delay 1000"
|
||||||
|
response_cmds << encap(zwave.wakeUpV2.wakeUpNoMoreInformation())
|
||||||
|
[[:], response(response_cmds)]
|
||||||
}
|
}
|
||||||
|
|
||||||
def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) {
|
def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) {
|
||||||
@@ -165,12 +178,20 @@ def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) {
|
def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) {
|
||||||
|
def result = []
|
||||||
def map = [:]
|
def map = [:]
|
||||||
map.name = "battery"
|
map.name = "battery"
|
||||||
map.value = cmd.batteryLevel == 255 ? 1 : cmd.batteryLevel.toString()
|
map.value = cmd.batteryLevel == 255 ? 1 : cmd.batteryLevel.toString()
|
||||||
map.unit = "%"
|
map.unit = "%"
|
||||||
map.displayed = true
|
|
||||||
createEvent(map)
|
result << createEvent(map)
|
||||||
|
|
||||||
|
if (!getDataValue("serialNumber")) {
|
||||||
|
result << response(encap(zwave.manufacturerSpecificV2.deviceSpecificGet()))
|
||||||
|
} else {
|
||||||
|
result << response(encap(zwave.wakeUpV2.wakeUpNoMoreInformation()))
|
||||||
|
}
|
||||||
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) {
|
def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) {
|
||||||
@@ -228,19 +249,18 @@ def zwaveEvent(physicalgraph.zwave.commands.deviceresetlocallyv1.DeviceResetLoca
|
|||||||
|
|
||||||
def configure() {
|
def configure() {
|
||||||
log.debug "Executing 'configure'"
|
log.debug "Executing 'configure'"
|
||||||
|
// Device wakes up every 4 hours, this interval of 8h 2m allows us to miss one wakeup notification before marking offline
|
||||||
|
sendEvent(name: "checkInterval", value: 8 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
|
||||||
|
|
||||||
|
// default initial state
|
||||||
|
sendEvent(name: "water", value: "dry")
|
||||||
|
|
||||||
def cmds = []
|
def cmds = []
|
||||||
|
|
||||||
cmds += zwave.wakeUpV2.wakeUpIntervalSet(seconds:21600, nodeid: zwaveHubNodeId)//FGFS' default wake up interval
|
cmds << zwave.associationV2.associationSet(groupingIdentifier:1, nodeId: [zwaveHubNodeId])
|
||||||
cmds += zwave.manufacturerSpecificV2.manufacturerSpecificGet()
|
cmds << zwave.batteryV1.batteryGet() // other queries sent as response to BatteryReport
|
||||||
cmds += zwave.manufacturerSpecificV2.deviceSpecificGet()
|
|
||||||
cmds += zwave.versionV1.versionGet()
|
|
||||||
cmds += zwave.batteryV1.batteryGet()
|
|
||||||
cmds += zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 1, scale: 0)
|
|
||||||
cmds += zwave.associationV2.associationSet(groupingIdentifier:1, nodeId: [zwaveHubNodeId])
|
|
||||||
cmds += zwave.wakeUpV2.wakeUpNoMoreInformation()
|
|
||||||
|
|
||||||
encapSequence(cmds, 500)
|
encapSequence(cmds, 200)
|
||||||
}
|
}
|
||||||
|
|
||||||
private secure(physicalgraph.zwave.Command cmd) {
|
private secure(physicalgraph.zwave.Command cmd) {
|
||||||
@@ -257,13 +277,10 @@ private encapSequence(commands, delay=200) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private encap(physicalgraph.zwave.Command cmd) {
|
private encap(physicalgraph.zwave.Command cmd) {
|
||||||
def secureClasses = [0x20, 0x5A, 0x70, 0x71, 0x84, 0x85, 0x8E, 0x9C]
|
if (zwaveInfo.zw && !zwaveInfo.zw.contains("s")) {
|
||||||
|
// Secure inclusion failed
|
||||||
//todo: check if secure inclusion was successful
|
|
||||||
//if not do not send security-encapsulated command
|
|
||||||
if (secureClasses.find{ it == cmd.commandClassId }) {
|
|
||||||
secure(cmd)
|
|
||||||
} else {
|
|
||||||
crc16(cmd)
|
crc16(cmd)
|
||||||
|
} else {
|
||||||
|
secure(cmd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+11
-7
@@ -14,7 +14,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
metadata {
|
metadata {
|
||||||
definition (name: "Fibaro Motion Sensor ZW5", namespace: "fibargroup", author: "Fibar Group S.A.") {
|
definition (name: "Fibaro Motion Sensor ZW5", namespace: "fibargroup", author: "Fibar Group S.A.", ocfDeviceType: "x.com.st.d.sensor.motion") {
|
||||||
capability "Battery"
|
capability "Battery"
|
||||||
capability "Configuration"
|
capability "Configuration"
|
||||||
capability "Illuminance Measurement"
|
capability "Illuminance Measurement"
|
||||||
@@ -22,6 +22,7 @@ metadata {
|
|||||||
capability "Sensor"
|
capability "Sensor"
|
||||||
capability "Tamper Alert"
|
capability "Tamper Alert"
|
||||||
capability "Temperature Measurement"
|
capability "Temperature Measurement"
|
||||||
|
capability "Health Check"
|
||||||
|
|
||||||
fingerprint deviceId: "0x0701", inClusters: "0x5E, 0x20, 0x86, 0x72, 0x5A, 0x59, 0x85, 0x73, 0x84, 0x80, 0x71, 0x56, 0x70, 0x31, 0x8E, 0x22, 0x30, 0x9C, 0x98, 0x7A", outClusters: ""
|
fingerprint deviceId: "0x0701", inClusters: "0x5E, 0x20, 0x86, 0x72, 0x5A, 0x59, 0x85, 0x73, 0x84, 0x80, 0x71, 0x56, 0x70, 0x31, 0x8E, 0x22, 0x30, 0x9C, 0x98, 0x7A", outClusters: ""
|
||||||
}
|
}
|
||||||
@@ -33,13 +34,13 @@ metadata {
|
|||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
multiAttributeTile(name:"FGMS", type:"lighting", width:6, height:4) {//with generic type secondary control text is not displayed in Android app
|
multiAttributeTile(name:"FGMS", type:"lighting", width:6, height:4) {//with generic type secondary control text is not displayed in Android app
|
||||||
tileAttribute("device.motion", key:"PRIMARY_CONTROL") {
|
tileAttribute("device.motion", key:"PRIMARY_CONTROL") {
|
||||||
attributeState("inactive", icon:"st.motion.motion.inactive", backgroundColor:"#79b821")
|
attributeState("inactive", label:"no motion", icon:"st.motion.motion.inactive", backgroundColor:"#79b821")
|
||||||
attributeState("active", icon:"st.motion.motion.active", backgroundColor:"#ffa81e")
|
attributeState("active", label:"motion", icon:"st.motion.motion.active", backgroundColor:"#ffa81e")
|
||||||
}
|
}
|
||||||
|
|
||||||
tileAttribute("device.tamper", key:"SECONDARY_CONTROL") {
|
tileAttribute("device.tamper", key:"SECONDARY_CONTROL") {
|
||||||
attributeState("active", label:'tamper active', backgroundColor:"#53a7c0")
|
attributeState("active", label:'tamper active', backgroundColor:"#00a0dc")
|
||||||
attributeState("inactive", label:'tamper inactive', backgroundColor:"#ffffff")
|
attributeState("inactive", label:'tamper inactive', backgroundColor:"#cccccc")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,9 +128,10 @@ def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelR
|
|||||||
def map = [ displayed: true ]
|
def map = [ displayed: true ]
|
||||||
switch (cmd.sensorType) {
|
switch (cmd.sensorType) {
|
||||||
case 1:
|
case 1:
|
||||||
|
def cmdScale = cmd.scale == 1 ? "F" : "C"
|
||||||
map.name = "temperature"
|
map.name = "temperature"
|
||||||
map.unit = cmd.scale == 1 ? "F" : "C"
|
map.unit = getTemperatureScale()
|
||||||
map.value = convertTemperatureIfNeeded(cmd.scaledSensorValue, map.unit, cmd.precision)
|
map.value = convertTemperatureIfNeeded(cmd.scaledSensorValue, cmdScale, cmd.precision)
|
||||||
break
|
break
|
||||||
case 3:
|
case 3:
|
||||||
map.name = "illuminance"
|
map.name = "illuminance"
|
||||||
@@ -239,6 +241,8 @@ def zwaveEvent(physicalgraph.zwave.commands.deviceresetlocallyv1.DeviceResetLoca
|
|||||||
|
|
||||||
def configure() {
|
def configure() {
|
||||||
log.debug "Executing 'configure'"
|
log.debug "Executing 'configure'"
|
||||||
|
// Device-Watch simply pings if no device events received for 8 hrs & 2 minutes
|
||||||
|
sendEvent(name: "checkInterval", value: 8 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
|
||||||
|
|
||||||
def cmds = []
|
def cmds = []
|
||||||
|
|
||||||
|
|||||||
@@ -112,10 +112,10 @@ metadata {
|
|||||||
multiAttributeTile(name:"dtlsDoorCtrl", type:"generic", width:6, height:4) {tileAttribute("device.doorState", key: "PRIMARY_CONTROL")
|
multiAttributeTile(name:"dtlsDoorCtrl", type:"generic", width:6, height:4) {tileAttribute("device.doorState", key: "PRIMARY_CONTROL")
|
||||||
{
|
{
|
||||||
attributeState "unknown", label: '${name}', action:"openDoor", icon: "st.secondary.tools", nextState:"Sent"
|
attributeState "unknown", label: '${name}', action:"openDoor", icon: "st.secondary.tools", nextState:"Sent"
|
||||||
attributeState "open", label: '${name}', action:"closeDoor", icon: "st.doors.garage.garage-open", backgroundColor: "#0000ff", nextState:"Sent"
|
attributeState "open", label: '${name}', action:"closeDoor", icon: "st.doors.garage.garage-open", backgroundColor: "#00A0DC", nextState:"Sent"
|
||||||
attributeState "opening", label: '${name}', action:"closeDoor", icon: "st.doors.garage.garage-opening", backgroundColor: "#ffa81e"
|
attributeState "opening", label: '${name}', action:"closeDoor", icon: "st.doors.garage.garage-opening", backgroundColor: "#00A0DC"
|
||||||
attributeState "closed", label: '${name}', action:"openDoor", icon: "st.doors.garage.garage-closed", backgroundColor: "#79b821", nextState:"Sent"
|
attributeState "closed", label: '${name}', action:"openDoor", icon: "st.doors.garage.garage-closed", backgroundColor: "#ffffff", nextState:"Sent"
|
||||||
attributeState "closing", label: '${name}', action:"openDoor", icon: "st.doors.garage.garage-closing", backgroundColor: "#ffa81e"
|
attributeState "closing", label: '${name}', action:"openDoor", icon: "st.doors.garage.garage-closing", backgroundColor: "#ffffff"
|
||||||
attributeState "jammed", label: '${name}', action:"closeDoorHiI", icon: "st.doors.garage.garage-open", backgroundColor: "#ff0000", nextState:"Sent"
|
attributeState "jammed", label: '${name}', action:"closeDoorHiI", icon: "st.doors.garage.garage-open", backgroundColor: "#ff0000", nextState:"Sent"
|
||||||
attributeState "forced close", label: "forced", action:"openDoor", icon: "st.doors.garage.garage-closed", backgroundColor: "#ff8000", nextState:"Sent"
|
attributeState "forced close", label: "forced", action:"openDoor", icon: "st.doors.garage.garage-closed", backgroundColor: "#ff8000", nextState:"Sent"
|
||||||
attributeState "fault", label: 'FAULT', action:"openDoor", icon: "st.secondary.tools", backgroundColor: "#ff0000", nextState:"Sent"
|
attributeState "fault", label: 'FAULT', action:"openDoor", icon: "st.secondary.tools", backgroundColor: "#ff0000", nextState:"Sent"
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ metadata {
|
|||||||
tiles {
|
tiles {
|
||||||
standardTile("sleeping", "device.sleeping", width: 1, height: 1, canChangeIcon: false, canChangeBackground: false) {
|
standardTile("sleeping", "device.sleeping", width: 1, height: 1, canChangeIcon: false, canChangeBackground: false) {
|
||||||
state("sleeping", label: "Sleeping", icon:"st.Bedroom.bedroom12", backgroundColor:"#ffffff")
|
state("sleeping", label: "Sleeping", icon:"st.Bedroom.bedroom12", backgroundColor:"#ffffff")
|
||||||
state("not sleeping", label: "Awake", icon:"st.Health & Wellness.health12", backgroundColor:"#79b821")
|
state("not sleeping", label: "Awake", icon:"st.Health & Wellness.health12", backgroundColor:"#00A0DC")
|
||||||
}
|
}
|
||||||
standardTile("steps", "device.steps", width: 2, height: 2, canChangeIcon: false, canChangeBackground: false) {
|
standardTile("steps", "device.steps", width: 2, height: 2, canChangeIcon: false, canChangeBackground: false) {
|
||||||
state("steps", label: '${currentValue} Steps', icon:"st.Health & Wellness.health11", backgroundColor:"#ffffff")
|
state("steps", label: '${currentValue} Steps', icon:"st.Health & Wellness.health11", backgroundColor:"#ffffff")
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
.st-ignore
|
||||||
|
README.md
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
# Keen Home Smart Vent
|
||||||
|
|
||||||
|
Cloud Execution
|
||||||
|
|
||||||
|
Works with:
|
||||||
|
|
||||||
|
* [Keen Home Smart Vent](https://www.smartthings.com/works-with-smartthings/keen-home/keen-home-smart-vent)
|
||||||
|
|
||||||
|
## Table of contents
|
||||||
|
|
||||||
|
* [Capabilities](#capabilities)
|
||||||
|
* [Health](#device-health)
|
||||||
|
* [Troubleshooting](#Troubleshooting)
|
||||||
|
|
||||||
|
## Capabilities
|
||||||
|
|
||||||
|
* **Switch** - can detect state (possible values: on/off)
|
||||||
|
* **Switch Level** - represents current light level, usually 0-100 in percent
|
||||||
|
* **Sensor** - detects sensor events
|
||||||
|
* **Temperature Measurement** - represents capability to measure temperature
|
||||||
|
* **Configuration** - _configure()_ command called when device is installed or device preferences updated
|
||||||
|
* **Battery** - defines device uses a battery
|
||||||
|
* **Refresh** - _refresh()_ command for status updates
|
||||||
|
* **Health Check** - indicates ability to get device health notifications
|
||||||
|
|
||||||
|
## Device Health
|
||||||
|
|
||||||
|
Keen Home Smart Vent with reporting interval of 10 mins.
|
||||||
|
SmartThings platform will ping the device after `checkInterval` seconds of inactivity in last attempt to reach the device before marking it `OFFLINE`
|
||||||
|
|
||||||
|
* __22min__ checkInterval
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the sensor is out of range.
|
||||||
|
Pairing needs to be tried again by placing the sensor closer to the hub.
|
||||||
|
Instructions related to pairing, resetting and removing the different motion sensors from SmartThings can be found in the following links
|
||||||
|
for the different models:
|
||||||
|
* [Keen Home Smart Vent Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/205302050-Keen-Home-Smart-Vent)
|
||||||
@@ -11,6 +11,7 @@ metadata {
|
|||||||
capability "Sensor"
|
capability "Sensor"
|
||||||
capability "Temperature Measurement"
|
capability "Temperature Measurement"
|
||||||
capability "Battery"
|
capability "Battery"
|
||||||
|
capability "Health Check"
|
||||||
|
|
||||||
command "getLevel"
|
command "getLevel"
|
||||||
command "getOnOff"
|
command "getOnOff"
|
||||||
@@ -20,10 +21,7 @@ metadata {
|
|||||||
command "setZigBeeIdTile"
|
command "setZigBeeIdTile"
|
||||||
command "clearObstruction"
|
command "clearObstruction"
|
||||||
|
|
||||||
fingerprint endpoint: "1",
|
fingerprint endpoint: "1", profileId: "0104", inClusters: "0000,0001,0003,0004,0005,0006,0008,0020,0402,0403,0B05,FC01,FC02", outClusters: "0019"
|
||||||
profileId: "0104",
|
|
||||||
inClusters: "0000,0001,0003,0004,0005,0006,0008,0020,0402,0403,0B05,FC01,FC02",
|
|
||||||
outClusters: "0019"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// simulator metadata
|
// simulator metadata
|
||||||
@@ -40,10 +38,10 @@ metadata {
|
|||||||
// UI tile definitions
|
// UI tile definitions
|
||||||
tiles {
|
tiles {
|
||||||
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
|
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
|
||||||
state "on", action: "switch.off", icon: "st.vents.vent-open-text", backgroundColor: "#53a7c0"
|
state "on", action: "switch.off", icon: "st.vents.vent-open-text", backgroundColor: "#00a0dc"
|
||||||
state "off", action: "switch.on", icon: "st.vents.vent-closed", backgroundColor: "#ffffff"
|
state "off", action: "switch.on", icon: "st.vents.vent-closed", backgroundColor: "#ffffff"
|
||||||
state "obstructed", action: "clearObstruction", icon: "st.vents.vent-closed", backgroundColor: "#ff0000"
|
state "obstructed", action: "clearObstruction", icon: "st.vents.vent-closed", backgroundColor: "#e86d13"
|
||||||
state "clearing", action: "", icon: "st.vents.vent-closed", backgroundColor: "#ffff33"
|
state "clearing", action: "", icon: "st.vents.vent-closed", backgroundColor: "#ffffff"
|
||||||
}
|
}
|
||||||
controlTile("levelSliderControl", "device.level", "slider", height: 1, width: 2, inactiveLabel: false) {
|
controlTile("levelSliderControl", "device.level", "slider", height: 1, width: 2, inactiveLabel: false) {
|
||||||
state "level", action:"switch level.setLevel"
|
state "level", action:"switch level.setLevel"
|
||||||
@@ -274,6 +272,7 @@ private Map makeTemperatureResult(value) {
|
|||||||
name: 'temperature',
|
name: 'temperature',
|
||||||
value: "" + value,
|
value: "" + value,
|
||||||
descriptionText: "${linkText} is ${value}°${temperatureScale}",
|
descriptionText: "${linkText} is ${value}°${temperatureScale}",
|
||||||
|
unit: temperatureScale
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -465,15 +464,27 @@ def refresh() {
|
|||||||
getBattery()
|
getBattery()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PING is used by Device-Watch in attempt to reach the Device
|
||||||
|
* */
|
||||||
|
def ping() {
|
||||||
|
return refresh()
|
||||||
|
}
|
||||||
|
|
||||||
def configure() {
|
def configure() {
|
||||||
log.debug "CONFIGURE"
|
log.debug "CONFIGURE"
|
||||||
|
|
||||||
|
// Device-Watch allows 2 check-in misses from device + ping (plus 1 min lag time)
|
||||||
|
// enrolls with default periodic reporting until newer 5 min interval is confirmed
|
||||||
|
sendEvent(name: "checkInterval", value: 2 * 10 * 60 + 2 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
|
||||||
|
|
||||||
// get ZigBee ID by hidden tile because that's the only way we can do it
|
// get ZigBee ID by hidden tile because that's the only way we can do it
|
||||||
setZigBeeIdTile()
|
setZigBeeIdTile()
|
||||||
|
|
||||||
def configCmds = [
|
def configCmds = [
|
||||||
// bind reporting clusters to hub
|
// bind reporting clusters to hub
|
||||||
"zdo bind 0x${device.deviceNetworkId} 1 1 0x0006 {${device.zigbeeId}} {}", "delay 500",
|
//commenting out switch cluster bind as using wrapper onOffConfig of zigbee class
|
||||||
|
//"zdo bind 0x${device.deviceNetworkId} 1 1 0x0006 {${device.zigbeeId}} {}", "delay 500",
|
||||||
"zdo bind 0x${device.deviceNetworkId} 1 1 0x0008 {${device.zigbeeId}} {}", "delay 500",
|
"zdo bind 0x${device.deviceNetworkId} 1 1 0x0008 {${device.zigbeeId}} {}", "delay 500",
|
||||||
"zdo bind 0x${device.deviceNetworkId} 1 1 0x0402 {${device.zigbeeId}} {}", "delay 500",
|
"zdo bind 0x${device.deviceNetworkId} 1 1 0x0402 {${device.zigbeeId}} {}", "delay 500",
|
||||||
"zdo bind 0x${device.deviceNetworkId} 1 1 0x0403 {${device.zigbeeId}} {}", "delay 500",
|
"zdo bind 0x${device.deviceNetworkId} 1 1 0x0403 {${device.zigbeeId}} {}", "delay 500",
|
||||||
@@ -509,5 +520,5 @@ def configure() {
|
|||||||
// "send 0x${device.deviceNetworkId} 1 1", "delay 1500",
|
// "send 0x${device.deviceNetworkId} 1 1", "delay 1500",
|
||||||
]
|
]
|
||||||
|
|
||||||
return configCmds + refresh()
|
return configCmds + zigbee.onOffConfig() + refresh()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Spruce Controller - Pre Release V2 10/11/2015
|
* Spruce Controller V2_4 Big Tiles *
|
||||||
*
|
|
||||||
* Copyright 2015 Plaid Systems
|
* Copyright 2015 Plaid Systems
|
||||||
*
|
*
|
||||||
* Author: NC
|
* Author: NC
|
||||||
@@ -21,82 +20,96 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
metadata {
|
metadata {
|
||||||
definition (name: "Spruce Controller", namespace: "plaidsystems", author: "NCauffman") {
|
definition (name: 'Spruce Controller', namespace: 'plaidsystems', author: 'Plaid Systems') {
|
||||||
capability "Switch"
|
capability 'Switch'
|
||||||
capability "Configuration"
|
capability 'Configuration'
|
||||||
capability "Refresh"
|
capability 'Refresh'
|
||||||
capability "Actuator"
|
capability 'Actuator'
|
||||||
capability "Valve"
|
capability 'Valve'
|
||||||
|
|
||||||
attribute "switch", "string"
|
attribute 'switch', 'string'
|
||||||
attribute "switch1", "string"
|
attribute 'switch1', 'string'
|
||||||
attribute "switch2", "string"
|
attribute 'switch2', 'string'
|
||||||
attribute "switch8", "string"
|
attribute 'switch8', 'string'
|
||||||
attribute "switch5", "string"
|
attribute 'switch5', 'string'
|
||||||
attribute "switch3", "string"
|
attribute 'switch3', 'string'
|
||||||
attribute "switch4", "string"
|
attribute 'switch4', 'string'
|
||||||
attribute "switch6", "string"
|
attribute 'switch6', 'string'
|
||||||
attribute "switch7", "string"
|
attribute 'switch7', 'string'
|
||||||
attribute "switch9", "string"
|
attribute 'switch9', 'string'
|
||||||
attribute "switch10", "string"
|
attribute 'switch10', 'string'
|
||||||
attribute "switch11", "string"
|
attribute 'switch11', 'string'
|
||||||
attribute "switch12", "string"
|
attribute 'switch12', 'string'
|
||||||
attribute "switch13", "string"
|
attribute 'switch13', 'string'
|
||||||
attribute "switch14", "string"
|
attribute 'switch14', 'string'
|
||||||
attribute "switch15", "string"
|
attribute 'switch15', 'string'
|
||||||
attribute "switch16", "string"
|
attribute 'switch16', 'string'
|
||||||
attribute "status", "string"
|
attribute 'rainsensor', 'string'
|
||||||
|
attribute 'status', 'string'
|
||||||
|
attribute 'tileMessage', 'string'
|
||||||
|
attribute 'minutes', 'string'
|
||||||
|
attribute 'VALUE_UP', 'string'
|
||||||
|
attribute 'VALUE_DOWN', 'string'
|
||||||
|
|
||||||
command "programOn"
|
command 'levelUp'
|
||||||
command "programOff"
|
command 'levelDown'
|
||||||
command "on"
|
command 'programOn'
|
||||||
command "off"
|
command 'programOff'
|
||||||
command "z1on"
|
command 'programWait'
|
||||||
command "z1off"
|
command 'programEnd'
|
||||||
command "z2on"
|
|
||||||
command "z2off"
|
|
||||||
command "z3on"
|
|
||||||
command "z3off"
|
|
||||||
command "z4on"
|
|
||||||
command "z4off"
|
|
||||||
command "z5on"
|
|
||||||
command "z5off"
|
|
||||||
command "z6on"
|
|
||||||
command "z6off"
|
|
||||||
command "z7on"
|
|
||||||
command "z7off"
|
|
||||||
command "z8on"
|
|
||||||
command "z8off"
|
|
||||||
command "z9on"
|
|
||||||
command "z9off"
|
|
||||||
command "z10on"
|
|
||||||
command "z10off"
|
|
||||||
command "z11on"
|
|
||||||
command "z11off"
|
|
||||||
command "z12on"
|
|
||||||
command "z12off"
|
|
||||||
command "z13on"
|
|
||||||
command "z13off"
|
|
||||||
command "z14on"
|
|
||||||
command "z14off"
|
|
||||||
command "z15on"
|
|
||||||
command "z15off"
|
|
||||||
command "z16on"
|
|
||||||
command "z16off"
|
|
||||||
command "offtime"
|
|
||||||
|
|
||||||
command "refresh"
|
command 'on'
|
||||||
command "rain"
|
command 'off'
|
||||||
command "manual"
|
command 'zon'
|
||||||
command "setDisplay"
|
command 'zoff'
|
||||||
|
command 'z1on'
|
||||||
|
command 'z1off'
|
||||||
|
command 'z2on'
|
||||||
|
command 'z2off'
|
||||||
|
command 'z3on'
|
||||||
|
command 'z3off'
|
||||||
|
command 'z4on'
|
||||||
|
command 'z4off'
|
||||||
|
command 'z5on'
|
||||||
|
command 'z5off'
|
||||||
|
command 'z6on'
|
||||||
|
command 'z6off'
|
||||||
|
command 'z7on'
|
||||||
|
command 'z7off'
|
||||||
|
command 'z8on'
|
||||||
|
command 'z8off'
|
||||||
|
command 'z9on'
|
||||||
|
command 'z9off'
|
||||||
|
command 'z10on'
|
||||||
|
command 'z10off'
|
||||||
|
command 'z11on'
|
||||||
|
command 'z11off'
|
||||||
|
command 'z12on'
|
||||||
|
command 'z12off'
|
||||||
|
command 'z13on'
|
||||||
|
command 'z13off'
|
||||||
|
command 'z14on'
|
||||||
|
command 'z14off'
|
||||||
|
command 'z15on'
|
||||||
|
command 'z15off'
|
||||||
|
command 'z16on'
|
||||||
|
command 'z16off'
|
||||||
|
|
||||||
command "settingsMap"
|
command 'config'
|
||||||
command "writeTime"
|
command 'refresh'
|
||||||
command "writeType"
|
command 'rain'
|
||||||
command "notify"
|
command 'manual'
|
||||||
command "updated"
|
command 'manualTime'
|
||||||
|
command 'settingsMap'
|
||||||
|
command 'writeTime'
|
||||||
|
command 'writeType'
|
||||||
|
command 'notify'
|
||||||
|
command 'updated'
|
||||||
|
|
||||||
fingerprint endpointId: "1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18", profileId: "0104", deviceId: "0002", deviceVersion: "00", inClusters: "0000,0003,0004,0005,0006,000F", outClusters: "0003, 0019", manufacturer: "PLAID SYSTEMS", model: "PS-SPRZ16-01"
|
//ST release
|
||||||
|
//fingerprint endpointId: '1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18', profileId: '0104', deviceId: '0002', deviceVersion: '00', inClusters: '0000,0003,0004,0005,0006,000F', outClusters: '0003, 0019', manufacturer: 'PLAID SYSTEMS', model: 'PS-SPRZ16-01'
|
||||||
|
//new release
|
||||||
|
fingerprint endpointId: "1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18", profileId: "0104", deviceId: "0002", deviceVersion: "00", inClusters: "0000,0003,0004,0005,0006,0009,000A,000F", outClusters: "0003, 0019", manufacturer: "PLAID SYSTEMS", model: "PS-SPRZ16-01"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,161 +118,229 @@ metadata {
|
|||||||
// status messages
|
// status messages
|
||||||
|
|
||||||
// reply messages
|
// reply messages
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
preferences {
|
preferences {
|
||||||
input description: "Press Configure button after making changes to these preferences", displayDuringSetup: true, type: "paragraph", element: "paragraph", title: ""
|
input description: 'If you have a rain sensor wired to the rain sensor input on the Spruce controller, turn it on here.', displayDuringSetup: true, type: 'paragraph', element: 'paragraph', title: 'Rain Sensor'
|
||||||
input "RainEnable", "bool", title: "Rain Sensor Attached?", required: false, displayDuringSetup: true
|
input description: 'The SYNC SETTINGS button must be pressed after making a change to the Rain sensor:', displayDuringSetup: false, type: 'paragraph', element: 'paragraph', title: ''
|
||||||
input "ManualTime", "number", title: "Automatic shutoff time when a zone is turned on manually?", required: false, displayDuringSetup: true
|
input 'RainEnable', 'bool', title: 'Rain Sensor Attached?', required: false, displayDuringSetup: true
|
||||||
|
input description: 'Adjust manual water time with arrows on main tile. The time indicated in the first small tile indicates the time the zone will water when manually switched on.', displayDuringSetup: false, type: 'paragraph', element: 'paragraph', title: ''
|
||||||
}
|
}
|
||||||
|
|
||||||
// UI tile definitions
|
// UI tile definitions
|
||||||
tiles {
|
tiles {
|
||||||
|
|
||||||
standardTile("status", "device.status") {
|
multiAttributeTile(name:"switchall", type:"generic", width:6, height:4) {
|
||||||
state "schedule", label: 'Schedule Set', icon: "http://www.plaidsystems.com/smartthings/st_spruce_leaf_225_t.png"
|
tileAttribute('device.status', key: 'PRIMARY_CONTROL') {
|
||||||
state "finished", label: 'Spruce Finished', icon: "st.Outdoor.outdoor5", backgroundColor: "#46c2e8"
|
attributeState 'schedule', label: 'Ready', icon: 'http://www.plaidsystems.com/smartthings/st_spruce_leaf_225_top.png'
|
||||||
state "raintoday", label: 'Rain Today', icon: "st.custom.wuk.nt_chancerain"
|
attributeState 'finished', label: 'Finished', icon: 'st.Outdoor.outdoor5', backgroundColor: '#46c2e8'
|
||||||
state "rainy", label: 'Previous Rain', icon: "st.custom.wuk.nt_chancerain"
|
attributeState 'raintoday', label: 'Rain Today', icon: 'http://www.plaidsystems.com/smartthings/st_rain.png', backgroundColor: '#d65fe3'
|
||||||
state "raintom", label: 'Rain Tomorrow', icon: "st.custom.wuk.nt_chancerain"
|
attributeState 'rainy', label: 'Rain', icon: 'http://www.plaidsystems.com/smartthings/st_rain.png', backgroundColor: '#d65fe3'
|
||||||
state "donewweek", label: 'Spruce Finished', icon: "st.Outdoor.outdoor5", backgroundColor: "#52c435"
|
attributeState 'raintom', label: 'Rain Tomorrow', icon: 'http://www.plaidsystems.com/smartthings/st_rain.png', backgroundColor: '#d65fe3'
|
||||||
state "skipping", label: 'Skip Today', icon: "st.Outdoor.outdoor20", backgroundColor: "#36cfe3"
|
attributeState 'donewweek', label: 'Finished', icon: 'st.Outdoor.outdoor5', backgroundColor: '#00A0DC'
|
||||||
state "moisture", label: '', icon: "st.Weather.weather2", backgroundColor: "#36cfe3"
|
attributeState 'skipping', label: 'Skip', icon: 'st.Outdoor.outdoor20', backgroundColor: '#46c2e8'
|
||||||
state "pause", label: 'PAUSE', icon: "st.contact.contact.open", backgroundColor: "#f2a51f"
|
attributeState 'moisture', label: 'Ready', icon: 'st.Weather.weather2', backgroundColor: '#46c2e8'
|
||||||
state "active", label: 'Active', icon: "st.Outdoor.outdoor12", backgroundColor: "#3DC72E"
|
attributeState 'pause', label: 'PAUSE', icon: 'st.contact.contact.open', backgroundColor: '#e86d13'
|
||||||
state "season", label: 'Seasonal Adjustment', icon: "st.Outdoor.outdoor17", backgroundColor: "#ffb900"
|
attributeState 'delayed', label: 'Delayed', icon: 'st.contact.contact.open', backgroundColor: '#e86d13'
|
||||||
state "disable", label: 'Disabled', icon: "st.secondary.off", backgroundColor: "#888888"
|
attributeState 'active', label: 'Active', icon: 'st.Outdoor.outdoor12', backgroundColor: '#3DC72E'
|
||||||
state "warning", label: '', icon: "st.categories.damageAndDanger", backgroundColor: "#ffff7f"
|
attributeState 'season', label: 'Adjust', icon: 'st.Outdoor.outdoor17', backgroundColor: '#ffb900'
|
||||||
state "alarm", label: 'Alarm', icon: "st.categories.damageAndDanger", backgroundColor: "#f9240c"
|
attributeState 'disable', label: 'Off', icon: 'st.secondary.off', backgroundColor: '#cccccc'
|
||||||
}
|
attributeState 'warning', label: 'Warning', icon: 'http://www.plaidsystems.com/smartthings/st_spruce_leaf_225_top_yellow.png'
|
||||||
standardTile("switch", "device.switch") {
|
attributeState 'alarm', label: 'Alarm', icon: 'http://www.plaidsystems.com/smartthings/st_spruce_leaf_225_s_red.png', backgroundColor: '#e66565'
|
||||||
//state "programOff", label: 'Start Program', action: "programOn", icon: "st.sonos.play-icon", backgroundColor: "#a9a9a9"
|
|
||||||
state "off", label: 'Start Program', action: "programOn", icon: "st.sonos.play-icon", backgroundColor: "#a9a9a9"
|
|
||||||
state "programOn", label: 'Initialize Program', action: "programOff", icon: "st.contact.contact.open", backgroundColor: "#f6e10e"
|
|
||||||
state "on", label: 'Program Running', action: "off", icon: "st.Outdoor.outdoor12", backgroundColor: "#3DC72E"
|
|
||||||
}
|
|
||||||
standardTile("rainsensor", "device.rainsensor") {
|
|
||||||
state "rainSensrooff", label: 'Rain Sensor Clear', icon: "st.Weather.weather14", backgroundColor: "#a9a9a9"
|
|
||||||
state "rainSensoron", label: 'Rain Detected', icon: "st.Weather.weather10", backgroundColor: "#f6e10e"
|
|
||||||
}
|
|
||||||
standardTile("switch1", "device.switch1") {
|
|
||||||
state "z1off", label: '1', action: "z1on", icon: "st.valves.water.closed", backgroundColor: "#ffffff"
|
|
||||||
state "z1on", label: '1', action: "z1off", icon: "st.valves.water.open", backgroundColor: "#46c2e8"
|
|
||||||
}
|
|
||||||
standardTile("switch2", "device.switch2") {
|
|
||||||
state "z2off", label: '2', action: "z2on", icon: "st.valves.water.closed", backgroundColor: "#ffffff"
|
|
||||||
state "z2on", label: '2', action: "z2off", icon: "st.valves.water.open", backgroundColor: "#46c2e8"
|
|
||||||
}
|
|
||||||
standardTile("switch3", "device.switch3", inactiveLabel: false) {
|
|
||||||
state "z3off", label: '3', action: "z3on", icon: "st.valves.water.closed", backgroundColor: "#ffffff"
|
|
||||||
state "z3on", label: '3', action: "z3off", icon: "st.valves.water.open", backgroundColor: "#46c2e8"
|
|
||||||
}
|
|
||||||
standardTile("switch4", "device.switch4", inactiveLabel: false) {
|
|
||||||
state "z4off", label: '4', action: "z4on", icon: "st.valves.water.closed", backgroundColor: "#ffffff"
|
|
||||||
state "z4on", label: '4', action: "z4off", icon: "st.valves.water.open", backgroundColor: "#46c2e8"
|
|
||||||
}
|
|
||||||
standardTile("switch5", "device.switch5", inactiveLabel: false) {
|
|
||||||
state "z5off", label: '5', action: "z5on", icon: "st.valves.water.closed", backgroundColor: "#ffffff"
|
|
||||||
state "z5on", label: '5', action: "z5off", icon: "st.valves.water.open", backgroundColor: "#46c2e8"
|
|
||||||
}
|
|
||||||
standardTile("switch6", "device.switch6", inactiveLabel: false) {
|
|
||||||
state "z6off", label: '6', action: "z6on", icon: "st.valves.water.closed", backgroundColor: "#ffffff"
|
|
||||||
state "z6on", label: '6', action: "z6off", icon: "st.valves.water.open", backgroundColor: "#46c2e8"
|
|
||||||
}
|
|
||||||
standardTile("switch7", "device.switch7", inactiveLabel: false) {
|
|
||||||
state "z7off", label: '7', action: "z7on", icon: "st.valves.water.closed", backgroundColor: "#ffffff"
|
|
||||||
state "z7on", label: '7', action: "z7off", icon: "st.valves.water.open", backgroundColor: "#46c2e8"
|
|
||||||
}
|
|
||||||
standardTile("switch8", "device.switch8", inactiveLabel: false) {
|
|
||||||
state "z8off", label: '8', action: "z8on", icon: "st.valves.water.closed", backgroundColor: "#ffffff"
|
|
||||||
state "z8on", label: '8', action: "z8off", icon: "st.valves.water.open", backgroundColor: "#46c2e8"
|
|
||||||
}
|
|
||||||
standardTile("switch9", "device.switch9", inactiveLabel: false) {
|
|
||||||
state "z9off", label: '9', action: "z9on", icon: "st.valves.water.closed", backgroundColor: "#ffffff"
|
|
||||||
state "z9on", label: '9', action: "z9off", icon: "st.valves.water.open", backgroundColor: "#46c2e8"
|
|
||||||
}
|
|
||||||
standardTile("switch10", "device.switch10", inactiveLabel: false) {
|
|
||||||
state "z10off", label: '10', action: "z10on", icon: "st.valves.water.closed", backgroundColor: "#ffffff"
|
|
||||||
state "z10on", label: '10', action: "z10off", icon: "st.valves.water.open", backgroundColor: "#46c2e8"
|
|
||||||
}
|
|
||||||
standardTile("switch11", "device.switch11", inactiveLabel: false) {
|
|
||||||
state "z11off", label: '11', action: "z11on", icon: "st.valves.water.closed", backgroundColor: "#ffffff"
|
|
||||||
state "z11on", label: '11', action: "z11off", icon: "st.valves.water.open", backgroundColor: "#46c2e8"
|
|
||||||
}
|
|
||||||
standardTile("switch12", "device.switch12", inactiveLabel: false) {
|
|
||||||
state "z12off", label: '12', action: "z12on", icon: "st.valves.water.closed", backgroundColor: "#ffffff"
|
|
||||||
state "z12on", label: '12', action: "z12off", icon: "st.valves.water.open", backgroundColor: "#46c2e8"
|
|
||||||
}
|
|
||||||
standardTile("switch13", "device.switch13", inactiveLabel: false) {
|
|
||||||
state "z13off", label: '13', action: "z13on", icon: "st.valves.water.closed", backgroundColor: "#ffffff"
|
|
||||||
state "z13on", label: '13', action: "z13off", icon: "st.valves.water.open", backgroundColor: "#46c2e8"
|
|
||||||
}
|
|
||||||
standardTile("switch14", "device.switch14", inactiveLabel: false) {
|
|
||||||
state "z14off", label: '14', action: "z14on", icon: "st.valves.water.closed", backgroundColor: "#ffffff"
|
|
||||||
state "z14on", label: '14', action: "z14off", icon: "st.valves.water.open", backgroundColor: "#46c2e8"
|
|
||||||
}
|
|
||||||
standardTile("switch15", "device.switch15", inactiveLabel: false) {
|
|
||||||
state "z15off", label: '15', action: "z15on", icon: "st.valves.water.closed", backgroundColor: "#ffffff"
|
|
||||||
state "z15on", label: '15', action: "z15off", icon: "st.valves.water.open", backgroundColor: "#46c2e8"
|
|
||||||
}
|
|
||||||
standardTile("switch16", "device.switch16", inactiveLabel: false) {
|
|
||||||
state "z16off", label: '16', action: "z16on", icon: "st.valves.water.closed", backgroundColor: "#ffffff"
|
|
||||||
state "z16on", label: '16', action: "z16off", icon: "st.valves.water.open", backgroundColor: "#46c2e8"
|
|
||||||
}
|
|
||||||
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat") {
|
|
||||||
state "default", action: "refresh", icon:"st.secondary.refresh"
|
|
||||||
}
|
|
||||||
standardTile("configure", "device.configure", inactiveLabel: false, decoration: "flat") {
|
|
||||||
state "configure", label:'', action:"configuration.configure", icon:"st.secondary.configure"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
main (["status"])
|
tileAttribute("device.minutes", key: "VALUE_CONTROL") {
|
||||||
details(["status","rainsensor","switch","switch1","switch2","switch3","switch4","switch5","switch6","switch7","switch8","switch9","switch10","switch11","switch12","switch13","switch14","switch15","switch16","refresh","configure"])
|
attributeState "VALUE_UP", action: "levelUp"
|
||||||
|
attributeState "VALUE_DOWN", action: "levelDown"
|
||||||
|
}
|
||||||
|
|
||||||
|
tileAttribute("device.tileMessage", key: "SECONDARY_CONTROL") {
|
||||||
|
attributeState "tileMessage", label: '${currentValue}'
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
valueTile('minutes', 'device.minutes'){
|
||||||
|
state 'minutes', label: '${currentValue} min'
|
||||||
|
}
|
||||||
|
valueTile('dummy', 'device.minutes'){
|
||||||
|
state 'minutes', label: ''
|
||||||
|
}
|
||||||
|
standardTile('switch', 'device.switch', width:2, height:2) {
|
||||||
|
state 'off', label: 'Start', action: 'programOn', icon: 'st.Outdoor.outdoor12', backgroundColor: '#a9a9a9'
|
||||||
|
state 'programOn', label: 'Wait', action: 'programOff', icon: 'st.contact.contact.open', backgroundColor: '#f6e10e'
|
||||||
|
state 'programWait', label: 'Wait', action: 'programEnd', icon: 'st.contact.contact.open', backgroundColor: '#f6e10e'
|
||||||
|
state 'on', label: 'Running', action: 'programEnd', icon: 'st.Outdoor.outdoor12', backgroundColor: '#3DC72E'
|
||||||
|
}
|
||||||
|
standardTile("rainsensor", "device.rainsensor", decoration: 'flat') {
|
||||||
|
state "rainSensoroff", label: 'sensor', icon: 'http://www.plaidsystems.com/smartthings/st_drop_on.png'
|
||||||
|
state "rainSensoron", label: 'sensor', icon: 'http://www.plaidsystems.com/smartthings/st_drop_on_blue_small.png'
|
||||||
|
state "disable", label: 'sensor', icon: 'http://www.plaidsystems.com/smartthings/st_drop_x_small.png'
|
||||||
|
state "enable", label: 'sensor', icon: 'http://www.plaidsystems.com/smartthings/st_drop_on.png'
|
||||||
|
}
|
||||||
|
standardTile('switch1', 'device.switch1', inactiveLabel: false) {
|
||||||
|
state 'z1off', label: '1', action: 'z1on', icon: 'st.valves.water.closed', backgroundColor: '#ffffff'
|
||||||
|
state 'z1on', label: '1', action: 'z1off', icon: 'st.valves.water.open', backgroundColor: '#00A0DC'
|
||||||
|
}
|
||||||
|
standardTile('switch2', 'device.switch2', inactiveLabel: false) {
|
||||||
|
state 'z2off', label: '2', action: 'z2on', icon: 'st.valves.water.closed', backgroundColor: '#ffffff'
|
||||||
|
state 'z2on', label: '2', action: 'z2off', icon: 'st.valves.water.open', backgroundColor: '#00A0DC'
|
||||||
|
}
|
||||||
|
standardTile('switch3', 'device.switch3', inactiveLabel: false) {
|
||||||
|
state 'z3off', label: '3', action: 'z3on', icon: 'st.valves.water.closed', backgroundColor: '#ffffff'
|
||||||
|
state 'z3on', label: '3', action: 'z3off', icon: 'st.valves.water.open', backgroundColor: '#00A0DC'
|
||||||
|
}
|
||||||
|
standardTile('switch4', 'device.switch4', inactiveLabel: false) {
|
||||||
|
state 'z4off', label: '4', action: 'z4on', icon: 'st.valves.water.closed', backgroundColor: '#ffffff'
|
||||||
|
state 'z4on', label: '4', action: 'z4off', icon: 'st.valves.water.open', backgroundColor: '#00A0DC'
|
||||||
|
}
|
||||||
|
standardTile('switch5', 'device.switch5', inactiveLabel: false) {
|
||||||
|
state 'z5off', label: '5', action: 'z5on', icon: 'st.valves.water.closed', backgroundColor: '#ffffff'
|
||||||
|
state 'z5on', label: '5', action: 'z5off', icon: 'st.valves.water.open', backgroundColor: '#00A0DC'
|
||||||
|
}
|
||||||
|
standardTile('switch6', 'device.switch6', inactiveLabel: false) {
|
||||||
|
state 'z6off', label: '6', action: 'z6on', icon: 'st.valves.water.closed', backgroundColor: '#ffffff'
|
||||||
|
state 'z6on', label: '6', action: 'z6off', icon: 'st.valves.water.open', backgroundColor: '#00A0DC'
|
||||||
|
}
|
||||||
|
standardTile('switch7', 'device.switch7', inactiveLabel: false) {
|
||||||
|
state 'z7off', label: '7', action: 'z7on', icon: 'st.valves.water.closed', backgroundColor: '#ffffff'
|
||||||
|
state 'z7on', label: '7', action: 'z7off', icon: 'st.valves.water.open', backgroundColor: '#00A0DC'
|
||||||
|
}
|
||||||
|
standardTile('switch8', 'device.switch8', inactiveLabel: false) {
|
||||||
|
state 'z8off', label: '8', action: 'z8on', icon: 'st.valves.water.closed', backgroundColor: '#ffffff'
|
||||||
|
state 'z8on', label: '8', action: 'z8off', icon: 'st.valves.water.open', backgroundColor: '#00A0DC'
|
||||||
|
}
|
||||||
|
standardTile('switch9', 'device.switch9', inactiveLabel: false) {
|
||||||
|
state 'z9off', label: '9', action: 'z9on', icon: 'st.valves.water.closed', backgroundColor: '#ffffff'
|
||||||
|
state 'z9on', label: '9', action: 'z9off', icon: 'st.valves.water.open', backgroundColor: '#00A0DC'
|
||||||
|
}
|
||||||
|
standardTile('switch10', 'device.switch10', inactiveLabel: false) {
|
||||||
|
state 'z10off', label: '10', action: 'z10on', icon: 'st.valves.water.closed', backgroundColor: '#ffffff'
|
||||||
|
state 'z10on', label: '10', action: 'z10off', icon: 'st.valves.water.open', backgroundColor: '#00A0DC'
|
||||||
|
}
|
||||||
|
standardTile('switch11', 'device.switch11', inactiveLabel: false) {
|
||||||
|
state 'z11off', label: '11', action: 'z11on', icon: 'st.valves.water.closed', backgroundColor: '#ffffff'
|
||||||
|
state 'z11on', label: '11', action: 'z11off', icon: 'st.valves.water.open', backgroundColor: '#00A0DC'
|
||||||
|
}
|
||||||
|
standardTile('switch12', 'device.switch12', inactiveLabel: false) {
|
||||||
|
state 'z12off', label: '12', action: 'z12on', icon: 'st.valves.water.closed', backgroundColor: '#ffffff'
|
||||||
|
state 'z12on', label: '12', action: 'z12off', icon: 'st.valves.water.open', backgroundColor: '#00A0DC'
|
||||||
|
}
|
||||||
|
standardTile('switch13', 'device.switch13', inactiveLabel: false) {
|
||||||
|
state 'z13off', label: '13', action: 'z13on', icon: 'st.valves.water.closed', backgroundColor: '#ffffff'
|
||||||
|
state 'z13on', label: '13', action: 'z13off', icon: 'st.valves.water.open', backgroundColor: '#00A0DC'
|
||||||
|
}
|
||||||
|
standardTile('switch14', 'device.switch14', inactiveLabel: false) {
|
||||||
|
state 'z14off', label: '14', action: 'z14on', icon: 'st.valves.water.closed', backgroundColor: '#ffffff'
|
||||||
|
state 'z14on', label: '14', action: 'z14off', icon: 'st.valves.water.open', backgroundColor: '#00A0DC'
|
||||||
|
}
|
||||||
|
standardTile('switch15', 'device.switch15', inactiveLabel: false) {
|
||||||
|
state 'z15off', label: '15', action: 'z15on', icon: 'st.valves.water.closed', backgroundColor: '#ffffff'
|
||||||
|
state 'z15on', label: '15', action: 'z15off', icon: 'st.valves.water.open', backgroundColor: '#00A0DC'
|
||||||
|
}
|
||||||
|
standardTile('switch16', 'device.switch16', inactiveLabel: false) {
|
||||||
|
state 'z16off', label: '16', action: 'z16on', icon: 'st.valves.water.closed', backgroundColor: '#ffffff'
|
||||||
|
state 'z16on', label: '16', action: 'z16off', icon: 'st.valves.water.open', backgroundColor: '#00A0DC'
|
||||||
|
}
|
||||||
|
standardTile('refresh', 'device.switch', inactiveLabel: false, decoration: 'flat') {
|
||||||
|
state 'default', action: 'refresh', icon:'st.secondary.refresh'//-icon'
|
||||||
|
}
|
||||||
|
standardTile('configure', 'device.configure', inactiveLabel: false, decoration: 'flat') {
|
||||||
|
state 'configure', label:'', action:'configuration.configure', icon:'http://www.plaidsystems.com/smartthings/st_syncsettings.png'//sync_icon_small.png'
|
||||||
|
}
|
||||||
|
|
||||||
|
main (['switchall'])
|
||||||
|
details(['switchall','minutes','rainsensor','switch1','switch2','switch3','switch4','switch','switch5','switch6','switch7','switch8','switch9','switch10','switch11','switch12','refresh','configure','switch13','switch14','switch15','switch16'])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//used for schedule
|
||||||
def programOn(){
|
def programOn(){
|
||||||
sendEvent(name: "switch", value: "programOn", descriptionText: "Program turned on")
|
sendEvent(name: 'switch', value: 'programOn', descriptionText: 'Program turned on')
|
||||||
|
}
|
||||||
|
|
||||||
|
def programWait(){
|
||||||
|
sendEvent(name: 'switch', value: 'programWait', descriptionText: "Initializing Schedule")
|
||||||
|
}
|
||||||
|
|
||||||
|
def programEnd(){
|
||||||
|
//sets switch to off and tells schedule switch is off/schedule complete with manaual
|
||||||
|
sendEvent(name: 'switch', value: 'off', descriptionText: 'Program manually turned off')
|
||||||
|
zoff()
|
||||||
}
|
}
|
||||||
|
|
||||||
def programOff(){
|
def programOff(){
|
||||||
sendEvent(name: "switch", value: "off", descriptionText: "Program turned off")
|
sendEvent(name: 'switch', value: 'off', descriptionText: 'Program turned off')
|
||||||
off()
|
off()
|
||||||
}
|
}
|
||||||
|
|
||||||
def updated(){
|
//set minutes
|
||||||
log.debug "updated"
|
def levelUp(){
|
||||||
|
def newvalue = 1
|
||||||
|
if (device.latestValue('minutes') != null) newvalue = device.latestValue('minutes').toInteger()+1
|
||||||
|
if (newvalue >= 60) newvalue = 60
|
||||||
|
def value = newvalue.toString()
|
||||||
|
log.debug value
|
||||||
|
sendEvent(name: 'minutes', value: "${value}", descriptionText: "Manual Time set to ${value}", display: false)
|
||||||
|
}
|
||||||
|
|
||||||
|
def levelDown(){
|
||||||
|
def newvalue = device.latestValue('minutes').toInteger()-1
|
||||||
|
if (newvalue <= 0) newvalue = 1
|
||||||
|
def value = newvalue.toString()
|
||||||
|
log.debug value
|
||||||
|
sendEvent(name: 'minutes', value: "${value}", descriptionText: "Manual Time set to ${value}", display: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse incoming device messages to generate events
|
// Parse incoming device messages to generate events
|
||||||
def parse(String description) {
|
def parse(String description) {
|
||||||
//log.debug "Parse description $description"
|
log.debug "Parse description ${description}"
|
||||||
def result = null
|
def result = null
|
||||||
def map = [:]
|
def map = [:]
|
||||||
if (description?.startsWith("read attr -")) {
|
if (description?.startsWith('read attr -')) {
|
||||||
def descMap = parseDescriptionAsMap(description)
|
def descMap = parseDescriptionAsMap(description)
|
||||||
//log.debug "Desc Map: $descMap"
|
//log.debug "Desc Map: $descMap"
|
||||||
//using 000F cluster instead of 0006 (switch) because ST does not differentiate between EPs and processes all as switch
|
//using 000F cluster instead of 0006 (switch) because ST does not differentiate between EPs and processes all as switch
|
||||||
if (descMap.cluster == "000F" && descMap.attrId == "0055") {
|
if (descMap.cluster == '000F' && descMap.attrId == '0055') {
|
||||||
log.debug "Zone"
|
log.debug 'Zone'
|
||||||
map = getZone(descMap)
|
map = getZone(descMap)
|
||||||
}
|
}
|
||||||
else if (descMap.cluster == "0009" && descMap.attrId == "0000") {
|
else if (descMap.cluster == '0009' && descMap.attrId == '0000') {
|
||||||
log.debug "Alarm"
|
log.debug 'Alarm'
|
||||||
map = getAlarm(descMap)
|
map = getAlarm(descMap)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (description?.startsWith('catchall: 0104 0009')){
|
||||||
|
log.debug 'Sync settings to controller complete'
|
||||||
|
if (device.latestValue('status') != 'alarm'){
|
||||||
|
def configEvt = createEvent(name: 'status', value: 'schedule', descriptionText: "Sync settings to controller complete")
|
||||||
|
def configMsg = createEvent(name: 'tileMessage', value: 'Sync settings to controller complete', descriptionText: "Sync settings to controller complete", displayed: false)
|
||||||
|
result = [configEvt, configMsg]
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
if (map) {
|
if (map) {
|
||||||
result = createEvent(map)
|
result = createEvent(map)
|
||||||
|
//configure after reboot
|
||||||
|
if (map.value == 'warning' || map.value == 'alarm'){
|
||||||
|
def cmds = config()
|
||||||
|
def alarmEvt = createEvent(name: 'tileMessage', value: map.descriptionText, descriptionText: "${map.descriptionText}", displayed: false)
|
||||||
|
result = cmds?.collect { new physicalgraph.device.HubAction(it) } + createEvent(map) + alarmEvt
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
log.debug "Parse returned $map $result"
|
else if (map.name == 'rainsensor'){
|
||||||
|
def rainEvt = createEvent(name: 'tileMessage', value: map.descriptionText, descriptionText: "${map.descriptionText}", displayed: false)
|
||||||
|
result = [createEvent(map), rainEvt]
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (map) log.debug "Parse returned ${map} ${result}"
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
def parseDescriptionAsMap(description) {
|
def parseDescriptionAsMap(description) {
|
||||||
(description - "read attr - ").split(",").inject([:]) { map, param ->
|
(description - 'read attr - ').split(',').inject([:]) { map, param ->
|
||||||
def nameAndValue = param.split(":")
|
def nameAndValue = param.split(':')
|
||||||
map += [(nameAndValue[0].trim()):nameAndValue[1].trim()]
|
map += [(nameAndValue[0].trim()):nameAndValue[1].trim()]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -270,27 +351,28 @@ def getZone(descMap){
|
|||||||
def EP = Integer.parseInt(descMap.endpoint.trim(), 16)
|
def EP = Integer.parseInt(descMap.endpoint.trim(), 16)
|
||||||
|
|
||||||
String onoff
|
String onoff
|
||||||
if(descMap.value == "00"){
|
if(descMap.value == '00'){
|
||||||
onoff = "off"
|
onoff = 'off'
|
||||||
}
|
}
|
||||||
else onoff = "on"
|
else onoff = 'on'
|
||||||
|
|
||||||
if (EP == 1){
|
if (EP == 1){
|
||||||
map.name = "switch"
|
map.name = 'switch'
|
||||||
map.value = onoff
|
map.value = onoff
|
||||||
map.descriptionText = "${device.displayName} turned sprinkler program $onoff"
|
map.descriptionText = "${device.displayName} turned sprinkler program ${onoff}"
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (EP == 18) {
|
else if (EP == 18) {
|
||||||
map.name = "rainsensor"
|
map.name = 'rainsensor'
|
||||||
map.value = "rainSensor" + onoff
|
log.debug "Rain enable: ${RainEnable}, sensor: ${onoff}"
|
||||||
map.descriptionText = "${device.displayName} rain sensor is $onoff"
|
map.value = 'rainSensor' + onoff
|
||||||
|
map.descriptionText = "${device.displayName} rain sensor is ${onoff}"
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
EP -= 1
|
EP -= 1
|
||||||
map.name = "switch" + EP
|
map.name = 'switch' + EP
|
||||||
map.value = "z" + EP + onoff
|
map.value = 'z' + EP + onoff
|
||||||
map.descriptionText = "${device.displayName} turned Zone $EP $onoff"
|
map.descriptionText = "${device.displayName} turned Zone $EP ${onoff}"
|
||||||
}
|
}
|
||||||
|
|
||||||
map.isStateChange = true
|
map.isStateChange = true
|
||||||
@@ -300,36 +382,58 @@ def getZone(descMap){
|
|||||||
|
|
||||||
def getAlarm(descMap){
|
def getAlarm(descMap){
|
||||||
def map = [:]
|
def map = [:]
|
||||||
map.name = "status"
|
map.name = 'status'
|
||||||
def alarmID = Integer.parseInt(descMap.value.trim(), 16)
|
def alarmID = Integer.parseInt(descMap.value.trim(), 16)
|
||||||
log.debug "${alarmID}"
|
log.debug "${alarmID}"
|
||||||
if(alarmID <= 0) map.descriptionText = "${device.displayName} has rebooted, no other alarms"
|
map.value = 'alarm'
|
||||||
else map.descriptionText = "${device.displayName} rebooted, reported error on zone ${alarmID - 1}, please check zone is working correctly"
|
|
||||||
map.value = "alarm"
|
|
||||||
map.isStateChange = true
|
|
||||||
map.displayed = true
|
map.displayed = true
|
||||||
|
map.isStateChange = true
|
||||||
|
if(alarmID <= 0){
|
||||||
|
map.descriptionText = "${device.displayName} reboot, no other alarms"
|
||||||
|
map.value = 'warning'
|
||||||
|
//map.isStateChange = false
|
||||||
|
}
|
||||||
|
else map.descriptionText = "${device.displayName} reboot, reported zone ${alarmID - 1} error, please check zone is working correctly, press SYNC SETTINGS button to clear"
|
||||||
|
|
||||||
return map
|
return map
|
||||||
}
|
}
|
||||||
|
|
||||||
//status notify and change status
|
//status notify and change status
|
||||||
def notify(value, text){
|
def notify(String val, String txt){
|
||||||
sendEvent(name:"status", value:"$value", descriptionText:"$text", isStateChange: true, display: false)
|
sendEvent(name: 'status', value: val, descriptionText: txt, isStateChange: true, display: false)
|
||||||
|
|
||||||
|
//String txtShort = txt.take(100)
|
||||||
|
sendEvent(name: 'tileMessage', value: txt, descriptionText: "", isStateChange: true, display: false)
|
||||||
|
}
|
||||||
|
|
||||||
|
def updated(){
|
||||||
|
log.debug "updated"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//prefrences - rain sensor, manual time
|
//prefrences - rain sensor, manual time
|
||||||
def rain() {
|
def rain() {
|
||||||
log.debug "Rain $RainEnable"
|
log.debug "Rain sensor: ${RainEnable}"
|
||||||
|
if (RainEnable) sendEvent(name: 'rainsensor', value: 'enable', descriptionText: "${device.displayName} rain sensor is enabled", isStateChange: true)
|
||||||
|
else sendEvent(name: 'rainsensor', value: 'disable', descriptionText: "${device.displayName} rain sensor is disabled", isStateChange: true)
|
||||||
|
|
||||||
if (RainEnable) "st wattr 0x${device.deviceNetworkId} 18 0x0F 0x51 0x10 {01}"
|
if (RainEnable) "st wattr 0x${device.deviceNetworkId} 18 0x0F 0x51 0x10 {01}"
|
||||||
else "st wattr 0x${device.deviceNetworkId} 18 0x0F 0x51 0x10 {00}"
|
else "st wattr 0x${device.deviceNetworkId} 18 0x0F 0x51 0x10 {00}"
|
||||||
}
|
}
|
||||||
def manual(){
|
|
||||||
log.debug "Time $ManualTime"
|
|
||||||
def mTime = 10
|
|
||||||
if (ManualTime) mTime = ManualTime
|
|
||||||
def manualTime = hex(mTime)
|
|
||||||
"st wattr 0x${device.deviceNetworkId} 1 6 0x4002 0x21 {00${manualTime}}"
|
|
||||||
|
|
||||||
|
def manualTime(value){
|
||||||
|
sendEvent(name: 'minutes', value: "${value}", descriptionText: "Manual Time set to ${value}", display: false)
|
||||||
|
}
|
||||||
|
|
||||||
|
def manual(){
|
||||||
|
def newManaul = 10
|
||||||
|
if (device.latestValue('minutes')) newManaul = device.latestValue('minutes').toInteger()
|
||||||
|
log.debug "Manual Zone runtime ${newManaul} mins"
|
||||||
|
def manualTime = hex(newManaul)
|
||||||
|
|
||||||
|
def sendCmds = []
|
||||||
|
sendCmds.push("st wattr 0x${device.deviceNetworkId} 1 6 0x4002 0x21 {00${manualTime}}")
|
||||||
|
return sendCmds
|
||||||
}
|
}
|
||||||
|
|
||||||
//write switch time settings map
|
//write switch time settings map
|
||||||
@@ -367,9 +471,16 @@ def writeTime(wEP, runTime){
|
|||||||
//set reporting and binding
|
//set reporting and binding
|
||||||
def configure() {
|
def configure() {
|
||||||
|
|
||||||
|
sendEvent(name: 'status', value: 'schedule', descriptionText: "Syncing settings to controller")
|
||||||
|
sendEvent(name: 'minutes', value: "10", descriptionText: "Manual Time set to 10 mins", display: false)
|
||||||
|
sendEvent(name: 'tileMessage', value: 'Syncing settings to controller', descriptionText: 'Syncing settings to controller')
|
||||||
|
config()
|
||||||
|
}
|
||||||
|
|
||||||
|
def config(){
|
||||||
|
|
||||||
String zigbeeId = swapEndianHex(device.hub.zigbeeId)
|
String zigbeeId = swapEndianHex(device.hub.zigbeeId)
|
||||||
log.debug "Confuguring Reporting and Bindings ${device.deviceNetworkId} ${device.zigbeeId}"
|
log.debug "Configuring Reporting and Bindings ${device.deviceNetworkId} ${device.zigbeeId}"
|
||||||
sendEvent(name: 'configuration',value: 100, descriptionText: "Configuration initialized")
|
|
||||||
|
|
||||||
def configCmds = [
|
def configCmds = [
|
||||||
//program on/off
|
//program on/off
|
||||||
@@ -458,36 +569,14 @@ def configure() {
|
|||||||
"zcl global send-me-a-report 0x09 0x00 0x21 1 0 {00}", "delay 500",
|
"zcl global send-me-a-report 0x09 0x00 0x21 1 0 {00}", "delay 500",
|
||||||
"send 0x${device.deviceNetworkId} 1 1", "delay 500"
|
"send 0x${device.deviceNetworkId} 1 1", "delay 500"
|
||||||
]
|
]
|
||||||
return configCmds + rain() + manual()
|
return configCmds + rain()
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private hex(value) {
|
|
||||||
new BigInteger(Math.round(value).toString()).toString(16)
|
|
||||||
}
|
|
||||||
|
|
||||||
private String swapEndianHex(String hex) {
|
|
||||||
reverseArray(hex.decodeHex()).encodeHex()
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte[] reverseArray(byte[] array) {
|
|
||||||
int i = 0;
|
|
||||||
int j = array.length - 1;
|
|
||||||
byte tmp;
|
|
||||||
while (j > i) {
|
|
||||||
tmp = array[j];
|
|
||||||
array[j] = array[i];
|
|
||||||
array[i] = tmp;
|
|
||||||
j--;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
return array
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def refresh() {
|
def refresh() {
|
||||||
|
|
||||||
log.debug "refresh"
|
log.debug "refresh pressed"
|
||||||
|
sendEvent(name: 'tileMessage', value: 'Refresh', descriptionText: 'Refresh')
|
||||||
|
|
||||||
def refreshCmds = [
|
def refreshCmds = [
|
||||||
|
|
||||||
"st rattr 0x${device.deviceNetworkId} 1 0x0F 0x55", "delay 500",
|
"st rattr 0x${device.deviceNetworkId} 1 0x0F 0x55", "delay 500",
|
||||||
@@ -513,64 +602,96 @@ def refresh() {
|
|||||||
"st rattr 0x${device.deviceNetworkId} 18 0x0F 0x51","delay 500",
|
"st rattr 0x${device.deviceNetworkId} 18 0x0F 0x51","delay 500",
|
||||||
|
|
||||||
]
|
]
|
||||||
return refreshCmds + rain() + manual()
|
|
||||||
|
return refreshCmds
|
||||||
|
}
|
||||||
|
|
||||||
|
private hex(value) {
|
||||||
|
new BigInteger(Math.round(value).toString()).toString(16)
|
||||||
|
}
|
||||||
|
|
||||||
|
private String swapEndianHex(String hex) {
|
||||||
|
reverseArray(hex.decodeHex()).encodeHex()
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] reverseArray(byte[] array) {
|
||||||
|
int i = 0;
|
||||||
|
int j = array.length - 1;
|
||||||
|
byte tmp;
|
||||||
|
while (j > i) {
|
||||||
|
tmp = array[j];
|
||||||
|
array[j] = array[i];
|
||||||
|
array[i] = tmp;
|
||||||
|
j--;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return array
|
||||||
|
}
|
||||||
|
|
||||||
|
//on & off redefined for Alexa to start manual schedule
|
||||||
|
def on() {
|
||||||
|
log.debug 'Alexa on'
|
||||||
|
//schedule subscribes to programOn
|
||||||
|
sendEvent(name: 'switch', value: 'programOn', descriptionText: 'Alexa turned program on')
|
||||||
|
}
|
||||||
|
def off() {
|
||||||
|
log.debug 'Alexa off'
|
||||||
|
sendEvent(name: 'switch', value: 'off', descriptionText: 'Alexa turned program off')
|
||||||
|
zoff()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Commands to device
|
// Commands to device
|
||||||
//zones on - 8
|
//zones on - 8
|
||||||
def on() {
|
def zon() {
|
||||||
//sendEvent(name:"status", value:"active", descriptionText:"Program Running", isStateChange: true, display: false)
|
|
||||||
log.debug "on"
|
|
||||||
"st cmd 0x${device.deviceNetworkId} 1 6 1 {}"
|
"st cmd 0x${device.deviceNetworkId} 1 6 1 {}"
|
||||||
}
|
}
|
||||||
def off() {
|
def zoff() {
|
||||||
log.debug "off"
|
|
||||||
"st cmd 0x${device.deviceNetworkId} 1 6 0 {}"
|
"st cmd 0x${device.deviceNetworkId} 1 6 0 {}"
|
||||||
}
|
}
|
||||||
def z1on() {
|
def z1on() {
|
||||||
"st cmd 0x${device.deviceNetworkId} 2 6 1 {}"
|
return manual() + "st cmd 0x${device.deviceNetworkId} 2 6 1 {}"
|
||||||
}
|
}
|
||||||
def z1off() {
|
def z1off() {
|
||||||
"st cmd 0x${device.deviceNetworkId} 2 6 0 {}"
|
"st cmd 0x${device.deviceNetworkId} 2 6 0 {}"
|
||||||
}
|
}
|
||||||
def z2on() {
|
def z2on() {
|
||||||
"st cmd 0x${device.deviceNetworkId} 3 6 1 {}"
|
return manual() + "st cmd 0x${device.deviceNetworkId} 3 6 1 {}"
|
||||||
}
|
}
|
||||||
def z2off() {
|
def z2off() {
|
||||||
"st cmd 0x${device.deviceNetworkId} 3 6 0 {}"
|
"st cmd 0x${device.deviceNetworkId} 3 6 0 {}"
|
||||||
}
|
}
|
||||||
def z3on() {
|
def z3on() {
|
||||||
"st cmd 0x${device.deviceNetworkId} 4 6 1 {}"
|
return manual() + "st cmd 0x${device.deviceNetworkId} 4 6 1 {}"
|
||||||
}
|
}
|
||||||
def z3off() {
|
def z3off() {
|
||||||
"st cmd 0x${device.deviceNetworkId} 4 6 0 {}"
|
"st cmd 0x${device.deviceNetworkId} 4 6 0 {}"
|
||||||
}
|
}
|
||||||
def z4on() {
|
def z4on() {
|
||||||
"st cmd 0x${device.deviceNetworkId} 5 6 1 {}"
|
return manual() + "st cmd 0x${device.deviceNetworkId} 5 6 1 {}"
|
||||||
}
|
}
|
||||||
def z4off() {
|
def z4off() {
|
||||||
"st cmd 0x${device.deviceNetworkId} 5 6 0 {}"
|
"st cmd 0x${device.deviceNetworkId} 5 6 0 {}"
|
||||||
}
|
}
|
||||||
def z5on() {
|
def z5on() {
|
||||||
"st cmd 0x${device.deviceNetworkId} 6 6 1 {}"
|
return manual() + "st cmd 0x${device.deviceNetworkId} 6 6 1 {}"
|
||||||
}
|
}
|
||||||
def z5off() {
|
def z5off() {
|
||||||
"st cmd 0x${device.deviceNetworkId} 6 6 0 {}"
|
"st cmd 0x${device.deviceNetworkId} 6 6 0 {}"
|
||||||
}
|
}
|
||||||
def z6on() {
|
def z6on() {
|
||||||
"st cmd 0x${device.deviceNetworkId} 7 6 1 {}"
|
return manual() + "st cmd 0x${device.deviceNetworkId} 7 6 1 {}"
|
||||||
}
|
}
|
||||||
def z6off() {
|
def z6off() {
|
||||||
"st cmd 0x${device.deviceNetworkId} 7 6 0 {}"
|
"st cmd 0x${device.deviceNetworkId} 7 6 0 {}"
|
||||||
}
|
}
|
||||||
def z7on() {
|
def z7on() {
|
||||||
"st cmd 0x${device.deviceNetworkId} 8 6 1 {}"
|
return manual() + "st cmd 0x${device.deviceNetworkId} 8 6 1 {}"
|
||||||
}
|
}
|
||||||
def z7off() {
|
def z7off() {
|
||||||
"st cmd 0x${device.deviceNetworkId} 8 6 0 {}"
|
"st cmd 0x${device.deviceNetworkId} 8 6 0 {}"
|
||||||
}
|
}
|
||||||
def z8on() {
|
def z8on() {
|
||||||
"st cmd 0x${device.deviceNetworkId} 9 6 1 {}"
|
return manual() + "st cmd 0x${device.deviceNetworkId} 9 6 1 {}"
|
||||||
}
|
}
|
||||||
def z8off() {
|
def z8off() {
|
||||||
"st cmd 0x${device.deviceNetworkId} 9 6 0 {}"
|
"st cmd 0x${device.deviceNetworkId} 9 6 0 {}"
|
||||||
@@ -578,50 +699,51 @@ def z8off() {
|
|||||||
|
|
||||||
//zones 9 - 16
|
//zones 9 - 16
|
||||||
def z9on() {
|
def z9on() {
|
||||||
"st cmd 0x${device.deviceNetworkId} 10 6 1 {}"
|
return manual() + "st cmd 0x${device.deviceNetworkId} 10 6 1 {}"
|
||||||
}
|
}
|
||||||
def z9off() {
|
def z9off() {
|
||||||
"st cmd 0x${device.deviceNetworkId} 10 6 0 {}"
|
"st cmd 0x${device.deviceNetworkId} 10 6 0 {}"
|
||||||
}
|
}
|
||||||
def z10on() {
|
def z10on() {
|
||||||
"st cmd 0x${device.deviceNetworkId} 11 6 1 {}"
|
return manual() + "st cmd 0x${device.deviceNetworkId} 11 6 1 {}"
|
||||||
}
|
}
|
||||||
def z10off() {
|
def z10off() {
|
||||||
"st cmd 0x${device.deviceNetworkId} 11 6 0 {}"
|
"st cmd 0x${device.deviceNetworkId} 11 6 0 {}"
|
||||||
}
|
}
|
||||||
def z11on() {
|
def z11on() {
|
||||||
"st cmd 0x${device.deviceNetworkId} 12 6 1 {}"
|
return manual() + "st cmd 0x${device.deviceNetworkId} 12 6 1 {}"
|
||||||
}
|
}
|
||||||
def z11off() {
|
def z11off() {
|
||||||
"st cmd 0x${device.deviceNetworkId} 12 6 0 {}"
|
"st cmd 0x${device.deviceNetworkId} 12 6 0 {}"
|
||||||
}
|
}
|
||||||
def z12on() {
|
def z12on() {
|
||||||
"st cmd 0x${device.deviceNetworkId} 13 6 1 {}"
|
return manual() + "st cmd 0x${device.deviceNetworkId} 13 6 1 {}"
|
||||||
}
|
}
|
||||||
def z12off() {
|
def z12off() {
|
||||||
"st cmd 0x${device.deviceNetworkId} 13 6 0 {}"
|
"st cmd 0x${device.deviceNetworkId} 13 6 0 {}"
|
||||||
}
|
}
|
||||||
def z13on() {
|
def z13on() {
|
||||||
"st cmd 0x${device.deviceNetworkId} 14 6 1 {}"
|
return manual() + "st cmd 0x${device.deviceNetworkId} 14 6 1 {}"
|
||||||
}
|
}
|
||||||
def z13off() {
|
def z13off() {
|
||||||
"st cmd 0x${device.deviceNetworkId} 14 6 0 {}"
|
"st cmd 0x${device.deviceNetworkId} 14 6 0 {}"
|
||||||
}
|
}
|
||||||
def z14on() {
|
def z14on() {
|
||||||
"st cmd 0x${device.deviceNetworkId} 15 6 1 {}"
|
return manual() + "st cmd 0x${device.deviceNetworkId} 15 6 1 {}"
|
||||||
}
|
}
|
||||||
def z14off() {
|
def z14off() {
|
||||||
"st cmd 0x${device.deviceNetworkId} 15 6 0 {}"
|
"st cmd 0x${device.deviceNetworkId} 15 6 0 {}"
|
||||||
}
|
}
|
||||||
def z15on() {
|
def z15on() {
|
||||||
"st cmd 0x${device.deviceNetworkId} 16 6 1 {}"
|
return manual() + "st cmd 0x${device.deviceNetworkId} 16 6 1 {}"
|
||||||
}
|
}
|
||||||
def z15off() {
|
def z15off() {
|
||||||
"st cmd 0x${device.deviceNetworkId} 16 6 0 {}"
|
"st cmd 0x${device.deviceNetworkId} 16 6 0 {}"
|
||||||
}
|
}
|
||||||
def z16on() {
|
def z16on() {
|
||||||
"st cmd 0x${device.deviceNetworkId} 17 6 1 {}"
|
return manual() + "st cmd 0x${device.deviceNetworkId} 17 6 1 {}"
|
||||||
}
|
}
|
||||||
def z16off() {
|
def z16off() {
|
||||||
"st cmd 0x${device.deviceNetworkId} 17 6 0 {}"
|
"st cmd 0x${device.deviceNetworkId} 17 6 0 {}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -254,7 +254,8 @@ private Map getTemperatureResult(value) {
|
|||||||
return [
|
return [
|
||||||
name: 'temperature',
|
name: 'temperature',
|
||||||
value: value,
|
value: value,
|
||||||
descriptionText: descriptionText
|
descriptionText: descriptionText,
|
||||||
|
unit: temperatureScale
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ metadata
|
|||||||
{
|
{
|
||||||
standardTile("mainTile", "device.status", width: 1, height: 1, icon: "st.Entertainment.entertainment11")
|
standardTile("mainTile", "device.status", width: 1, height: 1, icon: "st.Entertainment.entertainment11")
|
||||||
{
|
{
|
||||||
state "default", label: "Simple Sync", icon: "st.Home.home2", backgroundColor: "#55A7FF"
|
state "default", label: "Simple Sync", icon: "st.Home.home2", backgroundColor: "#00a0dc"
|
||||||
}
|
}
|
||||||
|
|
||||||
def detailTiles = ["mainTile"]
|
def detailTiles = ["mainTile"]
|
||||||
|
|||||||
@@ -47,9 +47,9 @@ metadata {
|
|||||||
|
|
||||||
tiles {
|
tiles {
|
||||||
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
|
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
|
||||||
state "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"turningOff"
|
state "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#00A0DC", nextState:"turningOff"
|
||||||
state "off", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
state "off", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
state "turningOn", label:'${name}', icon:"st.switches.switch.on", backgroundColor:"#79b821"
|
state "turningOn", label:'${name}', icon:"st.switches.switch.on", backgroundColor:"#00A0DC"
|
||||||
state "turningOff", label:'${name}', icon:"st.switches.switch.off", backgroundColor:"#ffffff"
|
state "turningOff", label:'${name}', icon:"st.switches.switch.off", backgroundColor:"#ffffff"
|
||||||
}
|
}
|
||||||
controlTile("levelSliderControl", "device.level", "slider", height: 2, width: 1, inactiveLabel: false) {
|
controlTile("levelSliderControl", "device.level", "slider", height: 2, width: 1, inactiveLabel: false) {
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ metadata {
|
|||||||
definition (name: "Aeon Key Fob", namespace: "smartthings", author: "SmartThings") {
|
definition (name: "Aeon Key Fob", namespace: "smartthings", author: "SmartThings") {
|
||||||
capability "Actuator"
|
capability "Actuator"
|
||||||
capability "Button"
|
capability "Button"
|
||||||
|
capability "Holdable Button"
|
||||||
capability "Configuration"
|
capability "Configuration"
|
||||||
capability "Sensor"
|
capability "Sensor"
|
||||||
capability "Battery"
|
capability "Battery"
|
||||||
@@ -36,14 +37,14 @@ metadata {
|
|||||||
tiles {
|
tiles {
|
||||||
standardTile("button", "device.button", width: 2, height: 2) {
|
standardTile("button", "device.button", width: 2, height: 2) {
|
||||||
state "default", label: "", icon: "st.unknown.zwave.remote-controller", backgroundColor: "#ffffff"
|
state "default", label: "", icon: "st.unknown.zwave.remote-controller", backgroundColor: "#ffffff"
|
||||||
state "button 1 pushed", label: "pushed #1", icon: "st.unknown.zwave.remote-controller", backgroundColor: "#79b821"
|
state "button 1 pushed", label: "pushed #1", icon: "st.unknown.zwave.remote-controller", backgroundColor: "#00A0DC"
|
||||||
state "button 2 pushed", label: "pushed #2", icon: "st.unknown.zwave.remote-controller", backgroundColor: "#79b821"
|
state "button 2 pushed", label: "pushed #2", icon: "st.unknown.zwave.remote-controller", backgroundColor: "#00A0DC"
|
||||||
state "button 3 pushed", label: "pushed #3", icon: "st.unknown.zwave.remote-controller", backgroundColor: "#79b821"
|
state "button 3 pushed", label: "pushed #3", icon: "st.unknown.zwave.remote-controller", backgroundColor: "#00A0DC"
|
||||||
state "button 4 pushed", label: "pushed #4", icon: "st.unknown.zwave.remote-controller", backgroundColor: "#79b821"
|
state "button 4 pushed", label: "pushed #4", icon: "st.unknown.zwave.remote-controller", backgroundColor: "#00A0DC"
|
||||||
state "button 1 held", label: "held #1", icon: "st.unknown.zwave.remote-controller", backgroundColor: "#ffa81e"
|
state "button 1 held", label: "held #1", icon: "st.unknown.zwave.remote-controller", backgroundColor: "#e86d13"
|
||||||
state "button 2 held", label: "held #2", icon: "st.unknown.zwave.remote-controller", backgroundColor: "#ffa81e"
|
state "button 2 held", label: "held #2", icon: "st.unknown.zwave.remote-controller", backgroundColor: "#e86d13"
|
||||||
state "button 3 held", label: "held #3", icon: "st.unknown.zwave.remote-controller", backgroundColor: "#ffa81e"
|
state "button 3 held", label: "held #3", icon: "st.unknown.zwave.remote-controller", backgroundColor: "#e86d13"
|
||||||
state "button 4 held", label: "held #4", icon: "st.unknown.zwave.remote-controller", backgroundColor: "#ffa81e"
|
state "button 4 held", label: "held #4", icon: "st.unknown.zwave.remote-controller", backgroundColor: "#e86d13"
|
||||||
}
|
}
|
||||||
valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat") {
|
valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat") {
|
||||||
state "battery", label:'${currentValue}% battery', unit:""
|
state "battery", label:'${currentValue}% battery', unit:""
|
||||||
@@ -118,3 +119,16 @@ def configure() {
|
|||||||
log.debug("Sending configuration: $cmd")
|
log.debug("Sending configuration: $cmd")
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def installed() {
|
||||||
|
initialize()
|
||||||
|
}
|
||||||
|
|
||||||
|
def updated() {
|
||||||
|
initialize()
|
||||||
|
}
|
||||||
|
|
||||||
|
def initialize() {
|
||||||
|
sendEvent(name: "numberOfButtons", value: 4)
|
||||||
|
}
|
||||||
|
|||||||
@@ -37,9 +37,9 @@ metadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
standardTile("switch", "device.switch", width: 1, height: 1, canChangeIcon: true) {
|
standardTile("switch", "device.switch", width: 1, height: 1, canChangeIcon: true) {
|
||||||
state "on", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff"
|
state "on", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#00a0dc", nextState:"turningOff"
|
||||||
state "off", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
|
state "off", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
state "turningOn", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff"
|
state "turningOn", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#00a0dc", nextState:"turningOff"
|
||||||
state "turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
|
state "turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
}
|
}
|
||||||
standardTile("reset", "device.reset", inactiveLabel: false, decoration: "flat") {
|
standardTile("reset", "device.reset", inactiveLabel: false, decoration: "flat") {
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ metadata {
|
|||||||
definition (name: "Aeon Minimote", namespace: "smartthings", author: "SmartThings") {
|
definition (name: "Aeon Minimote", namespace: "smartthings", author: "SmartThings") {
|
||||||
capability "Actuator"
|
capability "Actuator"
|
||||||
capability "Button"
|
capability "Button"
|
||||||
|
capability "Holdable Button"
|
||||||
capability "Configuration"
|
capability "Configuration"
|
||||||
capability "Sensor"
|
capability "Sensor"
|
||||||
|
|
||||||
@@ -107,3 +108,16 @@ def configure() {
|
|||||||
log.debug("Sending configuration: $cmds")
|
log.debug("Sending configuration: $cmds")
|
||||||
return cmds
|
return cmds
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def installed() {
|
||||||
|
initialize()
|
||||||
|
}
|
||||||
|
|
||||||
|
def updated() {
|
||||||
|
initialize()
|
||||||
|
}
|
||||||
|
|
||||||
|
def initialize() {
|
||||||
|
sendEvent(name: "numberOfButtons", value: 4)
|
||||||
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ metadata {
|
|||||||
attribute "powerSupply", "enum", ["USB Cable", "Battery"]
|
attribute "powerSupply", "enum", ["USB Cable", "Battery"]
|
||||||
|
|
||||||
fingerprint deviceId: "0x2101", inClusters: "0x5E,0x86,0x72,0x59,0x85,0x73,0x71,0x84,0x80,0x30,0x31,0x70,0x7A", outClusters: "0x5A"
|
fingerprint deviceId: "0x2101", inClusters: "0x5E,0x86,0x72,0x59,0x85,0x73,0x71,0x84,0x80,0x30,0x31,0x70,0x7A", outClusters: "0x5A"
|
||||||
|
fingerprint deviceId: "0x2101", inClusters: "0x5E,0x86,0x72,0x59,0x85,0x73,0x71,0x84,0x80,0x30,0x31,0x70,0x7A,0x5A"
|
||||||
}
|
}
|
||||||
|
|
||||||
simulator {
|
simulator {
|
||||||
@@ -81,8 +82,8 @@ metadata {
|
|||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
multiAttributeTile(name:"motion", type: "generic", width: 6, height: 4){
|
multiAttributeTile(name:"motion", type: "generic", width: 6, height: 4){
|
||||||
tileAttribute ("device.motion", key: "PRIMARY_CONTROL") {
|
tileAttribute ("device.motion", key: "PRIMARY_CONTROL") {
|
||||||
attributeState "active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#53a7c0"
|
attributeState "active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#00A0DC"
|
||||||
attributeState "inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#ffffff"
|
attributeState "inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#cccccc"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
valueTile("temperature", "device.temperature", inactiveLabel: false, width: 2, height: 2) {
|
valueTile("temperature", "device.temperature", inactiveLabel: false, width: 2, height: 2) {
|
||||||
@@ -352,7 +353,7 @@ def configure() {
|
|||||||
motionSensitivity == "minimum" ? 0 : 64)
|
motionSensitivity == "minimum" ? 0 : 64)
|
||||||
|
|
||||||
//5. report every x minutes (threshold reports don't work on battery power, default 8 mins)
|
//5. report every x minutes (threshold reports don't work on battery power, default 8 mins)
|
||||||
request << zwave.configurationV1.configurationSet(parameterNumber: 111, size: 4, scaledConfigurationValue: timeOptionValueMap[reportInterval] ?: 8*60) //association group 1
|
request << zwave.configurationV1.configurationSet(parameterNumber: 111, size: 4, scaledConfigurationValue: timeOptionValueMap[reportInterval] ?: (8*60)) //association group 1
|
||||||
|
|
||||||
request << zwave.configurationV1.configurationSet(parameterNumber: 112, size: 4, scaledConfigurationValue: 6*60*60) //association group 2
|
request << zwave.configurationV1.configurationSet(parameterNumber: 112, size: 4, scaledConfigurationValue: 6*60*60) //association group 2
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
.st-ignore
|
||||||
|
README.md
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
# Aeon Multisensor Gen5
|
||||||
|
|
||||||
|
Cloud Execution
|
||||||
|
|
||||||
|
Works with:
|
||||||
|
|
||||||
|
* [Aeon Labs MultiSensor (Gen 5)](https://www.smartthings.com/works-with-smartthings/sensors/aeon-labs-multisensor-gen-5)
|
||||||
|
|
||||||
|
## Table of contents
|
||||||
|
|
||||||
|
* [Capabilities](#capabilities)
|
||||||
|
* [Health](#device-health)
|
||||||
|
* [Troubleshooting](#troubleshooting)
|
||||||
|
|
||||||
|
## Capabilities
|
||||||
|
|
||||||
|
* **Motion Sensor** - can detect motion
|
||||||
|
* **Temperature Measurement** - defines device measures current temperature
|
||||||
|
* **Relative Humidity Measurement** - allow reading the relative humidity from devices that support it
|
||||||
|
* **Illuminance Measurement** - gives the illuminance reading from devices that support it
|
||||||
|
* **Configuration** - _configure()_ command called when device is installed or device preferences updated
|
||||||
|
* **Sensor** - detects sensor events
|
||||||
|
* **Battery** - defines device uses a battery
|
||||||
|
* **Health Check** - indicates ability to get device health notifications
|
||||||
|
|
||||||
|
|
||||||
|
## Device Health
|
||||||
|
|
||||||
|
Aeon Labs MultiSensor (Gen 5) is polled by the hub.
|
||||||
|
As of hubCore version 0.14.38 the hub sends up reports every 15 minutes regardless of whether the state changed.
|
||||||
|
Device-Watch allows 2 check-in misses from device plus some lag time. So Check-in interval = (2*15 + 2)mins = 32 mins.
|
||||||
|
Not to mention after going OFFLINE when the device is plugged back in, it might take a considerable amount of time for
|
||||||
|
the device to appear as ONLINE again. This is because if this listening device does not respond to two poll requests in a row,
|
||||||
|
it is not polled for 5 minutes by the hub. This can delay up the process of being marked ONLINE by quite some time.
|
||||||
|
|
||||||
|
* __32min__ checkInterval
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the device is out of range.
|
||||||
|
Pairing needs to be tried again by placing the device closer to the hub.
|
||||||
|
Instructions related to pairing, resetting and removing the device from SmartThings can be found in the following link:
|
||||||
|
* [Aeon Labs MultiSensor (Gen 5) Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/206157226-Aeon-Labs-MultiSensor-Gen-5-)
|
||||||
@@ -20,8 +20,12 @@ metadata {
|
|||||||
capability "Configuration"
|
capability "Configuration"
|
||||||
capability "Sensor"
|
capability "Sensor"
|
||||||
capability "Battery"
|
capability "Battery"
|
||||||
|
capability "Health Check"
|
||||||
|
|
||||||
|
command "configureAfterSecure"
|
||||||
|
|
||||||
fingerprint deviceId: "0x0701", inClusters: "0x5E,0x86,0x72,0x59,0x85,0x73,0x71,0x84,0x80,0x30,0x31,0x70,0x98,0x7A", outClusters:"0x5A"
|
fingerprint deviceId: "0x0701", inClusters: "0x5E,0x86,0x72,0x59,0x85,0x73,0x71,0x84,0x80,0x30,0x31,0x70,0x98,0x7A", outClusters:"0x5A"
|
||||||
|
fingerprint mfr:"0086", prod:"0102", model:"004A", deviceJoinName: "Aeon Labs MultiSensor (Gen 5)"
|
||||||
}
|
}
|
||||||
|
|
||||||
simulator {
|
simulator {
|
||||||
@@ -62,8 +66,8 @@ metadata {
|
|||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
multiAttributeTile(name:"motion", type: "generic", width: 6, height: 4){
|
multiAttributeTile(name:"motion", type: "generic", width: 6, height: 4){
|
||||||
tileAttribute ("device.motion", key: "PRIMARY_CONTROL") {
|
tileAttribute ("device.motion", key: "PRIMARY_CONTROL") {
|
||||||
attributeState "active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#53a7c0"
|
attributeState "active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#00a0dc"
|
||||||
attributeState "inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#ffffff"
|
attributeState "inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#cccccc"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
valueTile("temperature", "device.temperature", inactiveLabel: false, width: 2, height: 2) {
|
valueTile("temperature", "device.temperature", inactiveLabel: false, width: 2, height: 2) {
|
||||||
@@ -96,6 +100,16 @@ metadata {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def installed(){
|
||||||
|
// Device-Watch simply pings if no device events received for 32min(checkInterval)
|
||||||
|
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
|
||||||
|
}
|
||||||
|
|
||||||
|
def updated(){
|
||||||
|
// Device-Watch simply pings if no device events received for 32min(checkInterval)
|
||||||
|
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
|
||||||
|
}
|
||||||
|
|
||||||
def parse(String description)
|
def parse(String description)
|
||||||
{
|
{
|
||||||
def result = null
|
def result = null
|
||||||
@@ -242,6 +256,13 @@ def configureAfterSecure() {
|
|||||||
secureSequence(request) + ["delay 20000", zwave.wakeUpV1.wakeUpNoMoreInformation().format()]
|
secureSequence(request) + ["delay 20000", zwave.wakeUpV1.wakeUpNoMoreInformation().format()]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PING is used by Device-Watch in attempt to reach the Device
|
||||||
|
* */
|
||||||
|
def ping() {
|
||||||
|
secure(zwave.batteryV1.batteryGet())
|
||||||
|
}
|
||||||
|
|
||||||
def configure() {
|
def configure() {
|
||||||
// log.debug "configure()"
|
// log.debug "configure()"
|
||||||
//["delay 30000"] + secure(zwave.securityV1.securityCommandsSupportedGet())
|
//["delay 30000"] + secure(zwave.securityV1.securityCommandsSupportedGet())
|
||||||
|
|||||||
@@ -59,8 +59,8 @@ metadata {
|
|||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
multiAttributeTile(name:"motion", type: "generic", width: 6, height: 4){
|
multiAttributeTile(name:"motion", type: "generic", width: 6, height: 4){
|
||||||
tileAttribute ("device.motion", key: "PRIMARY_CONTROL") {
|
tileAttribute ("device.motion", key: "PRIMARY_CONTROL") {
|
||||||
attributeState "active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#53a7c0"
|
attributeState "active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#00a0dc"
|
||||||
attributeState "inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#ffffff"
|
attributeState "inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#cccccc"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
valueTile("temperature", "device.temperature", inactiveLabel: false, width: 2, height: 2) {
|
valueTile("temperature", "device.temperature", inactiveLabel: false, width: 2, height: 2) {
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ metadata {
|
|||||||
// tile definitions
|
// tile definitions
|
||||||
tiles {
|
tiles {
|
||||||
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
|
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
|
||||||
state "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#79b821"
|
state "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#00a0dc"
|
||||||
state "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff"
|
state "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff"
|
||||||
}
|
}
|
||||||
valueTile("energy", "device.energy", decoration: "flat") {
|
valueTile("energy", "device.energy", decoration: "flat") {
|
||||||
|
|||||||
+1
-1
@@ -53,7 +53,7 @@ metadata {
|
|||||||
// tile definitions
|
// tile definitions
|
||||||
tiles {
|
tiles {
|
||||||
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
|
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
|
||||||
state "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#79b821"
|
state "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#00A0DC"
|
||||||
state "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff"
|
state "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff"
|
||||||
}
|
}
|
||||||
valueTile("power", "device.power", decoration: "flat") {
|
valueTile("power", "device.power", decoration: "flat") {
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
.st-ignore
|
||||||
|
README.md
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
# Aeon Siren
|
||||||
|
|
||||||
|
Cloud Execution
|
||||||
|
|
||||||
|
Works with:
|
||||||
|
|
||||||
|
* [Aeon Labs Siren (Gen 5)](https://www.smartthings.com/works-with-smartthings/aeon-labs/aeon-labs-siren-gen-5)
|
||||||
|
|
||||||
|
## Table of contents
|
||||||
|
|
||||||
|
* [Capabilities](#capabilities)
|
||||||
|
* [Health](#device-health)
|
||||||
|
|
||||||
|
## Capabilities
|
||||||
|
|
||||||
|
* **Actuator** - represents that a Device has commands
|
||||||
|
* **Alarm** - allows for interacting with devices that serve as alarms
|
||||||
|
* **Switch** - can detect state (possible values: on/off)
|
||||||
|
* **Health Check** - indicates ability to get device health notifications
|
||||||
|
|
||||||
|
## Device Health
|
||||||
|
|
||||||
|
Aeon Labs Siren (Gen 5) is polled by the hub.
|
||||||
|
As of hubCore version 0.14.38 the hub sends up reports every 15 minutes regardless of whether the state changed.
|
||||||
|
Device-Watch allows 2 check-in misses from device plus some lag time. So Check-in interval = (2*15 + 2)mins = 32 mins.
|
||||||
|
Not to mention after going OFFLINE when the device is plugged back in, it might take a considerable amount of time for
|
||||||
|
the device to appear as ONLINE again. This is because if this listening device does not respond to two poll requests in a row,
|
||||||
|
it is not polled for 5 minutes by the hub. This can delay up the process of being marked ONLINE by quite some time.
|
||||||
|
|
||||||
|
* __32min__ checkInterval
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the device is out of range.
|
||||||
|
Pairing needs to be tried again by placing the device closer to the hub.
|
||||||
|
Instructions related to pairing, resetting and removing the device from SmartThings can be found in the following link:
|
||||||
|
* [Aeon Labs Siren (Gen 5) Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/204555240-Aeon-Labs-Siren-Gen-5-)
|
||||||
@@ -20,10 +20,11 @@ metadata {
|
|||||||
capability "Actuator"
|
capability "Actuator"
|
||||||
capability "Alarm"
|
capability "Alarm"
|
||||||
capability "Switch"
|
capability "Switch"
|
||||||
|
capability "Health Check"
|
||||||
|
|
||||||
command "test"
|
command "test"
|
||||||
|
|
||||||
fingerprint deviceId: "0x1005", inClusters: "0x5E,0x98"
|
fingerprint deviceId: "0x1005", inClusters: "0x5E,0x98", deviceJoinName: "Aeon Labs Siren (Gen 5)"
|
||||||
}
|
}
|
||||||
|
|
||||||
simulator {
|
simulator {
|
||||||
@@ -57,7 +58,15 @@ metadata {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def installed() {
|
||||||
|
// Device-Watch simply pings if no device events received for 32min(checkInterval)
|
||||||
|
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
|
||||||
|
}
|
||||||
|
|
||||||
def updated() {
|
def updated() {
|
||||||
|
// Device-Watch simply pings if no device events received for 32min(checkInterval)
|
||||||
|
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
|
||||||
|
|
||||||
if(!state.sound) state.sound = 1
|
if(!state.sound) state.sound = 1
|
||||||
if(!state.volume) state.volume = 3
|
if(!state.volume) state.volume = 3
|
||||||
|
|
||||||
@@ -148,3 +157,10 @@ def test() {
|
|||||||
private secure(physicalgraph.zwave.Command cmd) {
|
private secure(physicalgraph.zwave.Command cmd) {
|
||||||
zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format()
|
zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PING is used by Device-Watch in attempt to reach the Device
|
||||||
|
* */
|
||||||
|
def ping() {
|
||||||
|
secure(zwave.basicV1.basicGet())
|
||||||
|
}
|
||||||
@@ -60,7 +60,7 @@ metadata {
|
|||||||
// tile definitions
|
// tile definitions
|
||||||
tiles {
|
tiles {
|
||||||
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
|
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
|
||||||
state "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#79b821"
|
state "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#00a0dc"
|
||||||
state "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff"
|
state "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff"
|
||||||
}
|
}
|
||||||
valueTile("power", "device.power", decoration: "flat") {
|
valueTile("power", "device.power", decoration: "flat") {
|
||||||
@@ -78,7 +78,7 @@ metadata {
|
|||||||
|
|
||||||
(1..4).each { n ->
|
(1..4).each { n ->
|
||||||
standardTile("switch$n", "switch$n", canChangeIcon: true) {
|
standardTile("switch$n", "switch$n", canChangeIcon: true) {
|
||||||
state "on", label: '${name}', action: "off$n", icon: "st.switches.switch.on", backgroundColor: "#79b821"
|
state "on", label: '${name}', action: "off$n", icon: "st.switches.switch.on", backgroundColor: "#00a0dc"
|
||||||
state "off", label: '${name}', action: "on$n", icon: "st.switches.switch.off", backgroundColor: "#ffffff"
|
state "off", label: '${name}', action: "on$n", icon: "st.switches.switch.off", backgroundColor: "#ffffff"
|
||||||
}
|
}
|
||||||
valueTile("power$n", "power$n", decoration: "flat") {
|
valueTile("power$n", "power$n", decoration: "flat") {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright 2016 SmartThings
|
* Copyright 2017 SmartThings
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||||
* in compliance with the License. You may obtain a copy of the License at:
|
* in compliance with the License. You may obtain a copy of the License at:
|
||||||
@@ -11,17 +11,6 @@
|
|||||||
* for the specific language governing permissions and limitations under the License.
|
* for the specific language governing permissions and limitations under the License.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
|
||||||
* Purpose: Arrival Sensor HA DTH File
|
|
||||||
*
|
|
||||||
* Filename: Arrival-Sensor-HA.src/Arrival-Sensor-HA.groovy
|
|
||||||
*
|
|
||||||
* Change History:
|
|
||||||
* 1. 20160115 TW - Update/Edit to support i18n translations
|
|
||||||
* 2. 20160121 TW - Update to V4 battery calcs, added pref's page title translations
|
|
||||||
*/
|
|
||||||
|
|
||||||
metadata {
|
metadata {
|
||||||
definition (name: "Arrival Sensor HA", namespace: "smartthings", author: "SmartThings") {
|
definition (name: "Arrival Sensor HA", namespace: "smartthings", author: "SmartThings") {
|
||||||
capability "Tone"
|
capability "Tone"
|
||||||
@@ -50,7 +39,7 @@ metadata {
|
|||||||
|
|
||||||
tiles {
|
tiles {
|
||||||
standardTile("presence", "device.presence", width: 2, height: 2, canChangeBackground: true) {
|
standardTile("presence", "device.presence", width: 2, height: 2, canChangeBackground: true) {
|
||||||
state "present", labelIcon:"st.presence.tile.present", backgroundColor:"#53a7c0"
|
state "present", labelIcon:"st.presence.tile.present", backgroundColor:"#00a0dc"
|
||||||
state "not present", labelIcon:"st.presence.tile.not-present", backgroundColor:"#ffffff"
|
state "not present", labelIcon:"st.presence.tile.not-present", backgroundColor:"#ffffff"
|
||||||
}
|
}
|
||||||
standardTile("beep", "device.beep", decoration: "flat") {
|
standardTile("beep", "device.beep", decoration: "flat") {
|
||||||
@@ -70,7 +59,7 @@ def updated() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def configure() {
|
def configure() {
|
||||||
def cmds = zigbee.configureReporting(0x0001, 0x0020, 0x20, 20, 20, 0x01)
|
def cmds = zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, 0x0020) + zigbee.batteryConfig(20, 20, 0x01)
|
||||||
log.debug "configure -- cmds: ${cmds}"
|
log.debug "configure -- cmds: ${cmds}"
|
||||||
return cmds
|
return cmds
|
||||||
}
|
}
|
||||||
@@ -162,7 +151,7 @@ private handlePresenceEvent(present) {
|
|||||||
|
|
||||||
private startTimer() {
|
private startTimer() {
|
||||||
log.debug "Scheduling periodic timer"
|
log.debug "Scheduling periodic timer"
|
||||||
schedule("0 * * * * ?", checkPresenceCallback)
|
runEvery1Minute("checkPresenceCallback")
|
||||||
}
|
}
|
||||||
|
|
||||||
private stopTimer() {
|
private stopTimer() {
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
#==============================================================================
|
|
||||||
# Copyright 2016 SmartThings
|
# Copyright 2016 SmartThings
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
@@ -12,15 +11,6 @@
|
|||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
#==============================================================================
|
|
||||||
# Purpose: Arrival Sensor HA i18n Translation File
|
|
||||||
#
|
|
||||||
# Filename: Arrival-Sensor-HA.src/i18n/messages.properties
|
|
||||||
#
|
|
||||||
# Change History:
|
|
||||||
# 1. 20160115 TW Initial release with informal Korean translation.
|
|
||||||
# 2. 20160121 TW Added def preference section titles.
|
|
||||||
#==============================================================================
|
|
||||||
# Korean (ko)
|
# Korean (ko)
|
||||||
# Device Preferences
|
# Device Preferences
|
||||||
'''Give your device a name'''.ko=기기 이름 설정
|
'''Give your device a name'''.ko=기기 이름 설정
|
||||||
|
|||||||
@@ -42,8 +42,8 @@ metadata {
|
|||||||
|
|
||||||
tiles {
|
tiles {
|
||||||
standardTile("presence", "device.presence", width: 2, height: 2, canChangeBackground: true) {
|
standardTile("presence", "device.presence", width: 2, height: 2, canChangeBackground: true) {
|
||||||
state "present", labelIcon:"st.presence.tile.present", backgroundColor:"#53a7c0"
|
state "present", labelIcon:"st.presence.tile.present", backgroundColor:"#00a0dc"
|
||||||
state "not present", labelIcon:"st.presence.tile.not-present", backgroundColor:"#ebeef2"
|
state "not present", labelIcon:"st.presence.tile.not-present", backgroundColor:"#ffffff"
|
||||||
}
|
}
|
||||||
standardTile("beep", "device.beep", decoration: "flat") {
|
standardTile("beep", "device.beep", decoration: "flat") {
|
||||||
state "beep", label:'', action:"tone.beep", icon:"st.secondary.beep", backgroundColor:"#ffffff"
|
state "beep", label:'', action:"tone.beep", icon:"st.secondary.beep", backgroundColor:"#ffffff"
|
||||||
@@ -87,16 +87,27 @@ def beep() {
|
|||||||
up to this long from the time you send the message to the time you hear a sound.
|
up to this long from the time you send the message to the time you hear a sound.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Used source endpoint of 0x02 because we are using smartthings manufacturer specific cluster.
|
||||||
[
|
[
|
||||||
"raw 0xFC05 {15 0A 11 00 00 15 01}",
|
"raw 0xFC05 {15 0A 11 00 00 15 01}",
|
||||||
|
"delay 200",
|
||||||
|
"send 0x$zigbee.deviceNetworkId 0x02 0x$zigbee.endpointId",
|
||||||
"delay 7000",
|
"delay 7000",
|
||||||
"raw 0xFC05 {15 0A 11 00 00 15 01}",
|
"raw 0xFC05 {15 0A 11 00 00 15 01}",
|
||||||
|
"delay 200",
|
||||||
|
"send 0x$zigbee.deviceNetworkId 0x02 0x$zigbee.endpointId",
|
||||||
"delay 7000",
|
"delay 7000",
|
||||||
"raw 0xFC05 {15 0A 11 00 00 15 01}",
|
"raw 0xFC05 {15 0A 11 00 00 15 01}",
|
||||||
|
"delay 200",
|
||||||
|
"send 0x$zigbee.deviceNetworkId 0x02 0x$zigbee.endpointId",
|
||||||
"delay 7000",
|
"delay 7000",
|
||||||
"raw 0xFC05 {15 0A 11 00 00 15 01}",
|
"raw 0xFC05 {15 0A 11 00 00 15 01}",
|
||||||
|
"delay 200",
|
||||||
|
"send 0x$zigbee.deviceNetworkId 0x02 0x$zigbee.endpointId",
|
||||||
"delay 7000",
|
"delay 7000",
|
||||||
"raw 0xFC05 {15 0A 11 00 00 15 01}"
|
"raw 0xFC05 {15 0A 11 00 00 15 01}",
|
||||||
|
"delay 200",
|
||||||
|
"send 0x$zigbee.deviceNetworkId 0x02 0x$zigbee.endpointId",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,9 @@ metadata {
|
|||||||
capability "Switch"
|
capability "Switch"
|
||||||
capability "Refresh"
|
capability "Refresh"
|
||||||
capability "Music Player"
|
capability "Music Player"
|
||||||
capability "Polling"
|
capability "Health Check"
|
||||||
|
capability "Sensor"
|
||||||
|
capability "Actuator"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Define all commands, ie, if you have a custom action not
|
* Define all commands, ie, if you have a custom action not
|
||||||
@@ -47,6 +49,9 @@ metadata {
|
|||||||
|
|
||||||
command "everywhereJoin"
|
command "everywhereJoin"
|
||||||
command "everywhereLeave"
|
command "everywhereLeave"
|
||||||
|
|
||||||
|
command "forceOff"
|
||||||
|
command "forceOn"
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -64,8 +69,10 @@ metadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
standardTile("switch", "device.switch", width: 1, height: 1, canChangeIcon: true) {
|
standardTile("switch", "device.switch", width: 1, height: 1, canChangeIcon: true) {
|
||||||
state "off", label: '${name}', action: "switch.on", icon: "st.Electronics.electronics16", backgroundColor: "#ffffff"
|
state "on", label: '${name}', action: "forceOff", icon: "st.Electronics.electronics16", backgroundColor: "#00a0dc", nextState:"turningOff"
|
||||||
state "on", label: '${name}', action: "switch.off", icon: "st.Electronics.electronics16", backgroundColor: "#79b821"
|
state "turningOff", label:'TURNING OFF', icon:"st.Electronics.electronics16", backgroundColor:"#ffffff"
|
||||||
|
state "off", label: '${name}', action: "forceOn", icon: "st.Electronics.electronics16", backgroundColor: "#ffffff", nextState:"turningOn"
|
||||||
|
state "turningOn", label:'TURNING ON', icon:"st.Electronics.electronics16", backgroundColor:"#00a0dc"
|
||||||
}
|
}
|
||||||
valueTile("1", "device.station1", decoration: "flat", canChangeIcon: false) {
|
valueTile("1", "device.station1", decoration: "flat", canChangeIcon: false) {
|
||||||
state "station1", label:'${currentValue}', action:"preset1"
|
state "station1", label:'${currentValue}', action:"preset1"
|
||||||
@@ -138,8 +145,22 @@ metadata {
|
|||||||
* one place.
|
* one place.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
def off() { onAction("off") }
|
def off() {
|
||||||
def on() { onAction("on") }
|
if (device.currentState("switch")?.value == "on") {
|
||||||
|
onAction("off")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
def forceOff() {
|
||||||
|
onAction("off")
|
||||||
|
}
|
||||||
|
def on() {
|
||||||
|
if (device.currentState("switch")?.value == "off") {
|
||||||
|
onAction("on")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
def forceOn() {
|
||||||
|
onAction("on")
|
||||||
|
}
|
||||||
def volup() { onAction("volup") }
|
def volup() { onAction("volup") }
|
||||||
def voldown() { onAction("voldown") }
|
def voldown() { onAction("voldown") }
|
||||||
def preset1() { onAction("1") }
|
def preset1() { onAction("1") }
|
||||||
@@ -217,7 +238,33 @@ def parse(String event) {
|
|||||||
* @return action(s) to take or null
|
* @return action(s) to take or null
|
||||||
*/
|
*/
|
||||||
def installed() {
|
def installed() {
|
||||||
onAction("refresh")
|
// Notify health check about this device with timeout interval 12 minutes
|
||||||
|
sendEvent(name: "checkInterval", value: 12 * 60, data: [protocol: "lan", hubHardwareId: device.hub.hardwareID], displayed: false)
|
||||||
|
startPoll()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by health check if no events been generated in the last 12 minutes
|
||||||
|
* If device doesn't respond it will be marked offline (not available)
|
||||||
|
*/
|
||||||
|
def ping() {
|
||||||
|
TRACE("ping")
|
||||||
|
boseSendGetNowPlaying()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schedule a 2 minute poll of the device to refresh the
|
||||||
|
* tiles so the user gets the correct information.
|
||||||
|
*/
|
||||||
|
def startPoll() {
|
||||||
|
TRACE("startPoll")
|
||||||
|
unschedule()
|
||||||
|
// Schedule 2 minute polling of speaker status (song average length is 3-4 minutes)
|
||||||
|
def sec = Math.round(Math.floor(Math.random() * 60))
|
||||||
|
//def cron = "$sec 0/5 * * * ?" // every 5 min
|
||||||
|
def cron = "$sec 0/2 * * * ?" // every 2 min
|
||||||
|
log.debug "schedule('$cron', boseSendGetNowPlaying)"
|
||||||
|
schedule(cron, boseSendGetNowPlaying)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -238,11 +285,11 @@ def onAction(String user, data=null) {
|
|||||||
def actions = null
|
def actions = null
|
||||||
switch (user) {
|
switch (user) {
|
||||||
case "on":
|
case "on":
|
||||||
actions = boseSetPowerState(true)
|
boseSetPowerState(true)
|
||||||
break
|
break
|
||||||
case "off":
|
case "off":
|
||||||
boseSetNowPlaying(null, "STANDBY")
|
boseSetNowPlaying(null, "STANDBY")
|
||||||
actions = boseSetPowerState(false)
|
boseSetPowerState(false)
|
||||||
break
|
break
|
||||||
case "volume":
|
case "volume":
|
||||||
actions = boseSetVolume(data)
|
actions = boseSetVolume(data)
|
||||||
@@ -297,14 +344,6 @@ def onAction(String user, data=null) {
|
|||||||
return actions
|
return actions
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Called every so often (every 5 minutes actually) to refresh the
|
|
||||||
* tiles so the user gets the correct information.
|
|
||||||
*/
|
|
||||||
def poll() {
|
|
||||||
return boseRefreshNowPlaying()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Joins this speaker into the everywhere zone
|
* Joins this speaker into the everywhere zone
|
||||||
*/
|
*/
|
||||||
@@ -747,8 +786,16 @@ def cb_boseSetInput(xml, input) {
|
|||||||
*/
|
*/
|
||||||
def boseSetPowerState(boolean enable) {
|
def boseSetPowerState(boolean enable) {
|
||||||
log.info "boseSetPowerState(${enable})"
|
log.info "boseSetPowerState(${enable})"
|
||||||
queueCallback('nowPlaying', "cb_boseSetPowerState", enable ? "POWERON" : "POWEROFF")
|
// Fix to get faster update of power status back from speaker after sending on/off
|
||||||
return boseRefreshNowPlaying()
|
// Instead of queuing the command to be sent after the refresh send it directly via sendHubCommand
|
||||||
|
// Note: This is a temporary hack that should be replaced by a re-design of the
|
||||||
|
// DTH to use sendHubCommand for all commands
|
||||||
|
sendHubCommand(bosePOST("/key", "<key state=\"press\" sender=\"Gabbo\">POWER</key>"))
|
||||||
|
sendHubCommand(bosePOST("/key", "<key state=\"release\" sender=\"Gabbo\">POWER</key>"))
|
||||||
|
sendHubCommand(boseGET("/now_playing"))
|
||||||
|
if (enable) {
|
||||||
|
queueCallback('nowPlaying', "cb_boseConfirmPowerOn", 5)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -787,10 +834,11 @@ def cb_boseSetPowerState(xml, state) {
|
|||||||
*/
|
*/
|
||||||
def cb_boseConfirmPowerOn(xml, tries) {
|
def cb_boseConfirmPowerOn(xml, tries) {
|
||||||
def result = []
|
def result = []
|
||||||
log.warn "boseConfirmPowerOn() attempt #" + tries
|
def attempt = tries as Integer
|
||||||
if (xml.attributes()['source'] == "STANDBY" && tries > 0) {
|
log.warn "boseConfirmPowerOn() attempt #$attempt"
|
||||||
|
if (xml.attributes()['source'] == "STANDBY" && attempt > 0) {
|
||||||
result << boseRefreshNowPlaying()
|
result << boseRefreshNowPlaying()
|
||||||
queueCallback('nowPlaying', "cb_boseConfirmPowerOn", tries-1)
|
queueCallback('nowPlaying', "cb_boseConfirmPowerOn", attempt-1)
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
@@ -809,6 +857,10 @@ def boseRefreshNowPlaying(delay=0) {
|
|||||||
return boseGET("/now_playing")
|
return boseGET("/now_playing")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def boseSendGetNowPlaying() {
|
||||||
|
sendHubCommand(boseGET("/now_playing"))
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Requests the list of presets
|
* Requests the list of presets
|
||||||
*
|
*
|
||||||
@@ -987,3 +1039,7 @@ def boseGetDeviceID() {
|
|||||||
def getDeviceIP() {
|
def getDeviceIP() {
|
||||||
return parent.resolveDNI2Address(device.deviceNetworkId)
|
return parent.resolveDNI2Address(device.deviceNetworkId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def TRACE(text) {
|
||||||
|
log.trace "${text}"
|
||||||
|
}
|
||||||
@@ -1,146 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright 2015 SmartThings
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License. You may obtain a copy of the License at:
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
|
||||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
|
|
||||||
* for the specific language governing permissions and limitations under the License.
|
|
||||||
*
|
|
||||||
* CentraLite Dimmer
|
|
||||||
*
|
|
||||||
* Author: SmartThings
|
|
||||||
* Date: 2013-12-04
|
|
||||||
*/
|
|
||||||
//DEPRECATED - Using the generic DTH for this device. Users need to be moved before deleting this DTH
|
|
||||||
metadata {
|
|
||||||
definition (name: "CentraLite Dimmer", namespace: "smartthings", author: "SmartThings") {
|
|
||||||
capability "Switch Level"
|
|
||||||
capability "Actuator"
|
|
||||||
capability "Switch"
|
|
||||||
capability "Power Meter"
|
|
||||||
capability "Configuration"
|
|
||||||
capability "Refresh"
|
|
||||||
capability "Sensor"
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// simulator metadata
|
|
||||||
simulator {
|
|
||||||
// status messages
|
|
||||||
status "on": "on/off: 1"
|
|
||||||
status "off": "on/off: 0"
|
|
||||||
|
|
||||||
// reply messages
|
|
||||||
reply "zcl on-off on": "on/off: 1"
|
|
||||||
reply "zcl on-off off": "on/off: 0"
|
|
||||||
}
|
|
||||||
|
|
||||||
tiles(scale: 2) {
|
|
||||||
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
|
||||||
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
|
||||||
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"turningOff"
|
|
||||||
attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
|
||||||
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"turningOff"
|
|
||||||
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
|
||||||
}
|
|
||||||
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
|
|
||||||
attributeState "level", action:"switch level.setLevel"
|
|
||||||
}
|
|
||||||
tileAttribute ("power", key: "SECONDARY_CONTROL") {
|
|
||||||
attributeState "power", label:'${currentValue} W'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
standardTile("refresh", "device.power", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
|
||||||
state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh"
|
|
||||||
}
|
|
||||||
|
|
||||||
main "switch"
|
|
||||||
details(["switch","refresh"])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse incoming device messages to generate events
|
|
||||||
def parse(String description) {
|
|
||||||
log.debug "Parse description $description"
|
|
||||||
def name = null
|
|
||||||
def value = null
|
|
||||||
if (description?.startsWith("catchall:")) {
|
|
||||||
def msg = zigbee.parse(description)
|
|
||||||
log.trace msg
|
|
||||||
log.trace "data: $msg.data"
|
|
||||||
} else if (description?.startsWith("read attr -")) {
|
|
||||||
def descMap = parseDescriptionAsMap(description)
|
|
||||||
log.debug "Read attr: $description"
|
|
||||||
if (descMap.cluster == "0006" && descMap.attrId == "0000") {
|
|
||||||
name = "switch"
|
|
||||||
value = descMap.value.endsWith("01") ? "on" : "off"
|
|
||||||
} else {
|
|
||||||
def reportValue = description.split(",").find {it.split(":")[0].trim() == "value"}?.split(":")[1].trim()
|
|
||||||
name = "power"
|
|
||||||
// assume 16 bit signed for encoding and power divisor is 10
|
|
||||||
value = Integer.parseInt(reportValue, 16) / 10
|
|
||||||
}
|
|
||||||
} else if (description?.startsWith("on/off:")) {
|
|
||||||
log.debug "Switch command"
|
|
||||||
name = "switch"
|
|
||||||
value = description?.endsWith(" 1") ? "on" : "off"
|
|
||||||
}
|
|
||||||
|
|
||||||
def result = createEvent(name: name, value: value)
|
|
||||||
log.debug "Parse returned ${result?.descriptionText}"
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
def parseDescriptionAsMap(description) {
|
|
||||||
(description - "read attr - ").split(",").inject([:]) { map, param ->
|
|
||||||
def nameAndValue = param.split(":")
|
|
||||||
map += [(nameAndValue[0].trim()):nameAndValue[1].trim()]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Commands to device
|
|
||||||
def on() {
|
|
||||||
'zcl on-off on'
|
|
||||||
}
|
|
||||||
|
|
||||||
def off() {
|
|
||||||
'zcl on-off off'
|
|
||||||
}
|
|
||||||
|
|
||||||
def setLevel(value) {
|
|
||||||
log.trace "setLevel($value)"
|
|
||||||
sendEvent(name: "level", value: value)
|
|
||||||
def level = hexString(Math.round(value * 255/100))
|
|
||||||
def cmd = "st cmd 0x${device.deviceNetworkId} 1 8 4 {${level} 2000}"
|
|
||||||
log.debug cmd
|
|
||||||
cmd
|
|
||||||
}
|
|
||||||
|
|
||||||
def meter() {
|
|
||||||
"st rattr 0x${device.deviceNetworkId} 1 0xB04 0x50B"
|
|
||||||
}
|
|
||||||
|
|
||||||
def refresh() {
|
|
||||||
"st rattr 0x${device.deviceNetworkId} 1 0xB04 0x50B"
|
|
||||||
}
|
|
||||||
|
|
||||||
def configure() {
|
|
||||||
[
|
|
||||||
"zdo bind 0x${device.deviceNetworkId} 1 1 8 {${device.zigbeeId}} {}", "delay 200",
|
|
||||||
"zdo bind 0x${device.deviceNetworkId} 1 1 6 {${device.zigbeeId}} {}", "delay 200",
|
|
||||||
"zdo bind 0x${device.deviceNetworkId} 1 1 0xB04 {${device.zigbeeId}} {}"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
private hex(value, width=2) {
|
|
||||||
def s = new BigInteger(Math.round(value).toString()).toString(16)
|
|
||||||
while (s.size() < width) {
|
|
||||||
s = "0" + s
|
|
||||||
}
|
|
||||||
s
|
|
||||||
}
|
|
||||||
@@ -55,13 +55,13 @@ metadata {
|
|||||||
state "fanOn", label:'${name}', action:"thermostat.setThermostatFanMode"
|
state "fanOn", label:'${name}', action:"thermostat.setThermostatFanMode"
|
||||||
}
|
}
|
||||||
controlTile("heatSliderControl", "device.heatingSetpoint", "slider", height: 1, width: 2, inactiveLabel: false) {
|
controlTile("heatSliderControl", "device.heatingSetpoint", "slider", height: 1, width: 2, inactiveLabel: false) {
|
||||||
state "setHeatingSetpoint", action:"thermostat.setHeatingSetpoint", backgroundColor:"#d04e00"
|
state "setHeatingSetpoint", action:"thermostat.setHeatingSetpoint", backgroundColor:"#e86d13"
|
||||||
}
|
}
|
||||||
valueTile("heatingSetpoint", "device.heatingSetpoint", inactiveLabel: false, decoration: "flat") {
|
valueTile("heatingSetpoint", "device.heatingSetpoint", inactiveLabel: false, decoration: "flat") {
|
||||||
state "heat", label:'${currentValue}° heat', unit:"F", backgroundColor:"#ffffff"
|
state "heat", label:'${currentValue}° heat', unit:"F", backgroundColor:"#ffffff"
|
||||||
}
|
}
|
||||||
controlTile("coolSliderControl", "device.coolingSetpoint", "slider", height: 1, width: 2, inactiveLabel: false) {
|
controlTile("coolSliderControl", "device.coolingSetpoint", "slider", height: 1, width: 2, inactiveLabel: false) {
|
||||||
state "setCoolingSetpoint", action:"thermostat.setCoolingSetpoint", backgroundColor: "#1e9cbb"
|
state "setCoolingSetpoint", action:"thermostat.setCoolingSetpoint", backgroundColor: "#00a0dc"
|
||||||
}
|
}
|
||||||
valueTile("coolingSetpoint", "device.coolingSetpoint", inactiveLabel: false, decoration: "flat") {
|
valueTile("coolingSetpoint", "device.coolingSetpoint", inactiveLabel: false, decoration: "flat") {
|
||||||
state "cool", label:'${currentValue}° cool', unit:"F", backgroundColor:"#ffffff"
|
state "cool", label:'${currentValue}° cool', unit:"F", backgroundColor:"#ffffff"
|
||||||
@@ -81,48 +81,47 @@ metadata {
|
|||||||
// parse events into attributes
|
// parse events into attributes
|
||||||
def parse(String description) {
|
def parse(String description) {
|
||||||
log.debug "Parse description $description"
|
log.debug "Parse description $description"
|
||||||
def map = [:]
|
List result = []
|
||||||
if (description?.startsWith("read attr -")) {
|
def descMap = zigbee.parseDescriptionAsMap(description)
|
||||||
def descMap = parseDescriptionAsMap(description)
|
|
||||||
log.debug "Desc Map: $descMap"
|
log.debug "Desc Map: $descMap"
|
||||||
if (descMap.cluster == "0201" && descMap.attrId == "0000") {
|
List attrData = [[cluster: descMap.cluster ,attrId: descMap.attrId, value: descMap.value]]
|
||||||
|
descMap.additionalAttrs.each {
|
||||||
|
attrData << [cluster: descMap.cluster, attrId: it.attrId, value: it.value]
|
||||||
|
}
|
||||||
|
attrData.each {
|
||||||
|
def map = [:]
|
||||||
|
if (it.cluster == "0201" && it.attrId == "0000") {
|
||||||
log.debug "TEMP"
|
log.debug "TEMP"
|
||||||
map.name = "temperature"
|
map.name = "temperature"
|
||||||
map.value = getTemperature(descMap.value)
|
map.value = getTemperature(it.value)
|
||||||
} else if (descMap.cluster == "0201" && descMap.attrId == "0011") {
|
map.unit = temperatureScale
|
||||||
|
} else if (it.cluster == "0201" && it.attrId == "0011") {
|
||||||
log.debug "COOLING SETPOINT"
|
log.debug "COOLING SETPOINT"
|
||||||
map.name = "coolingSetpoint"
|
map.name = "coolingSetpoint"
|
||||||
map.value = getTemperature(descMap.value)
|
map.value = getTemperature(it.value)
|
||||||
} else if (descMap.cluster == "0201" && descMap.attrId == "0012") {
|
map.unit = temperatureScale
|
||||||
|
} else if (it.cluster == "0201" && it.attrId == "0012") {
|
||||||
log.debug "HEATING SETPOINT"
|
log.debug "HEATING SETPOINT"
|
||||||
map.name = "heatingSetpoint"
|
map.name = "heatingSetpoint"
|
||||||
map.value = getTemperature(descMap.value)
|
map.value = getTemperature(it.value)
|
||||||
} else if (descMap.cluster == "0201" && descMap.attrId == "001c") {
|
map.unit = temperatureScale
|
||||||
|
} else if (it.cluster == "0201" && it.attrId == "001c") {
|
||||||
log.debug "MODE"
|
log.debug "MODE"
|
||||||
map.name = "thermostatMode"
|
map.name = "thermostatMode"
|
||||||
map.value = getModeMap()[descMap.value]
|
map.value = getModeMap()[it.value]
|
||||||
} else if (descMap.cluster == "0202" && descMap.attrId == "0000") {
|
} else if (it.cluster == "0202" && it.attrId == "0000") {
|
||||||
log.debug "FAN MODE"
|
log.debug "FAN MODE"
|
||||||
map.name = "thermostatFanMode"
|
map.name = "thermostatFanMode"
|
||||||
map.value = getFanModeMap()[descMap.value]
|
map.value = getFanModeMap()[it.value]
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
def result = null
|
|
||||||
if (map) {
|
if (map) {
|
||||||
result = createEvent(map)
|
result << createEvent(map)
|
||||||
}
|
}
|
||||||
log.debug "Parse returned $map"
|
log.debug "Parse returned $map"
|
||||||
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
def parseDescriptionAsMap(description) {
|
|
||||||
(description - "read attr - ").split(",").inject([:]) { map, param ->
|
|
||||||
def nameAndValue = param.split(":")
|
|
||||||
map += [(nameAndValue[0].trim()):nameAndValue[1].trim()]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def getModeMap() { [
|
def getModeMap() { [
|
||||||
"00":"off",
|
"00":"off",
|
||||||
"03":"cool",
|
"03":"cool",
|
||||||
@@ -169,7 +168,7 @@ def setHeatingSetpoint(degrees) {
|
|||||||
|
|
||||||
def degreesInteger = Math.round(degrees)
|
def degreesInteger = Math.round(degrees)
|
||||||
log.debug "setHeatingSetpoint({$degreesInteger} ${temperatureScale})"
|
log.debug "setHeatingSetpoint({$degreesInteger} ${temperatureScale})"
|
||||||
sendEvent("name": "heatingSetpoint", "value": degreesInteger)
|
sendEvent("name": "heatingSetpoint", "value": degreesInteger, "unit": temperatureScale)
|
||||||
|
|
||||||
def celsius = (getTemperatureScale() == "C") ? degreesInteger : (fahrenheitToCelsius(degreesInteger) as Double).round(2)
|
def celsius = (getTemperatureScale() == "C") ? degreesInteger : (fahrenheitToCelsius(degreesInteger) as Double).round(2)
|
||||||
"st wattr 0x${device.deviceNetworkId} 1 0x201 0x12 0x29 {" + hex(celsius * 100) + "}"
|
"st wattr 0x${device.deviceNetworkId} 1 0x201 0x12 0x29 {" + hex(celsius * 100) + "}"
|
||||||
@@ -180,7 +179,7 @@ def setCoolingSetpoint(degrees) {
|
|||||||
if (degrees != null) {
|
if (degrees != null) {
|
||||||
def degreesInteger = Math.round(degrees)
|
def degreesInteger = Math.round(degrees)
|
||||||
log.debug "setCoolingSetpoint({$degreesInteger} ${temperatureScale})"
|
log.debug "setCoolingSetpoint({$degreesInteger} ${temperatureScale})"
|
||||||
sendEvent("name": "coolingSetpoint", "value": degreesInteger)
|
sendEvent("name": "coolingSetpoint", "value": degreesInteger, "unit": temperatureScale)
|
||||||
def celsius = (getTemperatureScale() == "C") ? degreesInteger : (fahrenheitToCelsius(degreesInteger) as Double).round(2)
|
def celsius = (getTemperatureScale() == "C") ? degreesInteger : (fahrenheitToCelsius(degreesInteger) as Double).round(2)
|
||||||
"st wattr 0x${device.deviceNetworkId} 1 0x201 0x11 0x29 {" + hex(celsius * 100) + "}"
|
"st wattr 0x${device.deviceNetworkId} 1 0x201 0x11 0x29 {" + hex(celsius * 100) + "}"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ metadata {
|
|||||||
tiles {
|
tiles {
|
||||||
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
|
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
|
||||||
state "off", label: '${name}', action: "switch.on", icon: "st.Home.home30", backgroundColor: "#ffffff"
|
state "off", label: '${name}', action: "switch.on", icon: "st.Home.home30", backgroundColor: "#ffffff"
|
||||||
state "on", label: '${name}', action: "switch.off", icon: "st.Home.home30", backgroundColor: "#79b821"
|
state "on", label: '${name}', action: "switch.off", icon: "st.Home.home30", backgroundColor: "#00a0dc"
|
||||||
}
|
}
|
||||||
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat") {
|
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat") {
|
||||||
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
|
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
|
||||||
@@ -182,3 +182,16 @@ def updateState(String name, String value) {
|
|||||||
state[name] = value
|
state[name] = value
|
||||||
device.updateDataValue(name, value)
|
device.updateDataValue(name, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def installed() {
|
||||||
|
initialize()
|
||||||
|
}
|
||||||
|
|
||||||
|
def updated() {
|
||||||
|
initialize()
|
||||||
|
}
|
||||||
|
|
||||||
|
def initialize() {
|
||||||
|
sendEvent(name: "numberOfButtons", value: 3)
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
.st-ignore
|
||||||
|
README.md
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
# Connected Cree LED Bulb
|
||||||
|
|
||||||
|
Cloud Execution
|
||||||
|
|
||||||
|
Works with:
|
||||||
|
|
||||||
|
* [Connected Cree LED Bulb](https://support.smartthings.com/hc/en-us/articles/204258280-Cree-Connected-LED-Bulb)
|
||||||
|
|
||||||
|
## Table of contents
|
||||||
|
|
||||||
|
* [Capabilities](#capabilities)
|
||||||
|
* [Health](#device-health)
|
||||||
|
|
||||||
|
## Capabilities
|
||||||
|
|
||||||
|
* **Actuator** - represents that a Device has commands
|
||||||
|
* **Configuration** - _configure()_ command called when device is installed or device preferences updated
|
||||||
|
* **Polling** - represents that poll() can be implemented for the device
|
||||||
|
* **Refresh** - _refresh()_ command for status updates
|
||||||
|
* **Switch** - can detect state (possible values: on/off)
|
||||||
|
* **Switch Level** - represents current light level, usually 0-100 in percent
|
||||||
|
* **Health Check** - indicates ability to get device health notifications
|
||||||
|
|
||||||
|
## Device Health
|
||||||
|
|
||||||
|
Connected Cree LED Bulb with cloud polling it every __5min__
|
||||||
|
SmartThings platform will ping the device after `checkInterval` seconds of inactivity in last attempt to reach the device before marking it `OFFLINE`
|
||||||
|
|
||||||
|
* __12min__ checkInterval
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the device is out of range.
|
||||||
|
Pairing needs to be tried again by placing the device closer to the hub.
|
||||||
|
Instructions related to pairing, resetting and removing the device from SmartThings can be found in the following link:
|
||||||
|
* [Cree Connected LED Bulb Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/204258280-Cree-Connected-LED-Bulb)
|
||||||
@@ -15,13 +15,15 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
metadata {
|
metadata {
|
||||||
definition (name: "Cree Bulb", namespace: "smartthings", author: "SmartThings") {
|
definition (name: "Cree Bulb", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.light") {
|
||||||
|
|
||||||
capability "Actuator"
|
capability "Actuator"
|
||||||
capability "Configuration"
|
capability "Configuration"
|
||||||
capability "Refresh"
|
capability "Refresh"
|
||||||
capability "Switch"
|
capability "Switch"
|
||||||
capability "Switch Level"
|
capability "Switch Level"
|
||||||
|
capability "Health Check"
|
||||||
|
capability "Light"
|
||||||
|
|
||||||
fingerprint profileId: "C05E", inClusters: "0000,0003,0004,0005,0006,0008,1000", outClusters: "0000,0019"
|
fingerprint profileId: "C05E", inClusters: "0000,0003,0004,0005,0006,0008,1000", outClusters: "0000,0019"
|
||||||
}
|
}
|
||||||
@@ -41,9 +43,9 @@ metadata {
|
|||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
||||||
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
||||||
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#79b821", nextState:"turningOff"
|
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#00A0DC", nextState:"turningOff"
|
||||||
attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#79b821", nextState:"turningOff"
|
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#00A0DC", nextState:"turningOff"
|
||||||
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
}
|
}
|
||||||
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
|
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
|
||||||
@@ -81,14 +83,30 @@ def on() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def setLevel(value) {
|
def setLevel(value) {
|
||||||
zigbee.setLevel(value) + ["delay 500"] + zigbee.levelRefresh() //adding refresh because of ZLL bulb not conforming to send-me-a-report
|
zigbee.setLevel(value) + zigbee.onOffRefresh() + zigbee.levelRefresh() //adding refresh because of ZLL bulb not conforming to send-me-a-report
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PING is used by Device-Watch in attempt to reach the Device
|
||||||
|
* */
|
||||||
|
def ping() {
|
||||||
|
return zigbee.levelRefresh()
|
||||||
}
|
}
|
||||||
|
|
||||||
def refresh() {
|
def refresh() {
|
||||||
zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.onOffConfig() + zigbee.levelConfig()
|
zigbee.onOffRefresh() + zigbee.levelRefresh()
|
||||||
|
}
|
||||||
|
|
||||||
|
def healthPoll() {
|
||||||
|
log.debug "healthPoll()"
|
||||||
|
def cmds = zigbee.onOffRefresh() + zigbee.levelRefresh()
|
||||||
|
cmds.each{ sendHubCommand(new physicalgraph.device.HubAction(it))}
|
||||||
}
|
}
|
||||||
|
|
||||||
def configure() {
|
def configure() {
|
||||||
log.debug "Configuring Reporting and Bindings."
|
unschedule()
|
||||||
zigbee.onOffConfig() + zigbee.levelConfig() + zigbee.onOffRefresh() + zigbee.levelRefresh()
|
runEvery5Minutes("healthPoll")
|
||||||
|
// Device-Watch allows 2 check-in misses from device + ping
|
||||||
|
sendEvent(name: "checkInterval", value: 60 * 12, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
|
||||||
|
zigbee.onOffRefresh() + zigbee.levelRefresh()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,13 +81,13 @@ metadata {
|
|||||||
state "fanCirculate", label:'${name}', action:"switchFanMode"
|
state "fanCirculate", label:'${name}', action:"switchFanMode"
|
||||||
}
|
}
|
||||||
controlTile("heatSliderControl", "device.heatingSetpoint", "slider", height: 1, width: 2, inactiveLabel: false) {
|
controlTile("heatSliderControl", "device.heatingSetpoint", "slider", height: 1, width: 2, inactiveLabel: false) {
|
||||||
state "setHeatingSetpoint", action:"quickSetHeat", backgroundColor:"#d04e00"
|
state "setHeatingSetpoint", action:"quickSetHeat", backgroundColor:"#e86d13"
|
||||||
}
|
}
|
||||||
valueTile("heatingSetpoint", "device.heatingSetpoint", inactiveLabel: false, decoration: "flat") {
|
valueTile("heatingSetpoint", "device.heatingSetpoint", inactiveLabel: false, decoration: "flat") {
|
||||||
state "heat", label:'${currentValue}° heat', backgroundColor:"#ffffff"
|
state "heat", label:'${currentValue}° heat', backgroundColor:"#ffffff"
|
||||||
}
|
}
|
||||||
controlTile("coolSliderControl", "device.coolingSetpoint", "slider", height: 1, width: 2, inactiveLabel: false) {
|
controlTile("coolSliderControl", "device.coolingSetpoint", "slider", height: 1, width: 2, inactiveLabel: false) {
|
||||||
state "setCoolingSetpoint", action:"quickSetCool", backgroundColor: "#1e9cbb"
|
state "setCoolingSetpoint", action:"quickSetCool", backgroundColor: "#00a0dc"
|
||||||
}
|
}
|
||||||
valueTile("coolingSetpoint", "device.coolingSetpoint", inactiveLabel: false, decoration: "flat") {
|
valueTile("coolingSetpoint", "device.coolingSetpoint", inactiveLabel: false, decoration: "flat") {
|
||||||
state "cool", label:'${currentValue}° cool', backgroundColor:"#ffffff"
|
state "cool", label:'${currentValue}° cool', backgroundColor:"#ffffff"
|
||||||
|
|||||||
@@ -33,10 +33,10 @@ metadata {
|
|||||||
|
|
||||||
tiles {
|
tiles {
|
||||||
standardTile("toggle", "device.lock", width: 2, height: 2) {
|
standardTile("toggle", "device.lock", width: 2, height: 2) {
|
||||||
state "locked", label:'locked', action:"lock.unlock", icon:"st.locks.lock.locked", backgroundColor:"#79b821", nextState:"unlocking"
|
state "locked", label:'locked', action:"lock.unlock", icon:"st.locks.lock.locked", backgroundColor:"#00a0dc", nextState:"unlocking"
|
||||||
state "unlocked", label:'unlocked', action:"lock.lock", icon:"st.locks.lock.unlocked", backgroundColor:"#ffffff", nextState:"locking"
|
state "unlocked", label:'unlocked', action:"lock.lock", icon:"st.locks.lock.unlocked", backgroundColor:"#ffffff", nextState:"locking"
|
||||||
state "unknown", label:"unknown", action:"lock.lock", icon:"st.locks.lock.unknown", backgroundColor:"#ffffff", nextState:"locking"
|
state "unknown", label:"unknown", action:"lock.lock", icon:"st.locks.lock.unknown", backgroundColor:"#ffffff", nextState:"locking"
|
||||||
state "locking", label:'locking', icon:"st.locks.lock.locked", backgroundColor:"#79b821"
|
state "locking", label:'locking', icon:"st.locks.lock.locked", backgroundColor:"#00a0dc"
|
||||||
state "unlocking", label:'unlocking', icon:"st.locks.lock.unlocked", backgroundColor:"#ffffff"
|
state "unlocking", label:'unlocking', icon:"st.locks.lock.unlocked", backgroundColor:"#ffffff"
|
||||||
}
|
}
|
||||||
standardTile("lock", "device.lock", inactiveLabel: false, decoration: "flat") {
|
standardTile("lock", "device.lock", inactiveLabel: false, decoration: "flat") {
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
.st-ignore
|
||||||
|
README.md
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
# Z-wave Dimmer Switch
|
||||||
|
|
||||||
|
Local Execution on V2 Hubs
|
||||||
|
|
||||||
|
Works with:
|
||||||
|
|
||||||
|
* [GE Z-Wave In-Wall Smart Dimmer (GE 12724)](http://products.z-wavealliance.org/products/1197)
|
||||||
|
* [GE Z-Wave In-Wall Smart Dimmer (Toggle) (GE 12729)](http://products.z-wavealliance.org/products/1201)
|
||||||
|
* [GE Z-Wave Plug-in Smart Dimmer (GE 12718)](http://products.z-wavealliance.org/products/1191)
|
||||||
|
* [GE 1,000-Watt In-Wall Smart Dimmer Switch (GE 12725)](http://products.z-wavealliance.org/products/1198)
|
||||||
|
* [GE In-Wall Smart Fan Control (GE 12730)](http://products.z-wavealliance.org/products/1202)
|
||||||
|
|
||||||
|
## Table of contents
|
||||||
|
|
||||||
|
* [Capabilities](#capabilities)
|
||||||
|
* [Health](#device-health)
|
||||||
|
* [Troubleshooting](#Troubleshooting)
|
||||||
|
|
||||||
|
## Capabilities
|
||||||
|
|
||||||
|
* **Switch Level** - it's defined to accept two parameters, the level and the rate of dimming
|
||||||
|
* **Actuator** - represents that a Device has commands
|
||||||
|
* **Indicator** - gives you the ability to set the indicator LED light on a Z-Wave switch
|
||||||
|
* **Switch** - can detect state (possible values: on/off)
|
||||||
|
* **Polling** - represents that poll() can be implemented for the device
|
||||||
|
* **Refresh** - _refresh()_ command for status updates
|
||||||
|
* **Sensor** - detects sensor events
|
||||||
|
* **Health Check** - indicates ability to get device health notifications
|
||||||
|
|
||||||
|
## Device Health
|
||||||
|
|
||||||
|
Z-Wave Smart Dimmers (In-Wall, In-Wall(Toggle), Plug-In), 1000-watt In-Wall Smart Dimmer Switch and In-Wall Smart Fan Control are polled by the hub.
|
||||||
|
As of hubCore version 0.14.38 the hub sends up reports every 15 minutes regardless of whether the state changed.
|
||||||
|
Check-in interval = 32 mins.
|
||||||
|
Not to mention after going OFFLINE when the device is plugged back in, it might take a considerable amount of time for
|
||||||
|
the device to appear as ONLINE again. This is because if this listening device does not respond to two poll requests in a row,
|
||||||
|
it is not polled for 5 minutes by the hub. This can delay up the process of being marked ONLINE by quite some time.
|
||||||
|
|
||||||
|
* __32min__ checkInterval
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the device is out of range.
|
||||||
|
Pairing needs to be tried again by placing the device closer to the hub.
|
||||||
|
Instructions related to pairing, resetting and removing the device from SmartThings can be found in the following link:
|
||||||
|
* [General Z-Wave Dimmer/Switch Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/200955890-Troubleshooting-GE-in-wall-switch-or-dimmer-won-t-respond-to-commands-or-automations-Z-Wave-)
|
||||||
|
* [GE Z-Wave In-Wall Smart Dimmer (GE 12724) Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/200902600-GE-In-Wall-Paddle-Dimmer-Switch-GE-12724-Z-Wave-)
|
||||||
|
* [GE Z-Wave In-Wall Smart Dimmer (Toggle) (GE 12729) Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/207568463-GE-In-Wall-Smart-Toggle-Dimmer-GE-12729-Z-Wave-)
|
||||||
|
* [GE Z-Wave Plug-in Smart Dimmer (GE 12718) Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/202088474-GE-Plug-In-Smart-Dimmer-GE-12718-Z-Wave-)
|
||||||
|
* [GE 1,000-Watt In-Wall Smart Dimmer Switch (GE 12725) Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/200879274)
|
||||||
|
* [GE In-Wall Smart Fan Control (GE 12730) Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/200879274)
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
metadata {
|
metadata {
|
||||||
definition (name: "Dimmer Switch", namespace: "smartthings", author: "SmartThings") {
|
definition (name: "Dimmer Switch", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.switch") {
|
||||||
capability "Switch Level"
|
capability "Switch Level"
|
||||||
capability "Actuator"
|
capability "Actuator"
|
||||||
capability "Indicator"
|
capability "Indicator"
|
||||||
@@ -20,8 +20,13 @@ metadata {
|
|||||||
capability "Polling"
|
capability "Polling"
|
||||||
capability "Refresh"
|
capability "Refresh"
|
||||||
capability "Sensor"
|
capability "Sensor"
|
||||||
|
capability "Health Check"
|
||||||
|
capability "Light"
|
||||||
|
|
||||||
fingerprint inClusters: "0x26"
|
fingerprint mfr:"0063", prod:"4457", deviceJoinName: "GE In-Wall Smart Dimmer"
|
||||||
|
fingerprint mfr:"0063", prod:"4944", deviceJoinName: "GE In-Wall Smart Dimmer"
|
||||||
|
fingerprint mfr:"0063", prod:"5044", deviceJoinName: "GE Plug-In Smart Dimmer"
|
||||||
|
fingerprint mfr:"0063", prod:"4944", model:"3034", deviceJoinName: "GE In-Wall Smart Fan Control"
|
||||||
}
|
}
|
||||||
|
|
||||||
simulator {
|
simulator {
|
||||||
@@ -42,12 +47,16 @@ metadata {
|
|||||||
reply "200163,delay 5000,2602": "command: 2603, payload: 63"
|
reply "200163,delay 5000,2602": "command: 2603, payload: 63"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
preferences {
|
||||||
|
input "ledIndicator", "enum", title: "LED Indicator", description: "Turn LED indicator... ", required: false, options:["on": "When On", "off": "When Off", "never": "Never"], defaultValue: "off"
|
||||||
|
}
|
||||||
|
|
||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
||||||
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
||||||
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"turningOff"
|
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#00a0dc", nextState:"turningOff"
|
||||||
attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"turningOff"
|
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#00a0dc", nextState:"turningOff"
|
||||||
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
}
|
}
|
||||||
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
|
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
|
||||||
@@ -70,11 +79,35 @@ metadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
main(["switch"])
|
main(["switch"])
|
||||||
details(["switch", "level", "indicator", "refresh"])
|
details(["switch", "level", "refresh"])
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def installed() {
|
||||||
|
// Device-Watch simply pings if no device events received for 32min(checkInterval)
|
||||||
|
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
|
||||||
|
}
|
||||||
|
|
||||||
|
def updated(){
|
||||||
|
// Device-Watch simply pings if no device events received for 32min(checkInterval)
|
||||||
|
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
|
||||||
|
switch (ledIndicator) {
|
||||||
|
case "on":
|
||||||
|
indicatorWhenOn()
|
||||||
|
break
|
||||||
|
case "off":
|
||||||
|
indicatorWhenOff()
|
||||||
|
break
|
||||||
|
case "never":
|
||||||
|
indicatorNever()
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
indicatorWhenOn()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def parse(String description) {
|
def parse(String description) {
|
||||||
def result = null
|
def result = null
|
||||||
if (description != "updated") {
|
if (description != "updated") {
|
||||||
@@ -138,6 +171,7 @@ def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerS
|
|||||||
log.debug "productTypeId: ${cmd.productTypeId}"
|
log.debug "productTypeId: ${cmd.productTypeId}"
|
||||||
def msr = String.format("%04X-%04X-%04X", cmd.manufacturerId, cmd.productTypeId, cmd.productId)
|
def msr = String.format("%04X-%04X-%04X", cmd.manufacturerId, cmd.productTypeId, cmd.productId)
|
||||||
updateDataValue("MSR", msr)
|
updateDataValue("MSR", msr)
|
||||||
|
updateDataValue("manufacturer", cmd.manufacturerName)
|
||||||
createEvent([descriptionText: "$device.displayName MSR: $msr", isStateChange: false])
|
createEvent([descriptionText: "$device.displayName MSR: $msr", isStateChange: false])
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,6 +225,13 @@ def poll() {
|
|||||||
zwave.switchMultilevelV1.switchMultilevelGet().format()
|
zwave.switchMultilevelV1.switchMultilevelGet().format()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PING is used by Device-Watch in attempt to reach the Device
|
||||||
|
* */
|
||||||
|
def ping() {
|
||||||
|
refresh()
|
||||||
|
}
|
||||||
|
|
||||||
def refresh() {
|
def refresh() {
|
||||||
log.debug "refresh() is called"
|
log.debug "refresh() is called"
|
||||||
def commands = []
|
def commands = []
|
||||||
@@ -201,19 +242,19 @@ def refresh() {
|
|||||||
delayBetween(commands,100)
|
delayBetween(commands,100)
|
||||||
}
|
}
|
||||||
|
|
||||||
def indicatorWhenOn() {
|
void indicatorWhenOn() {
|
||||||
sendEvent(name: "indicatorStatus", value: "when on")
|
sendEvent(name: "indicatorStatus", value: "when on", displayed: false)
|
||||||
zwave.configurationV1.configurationSet(configurationValue: [1], parameterNumber: 3, size: 1).format()
|
sendHubCommand(new physicalgraph.device.HubAction(zwave.configurationV1.configurationSet(configurationValue: [1], parameterNumber: 3, size: 1).format()))
|
||||||
}
|
}
|
||||||
|
|
||||||
def indicatorWhenOff() {
|
void indicatorWhenOff() {
|
||||||
sendEvent(name: "indicatorStatus", value: "when off")
|
sendEvent(name: "indicatorStatus", value: "when off", displayed: false)
|
||||||
zwave.configurationV1.configurationSet(configurationValue: [0], parameterNumber: 3, size: 1).format()
|
sendHubCommand(new physicalgraph.device.HubAction(zwave.configurationV1.configurationSet(configurationValue: [0], parameterNumber: 3, size: 1).format()))
|
||||||
}
|
}
|
||||||
|
|
||||||
def indicatorNever() {
|
void indicatorNever() {
|
||||||
sendEvent(name: "indicatorStatus", value: "never")
|
sendEvent(name: "indicatorStatus", value: "never", displayed: false)
|
||||||
zwave.configurationV1.configurationSet(configurationValue: [2], parameterNumber: 3, size: 1).format()
|
sendHubCommand(new physicalgraph.device.HubAction(zwave.configurationV1.configurationSet(configurationValue: [2], parameterNumber: 3, size: 1).format()))
|
||||||
}
|
}
|
||||||
|
|
||||||
def invertSwitch(invert=true) {
|
def invertSwitch(invert=true) {
|
||||||
|
|||||||
@@ -47,8 +47,8 @@ metadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
standardTile("motion", "device.motion") {
|
standardTile("motion", "device.motion") {
|
||||||
state("inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#ffffff")
|
state("inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#cccccc")
|
||||||
state("active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#53a7c0")
|
state("active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#00A0DC")
|
||||||
}
|
}
|
||||||
|
|
||||||
standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat") {
|
standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat") {
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ metadata {
|
|||||||
capability "Sensor"
|
capability "Sensor"
|
||||||
capability "Refresh"
|
capability "Refresh"
|
||||||
capability "Relative Humidity Measurement"
|
capability "Relative Humidity Measurement"
|
||||||
|
capability "Health Check"
|
||||||
|
|
||||||
command "generateEvent"
|
command "generateEvent"
|
||||||
command "raiseSetpoint"
|
command "raiseSetpoint"
|
||||||
@@ -31,18 +32,19 @@ metadata {
|
|||||||
command "switchMode"
|
command "switchMode"
|
||||||
command "switchFanMode"
|
command "switchFanMode"
|
||||||
|
|
||||||
attribute "thermostatSetpoint","number"
|
attribute "displayThermostatSetpoint", "string" // Added to be able to show "Auto"/"Off" keeping attribute thermostatSetpoint a number
|
||||||
attribute "thermostatStatus", "string"
|
attribute "thermostatStatus", "string"
|
||||||
attribute "maxHeatingSetpoint", "number"
|
attribute "maxHeatingSetpoint", "number"
|
||||||
attribute "minHeatingSetpoint", "number"
|
attribute "minHeatingSetpoint", "number"
|
||||||
attribute "maxCoolingSetpoint", "number"
|
attribute "maxCoolingSetpoint", "number"
|
||||||
attribute "minCoolingSetpoint", "number"
|
attribute "minCoolingSetpoint", "number"
|
||||||
attribute "deviceTemperatureUnit", "number"
|
attribute "deviceTemperatureUnit", "string"
|
||||||
|
attribute "deviceAlive", "enum", ["true", "false"]
|
||||||
}
|
}
|
||||||
|
|
||||||
tiles {
|
tiles {
|
||||||
valueTile("temperature", "device.temperature", width: 2, height: 2) {
|
standardTile("temperature", "device.temperature", width: 2, height: 2, decoration: "flat") {
|
||||||
state("temperature", label:'${currentValue}°', unit:"F",
|
state("temperature", label:'${currentValue}°', unit:"F", icon: "st.thermostat.ac.air-conditioning",
|
||||||
backgroundColors:[
|
backgroundColors:[
|
||||||
// Celsius
|
// Celsius
|
||||||
[value: 0, color: "#153591"],
|
[value: 0, color: "#153591"],
|
||||||
@@ -68,7 +70,7 @@ metadata {
|
|||||||
state "heat", action:"switchMode", nextState: "updating", icon: "st.thermostat.heat"
|
state "heat", action:"switchMode", nextState: "updating", icon: "st.thermostat.heat"
|
||||||
state "cool", action:"switchMode", nextState: "updating", icon: "st.thermostat.cool"
|
state "cool", action:"switchMode", nextState: "updating", icon: "st.thermostat.cool"
|
||||||
state "auto", action:"switchMode", nextState: "updating", icon: "st.thermostat.auto"
|
state "auto", action:"switchMode", nextState: "updating", icon: "st.thermostat.auto"
|
||||||
state "auxHeatOnly", action:"switchMode", icon: "st.thermostat.emergency-heat"
|
state "emergency heat", action:"switchMode", icon: "st.thermostat.emergency-heat" // emergency heat = auxHeatOnly
|
||||||
state "updating", label:"Working", icon: "st.secondary.secondary"
|
state "updating", label:"Working", icon: "st.secondary.secondary"
|
||||||
}
|
}
|
||||||
standardTile("fanMode", "device.thermostatFanMode", inactiveLabel: false, decoration: "flat") {
|
standardTile("fanMode", "device.thermostatFanMode", inactiveLabel: false, decoration: "flat") {
|
||||||
@@ -79,8 +81,8 @@ metadata {
|
|||||||
standardTile("upButtonControl", "device.thermostatSetpoint", inactiveLabel: false, decoration: "flat") {
|
standardTile("upButtonControl", "device.thermostatSetpoint", inactiveLabel: false, decoration: "flat") {
|
||||||
state "setpoint", action:"raiseSetpoint", icon:"st.thermostat.thermostat-up"
|
state "setpoint", action:"raiseSetpoint", icon:"st.thermostat.thermostat-up"
|
||||||
}
|
}
|
||||||
valueTile("thermostatSetpoint", "device.thermostatSetpoint", width: 1, height: 1, decoration: "flat") {
|
valueTile("displayThermostatSetpoint", "device.displayThermostatSetpoint", width: 1, height: 1, decoration: "flat") {
|
||||||
state "thermostatSetpoint", label:'${currentValue}'
|
state "displayThermostatSetpoint", label:'${currentValue}'
|
||||||
}
|
}
|
||||||
valueTile("currentStatus", "device.thermostatStatus", height: 1, width: 2, decoration: "flat") {
|
valueTile("currentStatus", "device.thermostatStatus", height: 1, width: 2, decoration: "flat") {
|
||||||
state "thermostatStatus", label:'${currentValue}', backgroundColor:"#ffffff"
|
state "thermostatStatus", label:'${currentValue}', backgroundColor:"#ffffff"
|
||||||
@@ -111,7 +113,7 @@ metadata {
|
|||||||
state "humidity", label:'${currentValue}%'
|
state "humidity", label:'${currentValue}%'
|
||||||
}
|
}
|
||||||
main "temperature"
|
main "temperature"
|
||||||
details(["temperature", "upButtonControl", "thermostatSetpoint", "currentStatus", "downButtonControl", "mode", "fanMode","humidity", "resumeProgram", "refresh"])
|
details(["temperature", "upButtonControl", "displayThermostatSetpoint", "currentStatus", "downButtonControl", "mode", "fanMode","humidity", "resumeProgram", "refresh"])
|
||||||
}
|
}
|
||||||
|
|
||||||
preferences {
|
preferences {
|
||||||
@@ -120,6 +122,21 @@ metadata {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void installed() {
|
||||||
|
// The device refreshes every 5 minutes by default so if we miss 2 refreshes we can consider it offline
|
||||||
|
// Using 12 minutes because in testing, device health team found that there could be "jitter"
|
||||||
|
sendEvent(name: "checkInterval", value: 60 * 12, data: [protocol: "cloud"], displayed: false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Device Watch will ping the device to proactively determine if the device has gone offline
|
||||||
|
// If the device was online the last time we refreshed, trigger another refresh as part of the ping.
|
||||||
|
def ping() {
|
||||||
|
def isAlive = device.currentValue("deviceAlive") == "true" ? true : false
|
||||||
|
if (isAlive) {
|
||||||
|
refresh()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// parse events into attributes
|
// parse events into attributes
|
||||||
def parse(String description) {
|
def parse(String description) {
|
||||||
log.debug "Parsing '${description}'"
|
log.debug "Parsing '${description}'"
|
||||||
@@ -148,15 +165,13 @@ def generateEvent(Map results) {
|
|||||||
handlerName: name]
|
handlerName: name]
|
||||||
|
|
||||||
if (name=="temperature" || name=="heatingSetpoint" || name=="coolingSetpoint" ) {
|
if (name=="temperature" || name=="heatingSetpoint" || name=="coolingSetpoint" ) {
|
||||||
def sendValue = convertTemperatureIfNeeded(value.toDouble(), "F", 1) //API return temperature value in F
|
def sendValue = location.temperatureScale == "C"? roundC(convertFtoC(value.toDouble())) : value.toInteger()
|
||||||
sendValue = location.temperatureScale == "C"? roundC(sendValue) : sendValue
|
|
||||||
isChange = isTemperatureStateChange(device, name, value.toString())
|
isChange = isTemperatureStateChange(device, name, value.toString())
|
||||||
isDisplayed = isChange
|
isDisplayed = isChange
|
||||||
event << [value: sendValue, isStateChange: isChange, displayed: isDisplayed]
|
event << [value: sendValue, unit: temperatureScale, isStateChange: isChange, displayed: isDisplayed]
|
||||||
} else if (name=="maxCoolingSetpoint" || name=="minCoolingSetpoint" || name=="maxHeatingSetpoint" || name=="minHeatingSetpoint") {
|
} else if (name=="maxCoolingSetpoint" || name=="minCoolingSetpoint" || name=="maxHeatingSetpoint" || name=="minHeatingSetpoint") {
|
||||||
def sendValue = convertTemperatureIfNeeded(value.toDouble(), "F", 1) //API return temperature value in F
|
def sendValue = location.temperatureScale == "C"? roundC(convertFtoC(value.toDouble())) : value.toInteger()
|
||||||
sendValue = location.temperatureScale == "C"? roundC(sendValue) : sendValue
|
event << [value: sendValue, unit: temperatureScale, displayed: false]
|
||||||
event << [value: sendValue, displayed: false]
|
|
||||||
} else if (name=="heatMode" || name=="coolMode" || name=="autoMode" || name=="auxHeatMode"){
|
} else if (name=="heatMode" || name=="coolMode" || name=="autoMode" || name=="auxHeatMode"){
|
||||||
isChange = isStateChange(device, name, value.toString())
|
isChange = isStateChange(device, name, value.toString())
|
||||||
event << [value: value.toString(), isStateChange: isChange, displayed: false]
|
event << [value: value.toString(), isStateChange: isChange, displayed: false]
|
||||||
@@ -166,6 +181,15 @@ def generateEvent(Map results) {
|
|||||||
} else if (name=="humidity") {
|
} else if (name=="humidity") {
|
||||||
isChange = isStateChange(device, name, value.toString())
|
isChange = isStateChange(device, name, value.toString())
|
||||||
event << [value: value.toString(), isStateChange: isChange, displayed: false, unit: "%"]
|
event << [value: value.toString(), isStateChange: isChange, displayed: false, unit: "%"]
|
||||||
|
} else if (name == "deviceAlive") {
|
||||||
|
isChange = isStateChange(device, name, value.toString())
|
||||||
|
event['isStateChange'] = isChange
|
||||||
|
event['displayed'] = false
|
||||||
|
} else if (name == "thermostatMode") {
|
||||||
|
def mode = value.toString()
|
||||||
|
mode = (mode == "auxHeatOnly") ? "emergency heat" : mode
|
||||||
|
isChange = isStateChange(device, name, mode)
|
||||||
|
event << [value: mode, isStateChange: isChange, displayed: isDisplayed]
|
||||||
} else {
|
} else {
|
||||||
isChange = isStateChange(device, name, value.toString())
|
isChange = isStateChange(device, name, value.toString())
|
||||||
isDisplayed = isChange
|
isDisplayed = isChange
|
||||||
@@ -234,9 +258,9 @@ void setHeatingSetpoint(setpoint) {
|
|||||||
def heatingValue = location.temperatureScale == "C"? convertCtoF(heatingSetpoint) : heatingSetpoint
|
def heatingValue = location.temperatureScale == "C"? convertCtoF(heatingSetpoint) : heatingSetpoint
|
||||||
|
|
||||||
def sendHoldType = holdType ? (holdType=="Temporary")? "nextTransition" : (holdType=="Permanent")? "indefinite" : "indefinite" : "indefinite"
|
def sendHoldType = holdType ? (holdType=="Temporary")? "nextTransition" : (holdType=="Permanent")? "indefinite" : "indefinite" : "indefinite"
|
||||||
if (parent.setHold(this, heatingValue, coolingValue, deviceId, sendHoldType)) {
|
if (parent.setHold(heatingValue, coolingValue, deviceId, sendHoldType)) {
|
||||||
sendEvent("name":"heatingSetpoint", "value":heatingSetpoint)
|
sendEvent("name":"heatingSetpoint", "value":heatingSetpoint, "unit":location.temperatureScale)
|
||||||
sendEvent("name":"coolingSetpoint", "value":coolingSetpoint)
|
sendEvent("name":"coolingSetpoint", "value":coolingSetpoint, "unit":location.temperatureScale)
|
||||||
log.debug "Done setHeatingSetpoint> coolingSetpoint: ${coolingSetpoint}, heatingSetpoint: ${heatingSetpoint}"
|
log.debug "Done setHeatingSetpoint> coolingSetpoint: ${coolingSetpoint}, heatingSetpoint: ${heatingSetpoint}"
|
||||||
generateSetpointEvent()
|
generateSetpointEvent()
|
||||||
generateStatusEvent()
|
generateStatusEvent()
|
||||||
@@ -253,7 +277,6 @@ void setCoolingSetpoint(setpoint) {
|
|||||||
def maxCoolingSetpoint = device.currentValue("maxCoolingSetpoint")
|
def maxCoolingSetpoint = device.currentValue("maxCoolingSetpoint")
|
||||||
def minCoolingSetpoint = device.currentValue("minCoolingSetpoint")
|
def minCoolingSetpoint = device.currentValue("minCoolingSetpoint")
|
||||||
|
|
||||||
|
|
||||||
if (coolingSetpoint > maxCoolingSetpoint) {
|
if (coolingSetpoint > maxCoolingSetpoint) {
|
||||||
coolingSetpoint = maxCoolingSetpoint
|
coolingSetpoint = maxCoolingSetpoint
|
||||||
} else if (coolingSetpoint < minCoolingSetpoint) {
|
} else if (coolingSetpoint < minCoolingSetpoint) {
|
||||||
@@ -271,9 +294,9 @@ void setCoolingSetpoint(setpoint) {
|
|||||||
def heatingValue = location.temperatureScale == "C"? convertCtoF(heatingSetpoint) : heatingSetpoint
|
def heatingValue = location.temperatureScale == "C"? convertCtoF(heatingSetpoint) : heatingSetpoint
|
||||||
|
|
||||||
def sendHoldType = holdType ? (holdType=="Temporary")? "nextTransition" : (holdType=="Permanent")? "indefinite" : "indefinite" : "indefinite"
|
def sendHoldType = holdType ? (holdType=="Temporary")? "nextTransition" : (holdType=="Permanent")? "indefinite" : "indefinite" : "indefinite"
|
||||||
if (parent.setHold(this, heatingValue, coolingValue, deviceId, sendHoldType)) {
|
if (parent.setHold(heatingValue, coolingValue, deviceId, sendHoldType)) {
|
||||||
sendEvent("name":"heatingSetpoint", "value":heatingSetpoint)
|
sendEvent("name":"heatingSetpoint", "value":heatingSetpoint, "unit":location.temperatureScale)
|
||||||
sendEvent("name":"coolingSetpoint", "value":coolingSetpoint)
|
sendEvent("name":"coolingSetpoint", "value":coolingSetpoint, "unit":location.temperatureScale)
|
||||||
log.debug "Done setCoolingSetpoint>> coolingSetpoint = ${coolingSetpoint}, heatingSetpoint = ${heatingSetpoint}"
|
log.debug "Done setCoolingSetpoint>> coolingSetpoint = ${coolingSetpoint}, heatingSetpoint = ${heatingSetpoint}"
|
||||||
generateSetpointEvent()
|
generateSetpointEvent()
|
||||||
generateStatusEvent()
|
generateStatusEvent()
|
||||||
@@ -283,18 +306,17 @@ void setCoolingSetpoint(setpoint) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void resumeProgram() {
|
void resumeProgram() {
|
||||||
|
|
||||||
log.debug "resumeProgram() is called"
|
log.debug "resumeProgram() is called"
|
||||||
sendEvent("name":"thermostatStatus", "value":"resuming schedule", "description":statusText, displayed: false)
|
sendEvent("name":"thermostatStatus", "value":"resuming schedule", "description":statusText, displayed: false)
|
||||||
def deviceId = device.deviceNetworkId.split(/\./).last()
|
def deviceId = device.deviceNetworkId.split(/\./).last()
|
||||||
if (parent.resumeProgram(this, deviceId)) {
|
if (parent.resumeProgram(deviceId)) {
|
||||||
sendEvent("name":"thermostatStatus", "value":"setpoint is updating", "description":statusText, displayed: false)
|
sendEvent("name":"thermostatStatus", "value":"setpoint is updating", "description":statusText, displayed: false)
|
||||||
runIn(5, "poll")
|
runIn(5, "poll")
|
||||||
log.debug "resumeProgram() is done"
|
log.debug "resumeProgram() is done"
|
||||||
sendEvent("name":"resumeProgram", "value":"resume", descriptionText: "resumeProgram is done", displayed: false, isStateChange: true)
|
sendEvent("name":"resumeProgram", "value":"resume", descriptionText: "resumeProgram is done", displayed: false, isStateChange: true)
|
||||||
} else {
|
} else {
|
||||||
sendEvent("name":"thermostatStatus", "value":"failed resume click refresh", "description":statusText, displayed: false)
|
sendEvent("name":"thermostatStatus", "value":"failed resume click refresh", "description":statusText, displayed: false)
|
||||||
log.error "Error resumeProgram() check parent.resumeProgram(this, deviceId)"
|
log.error "Error resumeProgram() check parent.resumeProgram(deviceId)"
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -354,7 +376,6 @@ def switchFanMode() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def switchToFanMode(nextMode) {
|
def switchToFanMode(nextMode) {
|
||||||
|
|
||||||
log.debug "switching to fan mode: $nextMode"
|
log.debug "switching to fan mode: $nextMode"
|
||||||
def returnCommand
|
def returnCommand
|
||||||
|
|
||||||
@@ -406,7 +427,7 @@ def generateOperatingStateEvent(operatingState) {
|
|||||||
def off() {
|
def off() {
|
||||||
log.debug "off"
|
log.debug "off"
|
||||||
def deviceId = device.deviceNetworkId.split(/\./).last()
|
def deviceId = device.deviceNetworkId.split(/\./).last()
|
||||||
if (parent.setMode (this,"off", deviceId))
|
if (parent.setMode ("off", deviceId))
|
||||||
generateModeEvent("off")
|
generateModeEvent("off")
|
||||||
else {
|
else {
|
||||||
log.debug "Error setting new mode."
|
log.debug "Error setting new mode."
|
||||||
@@ -420,7 +441,7 @@ def off() {
|
|||||||
def heat() {
|
def heat() {
|
||||||
log.debug "heat"
|
log.debug "heat"
|
||||||
def deviceId = device.deviceNetworkId.split(/\./).last()
|
def deviceId = device.deviceNetworkId.split(/\./).last()
|
||||||
if (parent.setMode (this,"heat", deviceId))
|
if (parent.setMode ("heat", deviceId))
|
||||||
generateModeEvent("heat")
|
generateModeEvent("heat")
|
||||||
else {
|
else {
|
||||||
log.debug "Error setting new mode."
|
log.debug "Error setting new mode."
|
||||||
@@ -436,10 +457,10 @@ def emergencyHeat() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def auxHeatOnly() {
|
def auxHeatOnly() {
|
||||||
log.debug "auxHeatOnly"
|
log.debug "auxHeatOnly = emergency heat"
|
||||||
def deviceId = device.deviceNetworkId.split(/\./).last()
|
def deviceId = device.deviceNetworkId.split(/\./).last()
|
||||||
if (parent.setMode (this,"auxHeatOnly", deviceId))
|
if (parent.setMode ("auxHeatOnly", deviceId))
|
||||||
generateModeEvent("auxHeatOnly")
|
generateModeEvent("emergency heat") // emergency heat = auxHeatOnly
|
||||||
else {
|
else {
|
||||||
log.debug "Error setting new mode."
|
log.debug "Error setting new mode."
|
||||||
def currentMode = device.currentState("thermostatMode")?.value
|
def currentMode = device.currentState("thermostatMode")?.value
|
||||||
@@ -452,7 +473,7 @@ def auxHeatOnly() {
|
|||||||
def cool() {
|
def cool() {
|
||||||
log.debug "cool"
|
log.debug "cool"
|
||||||
def deviceId = device.deviceNetworkId.split(/\./).last()
|
def deviceId = device.deviceNetworkId.split(/\./).last()
|
||||||
if (parent.setMode (this,"cool", deviceId))
|
if (parent.setMode ("cool", deviceId))
|
||||||
generateModeEvent("cool")
|
generateModeEvent("cool")
|
||||||
else {
|
else {
|
||||||
log.debug "Error setting new mode."
|
log.debug "Error setting new mode."
|
||||||
@@ -466,7 +487,7 @@ def cool() {
|
|||||||
def auto() {
|
def auto() {
|
||||||
log.debug "auto"
|
log.debug "auto"
|
||||||
def deviceId = device.deviceNetworkId.split(/\./).last()
|
def deviceId = device.deviceNetworkId.split(/\./).last()
|
||||||
if (parent.setMode (this,"auto", deviceId))
|
if (parent.setMode ("auto", deviceId))
|
||||||
generateModeEvent("auto")
|
generateModeEvent("auto")
|
||||||
else {
|
else {
|
||||||
log.debug "Error setting new mode."
|
log.debug "Error setting new mode."
|
||||||
@@ -489,7 +510,7 @@ def fanOn() {
|
|||||||
def coolingValue = location.temperatureScale == "C"? convertCtoF(coolingSetpoint) : coolingSetpoint
|
def coolingValue = location.temperatureScale == "C"? convertCtoF(coolingSetpoint) : coolingSetpoint
|
||||||
def heatingValue = location.temperatureScale == "C"? convertCtoF(heatingSetpoint) : heatingSetpoint
|
def heatingValue = location.temperatureScale == "C"? convertCtoF(heatingSetpoint) : heatingSetpoint
|
||||||
|
|
||||||
if (parent.setFanMode(this, heatingValue, coolingValue, deviceId, sendHoldType, fanMode)) {
|
if (parent.setFanMode(heatingValue, coolingValue, deviceId, sendHoldType, fanMode)) {
|
||||||
generateFanModeEvent(fanMode)
|
generateFanModeEvent(fanMode)
|
||||||
} else {
|
} else {
|
||||||
log.debug "Error setting new mode."
|
log.debug "Error setting new mode."
|
||||||
@@ -510,7 +531,7 @@ def fanAuto() {
|
|||||||
def coolingValue = location.temperatureScale == "C"? convertCtoF(coolingSetpoint) : coolingSetpoint
|
def coolingValue = location.temperatureScale == "C"? convertCtoF(coolingSetpoint) : coolingSetpoint
|
||||||
def heatingValue = location.temperatureScale == "C"? convertCtoF(heatingSetpoint) : heatingSetpoint
|
def heatingValue = location.temperatureScale == "C"? convertCtoF(heatingSetpoint) : heatingSetpoint
|
||||||
|
|
||||||
if (parent.setFanMode(this, heatingValue, coolingValue, deviceId, sendHoldType, fanMode)) {
|
if (parent.setFanMode(heatingValue, coolingValue, deviceId, sendHoldType, fanMode)) {
|
||||||
generateFanModeEvent(fanMode)
|
generateFanModeEvent(fanMode)
|
||||||
} else {
|
} else {
|
||||||
log.debug "Error setting new mode."
|
log.debug "Error setting new mode."
|
||||||
@@ -520,63 +541,62 @@ def fanAuto() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def generateSetpointEvent() {
|
def generateSetpointEvent() {
|
||||||
|
|
||||||
log.debug "Generate SetPoint Event"
|
log.debug "Generate SetPoint Event"
|
||||||
|
|
||||||
def mode = device.currentValue("thermostatMode")
|
def mode = device.currentValue("thermostatMode")
|
||||||
log.debug "Current Mode = ${mode}"
|
|
||||||
|
|
||||||
def heatingSetpoint = device.currentValue("heatingSetpoint")
|
def heatingSetpoint = device.currentValue("heatingSetpoint")
|
||||||
log.debug "Heating Setpoint = ${heatingSetpoint}"
|
|
||||||
|
|
||||||
def coolingSetpoint = device.currentValue("coolingSetpoint")
|
def coolingSetpoint = device.currentValue("coolingSetpoint")
|
||||||
log.debug "Cooling Setpoint = ${coolingSetpoint}"
|
|
||||||
|
|
||||||
def maxHeatingSetpoint = device.currentValue("maxHeatingSetpoint")
|
def maxHeatingSetpoint = device.currentValue("maxHeatingSetpoint")
|
||||||
def maxCoolingSetpoint = device.currentValue("maxCoolingSetpoint")
|
def maxCoolingSetpoint = device.currentValue("maxCoolingSetpoint")
|
||||||
def minHeatingSetpoint = device.currentValue("minHeatingSetpoint")
|
def minHeatingSetpoint = device.currentValue("minHeatingSetpoint")
|
||||||
def minCoolingSetpoint = device.currentValue("minCoolingSetpoint")
|
def minCoolingSetpoint = device.currentValue("minCoolingSetpoint")
|
||||||
|
|
||||||
if(location.temperatureScale == "C")
|
if(location.temperatureScale == "C") {
|
||||||
{
|
maxHeatingSetpoint = maxHeatingSetpoint > 40 ? roundC(convertFtoC(maxHeatingSetpoint)) : roundC(maxHeatingSetpoint)
|
||||||
maxHeatingSetpoint = roundC(maxHeatingSetpoint)
|
maxCoolingSetpoint = maxCoolingSetpoint > 40 ? roundC(convertFtoC(maxCoolingSetpoint)) : roundC(maxCoolingSetpoint)
|
||||||
maxCoolingSetpoint = roundC(maxCoolingSetpoint)
|
minHeatingSetpoint = minHeatingSetpoint > 40 ? roundC(convertFtoC(minHeatingSetpoint)) : roundC(minHeatingSetpoint)
|
||||||
minHeatingSetpoint = roundC(minHeatingSetpoint)
|
minCoolingSetpoint = minCoolingSetpoint > 40 ? roundC(convertFtoC(minCoolingSetpoint)) : roundC(minCoolingSetpoint)
|
||||||
minCoolingSetpoint = roundC(minCoolingSetpoint)
|
heatingSetpoint = heatingSetpoint > 40 ? roundC(convertFtoC(heatingSetpoint)) : roundC(heatingSetpoint)
|
||||||
heatingSetpoint = roundC(heatingSetpoint)
|
coolingSetpoint = coolingSetpoint > 40 ? roundC(convertFtoC(coolingSetpoint)) : roundC(coolingSetpoint)
|
||||||
coolingSetpoint = roundC(coolingSetpoint)
|
} else {
|
||||||
|
maxHeatingSetpoint = maxHeatingSetpoint < 40 ? roundC(convertCtoF(maxHeatingSetpoint)) : maxHeatingSetpoint
|
||||||
|
maxCoolingSetpoint = maxCoolingSetpoint < 40 ? roundC(convertCtoF(maxCoolingSetpoint)) : maxCoolingSetpoint
|
||||||
|
minHeatingSetpoint = minHeatingSetpoint < 40 ? roundC(convertCtoF(minHeatingSetpoint)) : minHeatingSetpoint
|
||||||
|
minCoolingSetpoint = minCoolingSetpoint < 40 ? roundC(convertCtoF(minCoolingSetpoint)) : minCoolingSetpoint
|
||||||
|
heatingSetpoint = heatingSetpoint < 40 ? roundC(convertCtoF(heatingSetpoint)) : heatingSetpoint
|
||||||
|
coolingSetpoint = coolingSetpoint < 40 ? roundC(convertCtoF(coolingSetpoint)) : coolingSetpoint
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.debug "Current Mode = ${mode}"
|
||||||
|
log.debug "Heating Setpoint = ${heatingSetpoint}"
|
||||||
|
log.debug "Cooling Setpoint = ${coolingSetpoint}"
|
||||||
|
|
||||||
sendEvent("name":"maxHeatingSetpoint", "value":maxHeatingSetpoint, "unit":location.temperatureScale)
|
sendEvent("name":"maxHeatingSetpoint", "value":maxHeatingSetpoint, "unit":location.temperatureScale)
|
||||||
sendEvent("name":"maxCoolingSetpoint", "value":maxCoolingSetpoint, "unit":location.temperatureScale)
|
sendEvent("name":"maxCoolingSetpoint", "value":maxCoolingSetpoint, "unit":location.temperatureScale)
|
||||||
sendEvent("name":"minHeatingSetpoint", "value":minHeatingSetpoint, "unit":location.temperatureScale)
|
sendEvent("name":"minHeatingSetpoint", "value":minHeatingSetpoint, "unit":location.temperatureScale)
|
||||||
sendEvent("name":"minCoolingSetpoint", "value":minCoolingSetpoint, "unit":location.temperatureScale)
|
sendEvent("name":"minCoolingSetpoint", "value":minCoolingSetpoint, "unit":location.temperatureScale)
|
||||||
|
sendEvent("name":"heatingSetpoint", "value":heatingSetpoint, "unit":location.temperatureScale)
|
||||||
|
sendEvent("name":"coolingSetpoint", "value":coolingSetpoint, "unit":location.temperatureScale)
|
||||||
|
|
||||||
|
def averageSetpoint = roundC((heatingSetpoint + coolingSetpoint) / 2)
|
||||||
if (mode == "heat") {
|
if (mode == "heat") {
|
||||||
|
sendEvent("name":"thermostatSetpoint", "value":heatingSetpoint, "unit":location.temperatureScale)
|
||||||
sendEvent("name":"thermostatSetpoint", "value":heatingSetpoint )
|
sendEvent("name":"displayThermostatSetpoint", "value":heatingSetpoint, "unit":location.temperatureScale, displayed: false)
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (mode == "cool") {
|
else if (mode == "cool") {
|
||||||
|
sendEvent("name":"thermostatSetpoint", "value":coolingSetpoint, "unit":location.temperatureScale)
|
||||||
sendEvent("name":"thermostatSetpoint", "value":coolingSetpoint)
|
sendEvent("name":"displayThermostatSetpoint", "value":coolingSetpoint, "unit":location.temperatureScale, displayed: false)
|
||||||
|
|
||||||
} else if (mode == "auto") {
|
} else if (mode == "auto") {
|
||||||
|
sendEvent("name":"thermostatSetpoint", "value":averageSetpoint, "unit":location.temperatureScale)
|
||||||
sendEvent("name":"thermostatSetpoint", "value":"Auto")
|
sendEvent("name":"displayThermostatSetpoint", "value":"Auto", displayed: false)
|
||||||
|
|
||||||
} else if (mode == "off") {
|
} else if (mode == "off") {
|
||||||
|
sendEvent("name":"thermostatSetpoint", "value":averageSetpoint, "unit":location.temperatureScale)
|
||||||
sendEvent("name":"thermostatSetpoint", "value":"Off")
|
sendEvent("name":"displayThermostatSetpoint", "value":"Off", displayed: false)
|
||||||
|
} else if (mode == "emergency heat") { // emergency heat = auxHeatOnly
|
||||||
} else if (mode == "auxHeatOnly") {
|
sendEvent("name":"thermostatSetpoint", "value":heatingSetpoint, "unit":location.temperatureScale)
|
||||||
|
sendEvent("name":"displayThermostatSetpoint", "value":heatingSetpoint, "unit":location.temperatureScale, displayed: false)
|
||||||
sendEvent("name":"thermostatSetpoint", "value":heatingSetpoint)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void raiseSetpoint() {
|
void raiseSetpoint() {
|
||||||
@@ -585,30 +605,41 @@ void raiseSetpoint() {
|
|||||||
def maxHeatingSetpoint = device.currentValue("maxHeatingSetpoint")
|
def maxHeatingSetpoint = device.currentValue("maxHeatingSetpoint")
|
||||||
def maxCoolingSetpoint = device.currentValue("maxCoolingSetpoint")
|
def maxCoolingSetpoint = device.currentValue("maxCoolingSetpoint")
|
||||||
|
|
||||||
|
|
||||||
if (mode == "off" || mode == "auto") {
|
if (mode == "off" || mode == "auto") {
|
||||||
log.warn "this mode: $mode does not allow raiseSetpoint"
|
log.warn "this mode: $mode does not allow raiseSetpoint"
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
def heatingSetpoint = device.currentValue("heatingSetpoint")
|
def heatingSetpoint = device.currentValue("heatingSetpoint")
|
||||||
def coolingSetpoint = device.currentValue("coolingSetpoint")
|
def coolingSetpoint = device.currentValue("coolingSetpoint")
|
||||||
def thermostatSetpoint = device.currentValue("thermostatSetpoint")
|
def thermostatSetpoint = device.currentValue("thermostatSetpoint")
|
||||||
|
|
||||||
|
if (location.temperatureScale == "C") {
|
||||||
|
maxHeatingSetpoint = maxHeatingSetpoint > 40 ? convertFtoC(maxHeatingSetpoint) : maxHeatingSetpoint
|
||||||
|
maxCoolingSetpoint = maxCoolingSetpoint > 40 ? convertFtoC(maxCoolingSetpoint) : maxCoolingSetpoint
|
||||||
|
heatingSetpoint = heatingSetpoint > 40 ? convertFtoC(heatingSetpoint) : heatingSetpoint
|
||||||
|
coolingSetpoint = coolingSetpoint > 40 ? convertFtoC(coolingSetpoint) : coolingSetpoint
|
||||||
|
thermostatSetpoint = thermostatSetpoint > 40 ? convertFtoC(thermostatSetpoint) : thermostatSetpoint
|
||||||
|
} else {
|
||||||
|
maxHeatingSetpoint = maxHeatingSetpoint < 40 ? convertCtoF(maxHeatingSetpoint) : maxHeatingSetpoint
|
||||||
|
maxCoolingSetpoint = maxCoolingSetpoint < 40 ? convertCtoF(maxCoolingSetpoint) : maxCoolingSetpoint
|
||||||
|
heatingSetpoint = heatingSetpoint < 40 ? convertCtoF(heatingSetpoint) : heatingSetpoint
|
||||||
|
coolingSetpoint = coolingSetpoint < 40 ? convertCtoF(coolingSetpoint) : coolingSetpoint
|
||||||
|
thermostatSetpoint = thermostatSetpoint < 40 ? convertCtoF(thermostatSetpoint) : thermostatSetpoint
|
||||||
|
}
|
||||||
|
|
||||||
log.debug "raiseSetpoint() mode = ${mode}, heatingSetpoint: ${heatingSetpoint}, coolingSetpoint:${coolingSetpoint}, thermostatSetpoint:${thermostatSetpoint}"
|
log.debug "raiseSetpoint() mode = ${mode}, heatingSetpoint: ${heatingSetpoint}, coolingSetpoint:${coolingSetpoint}, thermostatSetpoint:${thermostatSetpoint}"
|
||||||
|
|
||||||
if (device.latestState('thermostatSetpoint')) {
|
targetvalue = thermostatSetpoint ? thermostatSetpoint : 0
|
||||||
targetvalue = device.latestState('thermostatSetpoint').value
|
|
||||||
targetvalue = location.temperatureScale == "F"? targetvalue.toInteger() : targetvalue.toDouble()
|
|
||||||
} else {
|
|
||||||
targetvalue = 0
|
|
||||||
}
|
|
||||||
targetvalue = location.temperatureScale == "F"? targetvalue + 1 : targetvalue + 0.5
|
targetvalue = location.temperatureScale == "F"? targetvalue + 1 : targetvalue + 0.5
|
||||||
|
|
||||||
if ((mode == "heat" || mode == "auxHeatOnly") && targetvalue > maxHeatingSetpoint) {
|
if ((mode == "heat" || mode == "emergency heat") && targetvalue > maxHeatingSetpoint) { // emergency heat = auxHeatOnly
|
||||||
targetvalue = maxHeatingSetpoint
|
targetvalue = maxHeatingSetpoint
|
||||||
} else if (mode == "cool" && targetvalue > maxCoolingSetpoint) {
|
} else if (mode == "cool" && targetvalue > maxCoolingSetpoint) {
|
||||||
targetvalue = maxCoolingSetpoint
|
targetvalue = maxCoolingSetpoint
|
||||||
}
|
}
|
||||||
|
|
||||||
sendEvent("name":"thermostatSetpoint", "value":targetvalue, displayed: false)
|
sendEvent("name":"thermostatSetpoint", "value":targetvalue, "unit":location.temperatureScale, displayed: false)
|
||||||
|
sendEvent("name":"displayThermostatSetpoint", "value":targetvalue, "unit":location.temperatureScale, displayed: false)
|
||||||
log.info "In mode $mode raiseSetpoint() to $targetvalue"
|
log.info "In mode $mode raiseSetpoint() to $targetvalue"
|
||||||
|
|
||||||
runIn(3, "alterSetpoint", [data: [value:targetvalue], overwrite: true]) //when user click button this runIn will be overwrite
|
runIn(3, "alterSetpoint", [data: [value:targetvalue], overwrite: true]) //when user click button this runIn will be overwrite
|
||||||
@@ -622,29 +653,39 @@ void lowerSetpoint() {
|
|||||||
def minHeatingSetpoint = device.currentValue("minHeatingSetpoint")
|
def minHeatingSetpoint = device.currentValue("minHeatingSetpoint")
|
||||||
def minCoolingSetpoint = device.currentValue("minCoolingSetpoint")
|
def minCoolingSetpoint = device.currentValue("minCoolingSetpoint")
|
||||||
|
|
||||||
|
|
||||||
if (mode == "off" || mode == "auto") {
|
if (mode == "off" || mode == "auto") {
|
||||||
log.warn "this mode: $mode does not allow lowerSetpoint"
|
log.warn "this mode: $mode does not allow lowerSetpoint"
|
||||||
} else {
|
} else {
|
||||||
def heatingSetpoint = device.currentValue("heatingSetpoint")
|
def heatingSetpoint = device.currentValue("heatingSetpoint")
|
||||||
def coolingSetpoint = device.currentValue("coolingSetpoint")
|
def coolingSetpoint = device.currentValue("coolingSetpoint")
|
||||||
def thermostatSetpoint = device.currentValue("thermostatSetpoint")
|
def thermostatSetpoint = device.currentValue("thermostatSetpoint")
|
||||||
log.debug "lowerSetpoint() mode = ${mode}, heatingSetpoint: ${heatingSetpoint}, coolingSetpoint:${coolingSetpoint}, thermostatSetpoint:${thermostatSetpoint}"
|
|
||||||
if (device.latestState('thermostatSetpoint')) {
|
if (location.temperatureScale == "C") {
|
||||||
targetvalue = device.latestState('thermostatSetpoint').value
|
minHeatingSetpoint = minHeatingSetpoint > 40 ? convertFtoC(minHeatingSetpoint) : minHeatingSetpoint
|
||||||
targetvalue = location.temperatureScale == "F"? targetvalue.toInteger() : targetvalue.toDouble()
|
minCoolingSetpoint = minCoolingSetpoint > 40 ? convertFtoC(minCoolingSetpoint) : minCoolingSetpoint
|
||||||
|
heatingSetpoint = heatingSetpoint > 40 ? convertFtoC(heatingSetpoint) : heatingSetpoint
|
||||||
|
coolingSetpoint = coolingSetpoint > 40 ? convertFtoC(coolingSetpoint) : coolingSetpoint
|
||||||
|
thermostatSetpoint = thermostatSetpoint > 40 ? convertFtoC(thermostatSetpoint) : thermostatSetpoint
|
||||||
} else {
|
} else {
|
||||||
targetvalue = 0
|
minHeatingSetpoint = minHeatingSetpoint < 40 ? convertCtoF(minHeatingSetpoint) : minHeatingSetpoint
|
||||||
|
minCoolingSetpoint = minCoolingSetpoint < 40 ? convertCtoF(minCoolingSetpoint) : minCoolingSetpoint
|
||||||
|
heatingSetpoint = heatingSetpoint < 40 ? convertCtoF(heatingSetpoint) : heatingSetpoint
|
||||||
|
coolingSetpoint = coolingSetpoint < 40 ? convertCtoF(coolingSetpoint) : coolingSetpoint
|
||||||
|
thermostatSetpoint = thermostatSetpoint < 40 ? convertCtoF(thermostatSetpoint) : thermostatSetpoint
|
||||||
}
|
}
|
||||||
|
log.debug "lowerSetpoint() mode = ${mode}, heatingSetpoint: ${heatingSetpoint}, coolingSetpoint:${coolingSetpoint}, thermostatSetpoint:${thermostatSetpoint}"
|
||||||
|
|
||||||
|
targetvalue = thermostatSetpoint ? thermostatSetpoint : 0
|
||||||
targetvalue = location.temperatureScale == "F"? targetvalue - 1 : targetvalue - 0.5
|
targetvalue = location.temperatureScale == "F"? targetvalue - 1 : targetvalue - 0.5
|
||||||
|
|
||||||
if ((mode == "heat" || mode == "auxHeatOnly") && targetvalue < minHeatingSetpoint) {
|
if ((mode == "heat" || mode == "emergency heat") && targetvalue < minHeatingSetpoint) { // emergency heat = auxHeatOnly
|
||||||
targetvalue = minHeatingSetpoint
|
targetvalue = minHeatingSetpoint
|
||||||
} else if (mode == "cool" && targetvalue < minCoolingSetpoint) {
|
} else if (mode == "cool" && targetvalue < minCoolingSetpoint) {
|
||||||
targetvalue = minCoolingSetpoint
|
targetvalue = minCoolingSetpoint
|
||||||
}
|
}
|
||||||
|
|
||||||
sendEvent("name":"thermostatSetpoint", "value":targetvalue, displayed: false)
|
sendEvent("name":"thermostatSetpoint", "value":targetvalue, "unit":location.temperatureScale, displayed: false)
|
||||||
|
sendEvent("name":"displayThermostatSetpoint", "value":targetvalue, "unit":location.temperatureScale, displayed: false)
|
||||||
log.info "In mode $mode lowerSetpoint() to $targetvalue"
|
log.info "In mode $mode lowerSetpoint() to $targetvalue"
|
||||||
|
|
||||||
runIn(3, "alterSetpoint", [data: [value:targetvalue], overwrite: true]) //when user click button this runIn will be overwrite
|
runIn(3, "alterSetpoint", [data: [value:targetvalue], overwrite: true]) //when user click button this runIn will be overwrite
|
||||||
@@ -653,8 +694,11 @@ void lowerSetpoint() {
|
|||||||
|
|
||||||
//called by raiseSetpoint() and lowerSetpoint()
|
//called by raiseSetpoint() and lowerSetpoint()
|
||||||
void alterSetpoint(temp) {
|
void alterSetpoint(temp) {
|
||||||
|
|
||||||
def mode = device.currentValue("thermostatMode")
|
def mode = device.currentValue("thermostatMode")
|
||||||
|
|
||||||
|
if (mode == "off" || mode == "auto") {
|
||||||
|
log.warn "this mode: $mode does not allow alterSetpoint"
|
||||||
|
} else {
|
||||||
def heatingSetpoint = device.currentValue("heatingSetpoint")
|
def heatingSetpoint = device.currentValue("heatingSetpoint")
|
||||||
def coolingSetpoint = device.currentValue("coolingSetpoint")
|
def coolingSetpoint = device.currentValue("coolingSetpoint")
|
||||||
def deviceId = device.deviceNetworkId.split(/\./).last()
|
def deviceId = device.deviceNetworkId.split(/\./).last()
|
||||||
@@ -662,8 +706,20 @@ void alterSetpoint(temp) {
|
|||||||
def targetHeatingSetpoint
|
def targetHeatingSetpoint
|
||||||
def targetCoolingSetpoint
|
def targetCoolingSetpoint
|
||||||
|
|
||||||
|
def temperatureScaleHasChanged = false
|
||||||
|
|
||||||
|
if (location.temperatureScale == "C") {
|
||||||
|
if ( heatingSetpoint > 40.0 || coolingSetpoint > 40.0 ) {
|
||||||
|
temperatureScaleHasChanged = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ( heatingSetpoint < 40.0 || coolingSetpoint < 40.0 ) {
|
||||||
|
temperatureScaleHasChanged = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//step1: check thermostatMode, enforce limits before sending request to cloud
|
//step1: check thermostatMode, enforce limits before sending request to cloud
|
||||||
if (mode == "heat" || mode == "auxHeatOnly"){
|
if (mode == "heat" || mode == "emergency heat"){ // emergency heat = auxHeatOnly
|
||||||
if (temp.value > coolingSetpoint){
|
if (temp.value > coolingSetpoint){
|
||||||
targetHeatingSetpoint = temp.value
|
targetHeatingSetpoint = temp.value
|
||||||
targetCoolingSetpoint = temp.value
|
targetCoolingSetpoint = temp.value
|
||||||
@@ -690,30 +746,36 @@ void alterSetpoint(temp) {
|
|||||||
def coolingValue = location.temperatureScale == "C"? convertCtoF(targetCoolingSetpoint) : targetCoolingSetpoint
|
def coolingValue = location.temperatureScale == "C"? convertCtoF(targetCoolingSetpoint) : targetCoolingSetpoint
|
||||||
def heatingValue = location.temperatureScale == "C"? convertCtoF(targetHeatingSetpoint) : targetHeatingSetpoint
|
def heatingValue = location.temperatureScale == "C"? convertCtoF(targetHeatingSetpoint) : targetHeatingSetpoint
|
||||||
|
|
||||||
if (parent.setHold(this, heatingValue, coolingValue, deviceId, sendHoldType)) {
|
if (parent.setHold(heatingValue, coolingValue, deviceId, sendHoldType)) {
|
||||||
sendEvent("name": "thermostatSetpoint", "value": temp.value, displayed: false)
|
sendEvent("name": "thermostatSetpoint", "value": temp.value, displayed: false)
|
||||||
sendEvent("name": "heatingSetpoint", "value": targetHeatingSetpoint)
|
sendEvent("name": "displayThermostatSetpoint", "value": temp.value, displayed: false)
|
||||||
sendEvent("name": "coolingSetpoint", "value": targetCoolingSetpoint)
|
sendEvent("name": "heatingSetpoint", "value": targetHeatingSetpoint, "unit": location.temperatureScale)
|
||||||
|
sendEvent("name": "coolingSetpoint", "value": targetCoolingSetpoint, "unit": location.temperatureScale)
|
||||||
log.debug "alterSetpoint in mode $mode succeed change setpoint to= ${temp.value}"
|
log.debug "alterSetpoint in mode $mode succeed change setpoint to= ${temp.value}"
|
||||||
} else {
|
} else {
|
||||||
log.error "Error alterSetpoint()"
|
log.error "Error alterSetpoint()"
|
||||||
if (mode == "heat" || mode == "auxHeatOnly"){
|
if (mode == "heat" || mode == "emergency heat"){ // emergency heat = auxHeatOnly
|
||||||
sendEvent("name": "thermostatSetpoint", "value": heatingSetpoint.toString(), displayed: false)
|
sendEvent("name": "thermostatSetpoint", "value": heatingSetpoint.toString(), displayed: false)
|
||||||
|
sendEvent("name": "displayThermostatSetpoint", "value": heatingSetpoint.toString(), displayed: false)
|
||||||
} else if (mode == "cool") {
|
} else if (mode == "cool") {
|
||||||
sendEvent("name": "thermostatSetpoint", "value": coolingSetpoint.toString(), displayed: false)
|
sendEvent("name": "thermostatSetpoint", "value": coolingSetpoint.toString(), displayed: false)
|
||||||
|
sendEvent("name": "displayThermostatSetpoint", "value": heatingSetpoint.toString(), displayed: false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( temperatureScaleHasChanged )
|
||||||
|
generateSetpointEvent()
|
||||||
generateStatusEvent()
|
generateStatusEvent()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def generateStatusEvent() {
|
def generateStatusEvent() {
|
||||||
|
|
||||||
def mode = device.currentValue("thermostatMode")
|
def mode = device.currentValue("thermostatMode")
|
||||||
def heatingSetpoint = device.currentValue("heatingSetpoint")
|
def heatingSetpoint = device.currentValue("heatingSetpoint")
|
||||||
def coolingSetpoint = device.currentValue("coolingSetpoint")
|
def coolingSetpoint = device.currentValue("coolingSetpoint")
|
||||||
def temperature = device.currentValue("temperature")
|
def temperature = device.currentValue("temperature")
|
||||||
|
|
||||||
def statusText
|
def statusText
|
||||||
|
def operatingState = "idle"
|
||||||
|
|
||||||
log.debug "Generate Status Event for Mode = ${mode}"
|
log.debug "Generate Status Event for Mode = ${mode}"
|
||||||
log.debug "Temperature = ${temperature}"
|
log.debug "Temperature = ${temperature}"
|
||||||
@@ -722,38 +784,37 @@ def generateStatusEvent() {
|
|||||||
log.debug "HVAC Mode = ${mode}"
|
log.debug "HVAC Mode = ${mode}"
|
||||||
|
|
||||||
if (mode == "heat") {
|
if (mode == "heat") {
|
||||||
|
if (temperature >= heatingSetpoint) {
|
||||||
if (temperature >= heatingSetpoint)
|
|
||||||
statusText = "Right Now: Idle"
|
statusText = "Right Now: Idle"
|
||||||
else
|
|
||||||
statusText = "Heating to ${heatingSetpoint} ${location.temperatureScale}"
|
|
||||||
|
|
||||||
} else if (mode == "cool") {
|
|
||||||
|
|
||||||
if (temperature <= coolingSetpoint)
|
|
||||||
statusText = "Right Now: Idle"
|
|
||||||
else
|
|
||||||
statusText = "Cooling to ${coolingSetpoint} ${location.temperatureScale}"
|
|
||||||
|
|
||||||
} else if (mode == "auto") {
|
|
||||||
|
|
||||||
statusText = "Right Now: Auto"
|
|
||||||
|
|
||||||
} else if (mode == "off") {
|
|
||||||
|
|
||||||
statusText = "Right Now: Off"
|
|
||||||
|
|
||||||
} else if (mode == "auxHeatOnly") {
|
|
||||||
|
|
||||||
statusText = "Emergency Heat"
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
statusText = "Heating to ${heatingSetpoint} ${location.temperatureScale}"
|
||||||
statusText = "?"
|
operatingState = "heating"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
} else if (mode == "cool") {
|
||||||
|
if (temperature <= coolingSetpoint) {
|
||||||
|
statusText = "Right Now: Idle"
|
||||||
|
} else {
|
||||||
|
statusText = "Cooling to ${coolingSetpoint} ${location.temperatureScale}"
|
||||||
|
operatingState = "cooling"
|
||||||
|
}
|
||||||
|
} else if (mode == "auto") {
|
||||||
|
statusText = "Right Now: Auto"
|
||||||
|
if (temperature < heatingSetpoint) {
|
||||||
|
operatingState = "heating"
|
||||||
|
} else if (temperature > coolingSetpoint) {
|
||||||
|
operatingState = "cooling"
|
||||||
|
}
|
||||||
|
} else if (mode == "off") {
|
||||||
|
statusText = "Right Now: Off"
|
||||||
|
} else if (mode == "emergency heat") { // emergency heat = auxHeatOnly
|
||||||
|
statusText = "Emergency Heat"
|
||||||
|
} else {
|
||||||
|
statusText = "?"
|
||||||
|
}
|
||||||
|
|
||||||
log.debug "Generate Status Event = ${statusText}"
|
log.debug "Generate Status Event = ${statusText}"
|
||||||
sendEvent("name":"thermostatStatus", "value":statusText, "description":statusText, displayed: true)
|
sendEvent("name":"thermostatStatus", "value":statusText, "description":statusText, displayed: true)
|
||||||
|
sendEvent("name":"thermostatOperatingState", "value":operatingState, "description":operatingState, displayed: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
def generateActivityFeedsEvent(notificationMessage) {
|
def generateActivityFeedsEvent(notificationMessage) {
|
||||||
@@ -765,7 +826,7 @@ def roundC (tempC) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def convertFtoC (tempF) {
|
def convertFtoC (tempF) {
|
||||||
return String.format("%.1f", (Math.round(((tempF - 32)*(5/9)) * 2))/2)
|
return ((Math.round(((tempF - 32)*(5/9)) * 2))/2).toDouble()
|
||||||
}
|
}
|
||||||
|
|
||||||
def convertCtoF (tempC) {
|
def convertCtoF (tempC) {
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
.st-ignore
|
||||||
|
README.md
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
# EcoNet Vent
|
||||||
|
|
||||||
|
Cloud Execution
|
||||||
|
|
||||||
|
Works with:
|
||||||
|
|
||||||
|
* [EcoNet Controls Z-Wave Vent](https://www.smartthings.com/works-with-smartthings/econet-controls/econet-controls-z-wave-vent)
|
||||||
|
|
||||||
|
## Table of contents
|
||||||
|
|
||||||
|
* [Capabilities](#capabilities)
|
||||||
|
* [Health](#device-health)
|
||||||
|
* [Troubleshooting](#troubleshooting)
|
||||||
|
|
||||||
|
## Capabilities
|
||||||
|
|
||||||
|
* **Switch Level** - allows for the control of the level attribute of a light
|
||||||
|
* **Actuator** - represents that a Device has commands
|
||||||
|
* **Switch** - allows for the control of a switch device
|
||||||
|
* **Battery** - defines that the device has a battery
|
||||||
|
* **Refresh** - _refresh()_ command for status updates
|
||||||
|
* **Sensor** - detects sensor events
|
||||||
|
* **Polling** - allows for the polling of devices that support it
|
||||||
|
* **Configuration** - allow configuration of devices that support it
|
||||||
|
* **Health Check** - indicates ability to get device health notifications
|
||||||
|
|
||||||
|
## Device Health
|
||||||
|
|
||||||
|
EcoNet Controls Z-Wave Vent is polled by the hub.
|
||||||
|
As of hubCore version 0.14.38 the hub sends up reports every 15 minutes regardless of whether the state changed.
|
||||||
|
Device-Watch allows 2 check-in misses from device plus some lag time. So Check-in interval = (2*15 + 2)mins = 32 mins.
|
||||||
|
Not to mention after going OFFLINE when the device is plugged back in, it might take a considerable amount of time for
|
||||||
|
the device to appear as ONLINE again. This is because if this listening device does not respond to two poll requests in a row,
|
||||||
|
it is not polled for 5 minutes by the hub. This can delay up the process of being marked ONLINE by quite some time.
|
||||||
|
|
||||||
|
* __32min__ checkInterval
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the device is out of range.
|
||||||
|
Pairing needs to be tried again by placing the device closer to the hub.
|
||||||
|
Instructions related to pairing, resetting and removing the device from SmartThings can be found in the following link:
|
||||||
|
* [EcoNet Controls Z-Wave Vent Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/204556420-EcoNet-EV100-Vent)
|
||||||
@@ -26,11 +26,13 @@ metadata {
|
|||||||
capability "Sensor"
|
capability "Sensor"
|
||||||
capability "Polling"
|
capability "Polling"
|
||||||
capability "Configuration"
|
capability "Configuration"
|
||||||
|
capability "Health Check"
|
||||||
|
|
||||||
command "open"
|
command "open"
|
||||||
command "close"
|
command "close"
|
||||||
|
|
||||||
fingerprint deviceId: "0x1100", inClusters: "0x26,0x72,0x86,0x77,0x80,0x20"
|
fingerprint deviceId: "0x1100", inClusters: "0x26,0x72,0x86,0x77,0x80,0x20"
|
||||||
|
fingerprint mfr:"0157", prod:"0100", model:"0100", deviceJoinName: "EcoNet Controls Z-Wave Vent"
|
||||||
}
|
}
|
||||||
|
|
||||||
simulator {
|
simulator {
|
||||||
@@ -53,7 +55,7 @@ metadata {
|
|||||||
|
|
||||||
tiles {
|
tiles {
|
||||||
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
|
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
|
||||||
state "on", action:"switch.off", icon:"st.vents.vent-open-text", backgroundColor:"#53a7c0"
|
state "on", action:"switch.off", icon:"st.vents.vent-open-text", backgroundColor:"#00a0dc"
|
||||||
state "off", action:"switch.on", icon:"st.vents.vent-closed", backgroundColor:"#ffffff"
|
state "off", action:"switch.on", icon:"st.vents.vent-closed", backgroundColor:"#ffffff"
|
||||||
}
|
}
|
||||||
valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat") {
|
valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat") {
|
||||||
@@ -83,8 +85,15 @@ def parse(String description) {
|
|||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def installed() {
|
||||||
|
// Device-Watch simply pings if no device events received for 32min(checkInterval)
|
||||||
|
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
|
||||||
|
}
|
||||||
|
|
||||||
//send the command to stop polling
|
//send the command to stop polling
|
||||||
def updated() {
|
def updated() {
|
||||||
|
// Device-Watch simply pings if no device events received for 32min(checkInterval)
|
||||||
|
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
|
||||||
response("poll stop")
|
response("poll stop")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,6 +178,13 @@ def setLevel(value, duration) {
|
|||||||
setLevel(value)
|
setLevel(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PING is used by Device-Watch in attempt to reach the Device
|
||||||
|
* */
|
||||||
|
def ping() {
|
||||||
|
refresh()
|
||||||
|
}
|
||||||
|
|
||||||
def refresh() {
|
def refresh() {
|
||||||
delayBetween([
|
delayBetween([
|
||||||
zwave.switchMultilevelV1.switchMultilevelGet().format(),
|
zwave.switchMultilevelV1.switchMultilevelGet().format(),
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
.st-ignore
|
||||||
|
README.md
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
# Everspring Flood Sensor
|
||||||
|
|
||||||
|
Cloud Execution
|
||||||
|
|
||||||
|
Works with:
|
||||||
|
|
||||||
|
* [Everspring Water Detector](https://www.smartthings.com/works-with-smartthings/sensors/everspring-water-detector)
|
||||||
|
|
||||||
|
## Table of contents
|
||||||
|
|
||||||
|
* [Capabilities](#capabilities)
|
||||||
|
* [Health](#device-health)
|
||||||
|
* [Battery](#battery-specification)
|
||||||
|
* [Troubleshooting](#troubleshooting)
|
||||||
|
|
||||||
|
## Capabilities
|
||||||
|
|
||||||
|
* **Water Sensor** - can detect presence of water (dry or wet)
|
||||||
|
* **Configuration** - _configure()_ command called when device is installed or device preferences updated
|
||||||
|
* **Sensor** - detects sensor events
|
||||||
|
* **Battery** - defines device uses a battery
|
||||||
|
* **Health Check** - indicates ability to get device health notifications
|
||||||
|
|
||||||
|
## Device Health
|
||||||
|
|
||||||
|
Everspring Water Detector is a Z-wave sleepy device and wakes up every 4 hours.
|
||||||
|
Device-Watch allows 2 check-in misses from device plus some lag time. So Check-in interval = (2*4*60 + 2)mins = 482 mins.
|
||||||
|
|
||||||
|
* __482min__ checkInterval
|
||||||
|
|
||||||
|
## Battery Specification
|
||||||
|
|
||||||
|
Three AA 1.5V batteries are required.
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the device is out of range.
|
||||||
|
Pairing needs to be tried again by placing the device closer to the hub.
|
||||||
|
Instructions related to pairing, resetting and removing the device from SmartThings can be found in the following link:
|
||||||
|
* [Everspring Water Detector Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/202088304-Everspring-Water-Detector)
|
||||||
@@ -12,11 +12,12 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
metadata {
|
metadata {
|
||||||
definition (name: "Everspring Flood Sensor", namespace: "smartthings", author: "SmartThings") {
|
definition (name: "Everspring Flood Sensor", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "x.com.st.d.sensor.moisture") {
|
||||||
capability "Water Sensor"
|
capability "Water Sensor"
|
||||||
capability "Configuration"
|
capability "Configuration"
|
||||||
capability "Sensor"
|
capability "Sensor"
|
||||||
capability "Battery"
|
capability "Battery"
|
||||||
|
capability "Health Check"
|
||||||
|
|
||||||
fingerprint deviceId: "0xA102", inClusters: "0x86,0x72,0x85,0x84,0x80,0x70,0x9C,0x20,0x71"
|
fingerprint deviceId: "0xA102", inClusters: "0x86,0x72,0x85,0x84,0x80,0x70,0x9C,0x20,0x71"
|
||||||
}
|
}
|
||||||
@@ -33,7 +34,7 @@ metadata {
|
|||||||
multiAttributeTile(name:"water", type: "generic", width: 6, height: 4){
|
multiAttributeTile(name:"water", type: "generic", width: 6, height: 4){
|
||||||
tileAttribute ("device.water", key: "PRIMARY_CONTROL") {
|
tileAttribute ("device.water", key: "PRIMARY_CONTROL") {
|
||||||
attributeState "dry", icon:"st.alarm.water.dry", backgroundColor:"#ffffff"
|
attributeState "dry", icon:"st.alarm.water.dry", backgroundColor:"#ffffff"
|
||||||
attributeState "wet", icon:"st.alarm.water.wet", backgroundColor:"#53a7c0"
|
attributeState "wet", icon:"st.alarm.water.wet", backgroundColor:"#00a0dc"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
valueTile("battery", "device.battery", decoration: "flat", inactiveLabel: false, width: 2, height: 2) {
|
valueTile("battery", "device.battery", decoration: "flat", inactiveLabel: false, width: 2, height: 2) {
|
||||||
@@ -138,6 +139,8 @@ def zwaveEvent(physicalgraph.zwave.Command cmd)
|
|||||||
|
|
||||||
def configure()
|
def configure()
|
||||||
{
|
{
|
||||||
|
// Device wakes up every 4 hours, this interval allows us to miss one wakeup notification before marking offline
|
||||||
|
sendEvent(name: "checkInterval", value: 8 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
|
||||||
if (!device.currentState("battery")) {
|
if (!device.currentState("battery")) {
|
||||||
sendEvent(name: "battery", value:100, unit:"%", descriptionText:"(Default battery event)", displayed:false)
|
sendEvent(name: "battery", value:100, unit:"%", descriptionText:"(Default battery event)", displayed:false)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,9 +56,9 @@ metadata {
|
|||||||
|
|
||||||
tiles {
|
tiles {
|
||||||
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
|
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
|
||||||
state "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"turningOff"
|
state "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#00a0dc", nextState:"turningOff"
|
||||||
state "off", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
state "off", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
state "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"turningOff"
|
state "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#00a0dc", nextState:"turningOff"
|
||||||
state "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
state "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
}
|
}
|
||||||
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat") {
|
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat") {
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
.st-ignore
|
||||||
|
README.md
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
# Fibaro Door Window Sensor
|
||||||
|
|
||||||
|
Cloud Execution
|
||||||
|
|
||||||
|
Works with:
|
||||||
|
|
||||||
|
* [Fibaro Door/Window Sensor](https://www.smartthings.com/works-with-smartthings/sensors/fibaro-doorwindow-sensor)
|
||||||
|
|
||||||
|
## Table of contents
|
||||||
|
|
||||||
|
* [Capabilities](#capabilities)
|
||||||
|
* [Health](#device-health)
|
||||||
|
* [Battery](#battery-specification)
|
||||||
|
* [Troubleshooting](#troubleshooting)
|
||||||
|
|
||||||
|
## Capabilities
|
||||||
|
|
||||||
|
* **Contact Sensor** - can detect contact (possible values: open,closed)
|
||||||
|
* **Sensor** - detects sensor events
|
||||||
|
* **Battery** - defines device uses a battery
|
||||||
|
* **Configuration** - _configure()_ command called when device is installed or device preferences updated
|
||||||
|
* **Health Check** - indicates ability to get device health notifications
|
||||||
|
|
||||||
|
## Device Health
|
||||||
|
|
||||||
|
Fibaro Door/Window Sensor is a Z-wave sleepy device and wakes up every 4 hours.
|
||||||
|
Device-Watch allows 2 check-in misses from device plus some lag time. So Check-in interval = (2*4*60 + 2)mins = 482 mins.
|
||||||
|
|
||||||
|
* __482min__ checkInterval
|
||||||
|
|
||||||
|
## Battery Specification
|
||||||
|
|
||||||
|
One 1/2AA 3.6V battery is required.
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the device is out of range.
|
||||||
|
Pairing needs to be tried again by placing the device closer to the hub.
|
||||||
|
Instructions related to pairing, resetting and removing the device from SmartThings can be found in the following link:
|
||||||
|
* [Fibaro Door/Window Sensor Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/204075194-Fibaro-Door-Window-Sensor)
|
||||||
@@ -40,6 +40,7 @@
|
|||||||
capability "Sensor"
|
capability "Sensor"
|
||||||
capability "Battery"
|
capability "Battery"
|
||||||
capability "Configuration"
|
capability "Configuration"
|
||||||
|
capability "Health Check"
|
||||||
|
|
||||||
command "resetParams2StDefaults"
|
command "resetParams2StDefaults"
|
||||||
command "listCurrentParams"
|
command "listCurrentParams"
|
||||||
@@ -266,6 +267,9 @@ def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerS
|
|||||||
*/
|
*/
|
||||||
def configure() {
|
def configure() {
|
||||||
log.debug "Configuring Device..."
|
log.debug "Configuring Device..."
|
||||||
|
// Device wakes up every 4 hours, this interval allows us to miss one wakeup notification before marking offline
|
||||||
|
sendEvent(name: "checkInterval", value: 8 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
|
||||||
|
|
||||||
def cmds = []
|
def cmds = []
|
||||||
cmds << zwave.configurationV1.configurationSet(configurationValue: [0,0], parameterNumber: 1, size: 2).format()
|
cmds << zwave.configurationV1.configurationSet(configurationValue: [0,0], parameterNumber: 1, size: 2).format()
|
||||||
// send associate to group 3 to get sensor data reported only to hub
|
// send associate to group 3 to get sensor data reported only to hub
|
||||||
|
|||||||
@@ -39,6 +39,8 @@ metadata {
|
|||||||
capability "Temperature Measurement"
|
capability "Temperature Measurement"
|
||||||
capability "Configuration"
|
capability "Configuration"
|
||||||
capability "Battery"
|
capability "Battery"
|
||||||
|
capability "Health Check"
|
||||||
|
capability "Sensor"
|
||||||
|
|
||||||
command "resetParams2StDefaults"
|
command "resetParams2StDefaults"
|
||||||
command "listCurrentParams"
|
command "listCurrentParams"
|
||||||
@@ -46,6 +48,9 @@ metadata {
|
|||||||
command "test"
|
command "test"
|
||||||
|
|
||||||
fingerprint deviceId: "0xA102", inClusters: "0x30,0x9C,0x60,0x85,0x8E,0x72,0x70,0x86,0x80,0x84"
|
fingerprint deviceId: "0xA102", inClusters: "0x30,0x9C,0x60,0x85,0x8E,0x72,0x70,0x86,0x80,0x84"
|
||||||
|
fingerprint mfr:"010F", prod:"0000", model:"2002"
|
||||||
|
fingerprint mfr:"010F", prod:"0000", model:"1002"
|
||||||
|
fingerprint mfr:"010F", prod:"0B00", model:"1001"
|
||||||
}
|
}
|
||||||
|
|
||||||
simulator {
|
simulator {
|
||||||
@@ -72,7 +77,7 @@ metadata {
|
|||||||
tiles {
|
tiles {
|
||||||
standardTile("water", "device.water", width: 2, height: 2) {
|
standardTile("water", "device.water", width: 2, height: 2) {
|
||||||
state "dry", icon:"st.alarm.water.dry", backgroundColor:"#ffffff"
|
state "dry", icon:"st.alarm.water.dry", backgroundColor:"#ffffff"
|
||||||
state "wet", icon:"st.alarm.water.wet", backgroundColor:"#53a7c0"
|
state "wet", icon:"st.alarm.water.wet", backgroundColor:"#00a0dc"
|
||||||
}
|
}
|
||||||
valueTile("temperature", "device.temperature", inactiveLabel: false) {
|
valueTile("temperature", "device.temperature", inactiveLabel: false) {
|
||||||
state "temperature", label:'${currentValue}°',
|
state "temperature", label:'${currentValue}°',
|
||||||
@@ -88,7 +93,7 @@ metadata {
|
|||||||
}
|
}
|
||||||
standardTile("tamper", "device.tamper") {
|
standardTile("tamper", "device.tamper") {
|
||||||
state("secure", label:"secure", icon:"st.locks.lock.locked", backgroundColor:"#ffffff")
|
state("secure", label:"secure", icon:"st.locks.lock.locked", backgroundColor:"#ffffff")
|
||||||
state("tampered", label:"tampered", icon:"st.locks.lock.unlocked", backgroundColor:"#53a7c0")
|
state("tampered", label:"tampered", icon:"st.locks.lock.unlocked", backgroundColor:"#00a0dc")
|
||||||
}
|
}
|
||||||
valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat") {
|
valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat") {
|
||||||
state "battery", label:'${currentValue}% battery', unit:""
|
state "battery", label:'${currentValue}% battery', unit:""
|
||||||
@@ -107,20 +112,11 @@ def parse(String description)
|
|||||||
{
|
{
|
||||||
def result = []
|
def result = []
|
||||||
|
|
||||||
if (description == "updated") {
|
|
||||||
if (!state.MSR) {
|
|
||||||
result << response(zwave.wakeUpV1.wakeUpIntervalSet(seconds: 60*60, nodeid:zwaveHubNodeId))
|
|
||||||
result << response(zwave.manufacturerSpecificV2.manufacturerSpecificGet())
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
def cmd = zwave.parse(description, [0x31: 2, 0x30: 1, 0x70: 2, 0x71: 1, 0x84: 1, 0x80: 1, 0x9C: 1, 0x72: 2, 0x56: 2, 0x60: 3])
|
def cmd = zwave.parse(description, [0x31: 2, 0x30: 1, 0x70: 2, 0x71: 1, 0x84: 1, 0x80: 1, 0x9C: 1, 0x72: 2, 0x56: 2, 0x60: 3])
|
||||||
|
|
||||||
if (cmd) {
|
if (cmd) {
|
||||||
result += zwaveEvent(cmd) //createEvent(zwaveEvent(cmd))
|
result += zwaveEvent(cmd) //createEvent(zwaveEvent(cmd))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
result << response(zwave.batteryV1.batteryGet().format())
|
|
||||||
|
|
||||||
if ( result[0] != null ) {
|
if ( result[0] != null ) {
|
||||||
log.debug "Parse returned ${result}"
|
log.debug "Parse returned ${result}"
|
||||||
@@ -142,10 +138,9 @@ def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd) {
|
|||||||
def result = [createEvent(descriptionText: "${device.displayName} woke up", isStateChange: false)]
|
def result = [createEvent(descriptionText: "${device.displayName} woke up", isStateChange: false)]
|
||||||
if (!isConfigured()) {
|
if (!isConfigured()) {
|
||||||
// we're still in the process of configuring a newly joined device
|
// we're still in the process of configuring a newly joined device
|
||||||
result += lateConfigure(true)
|
result << lateConfigure(true)
|
||||||
} else {
|
} else {
|
||||||
result += response(zwave.wakeUpV1.wakeUpNoMoreInformation())
|
result << response(zwave.wakeUpV1.wakeUpNoMoreInformation())
|
||||||
log.debug "We're done with WakeUp!"
|
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
@@ -304,6 +299,12 @@ def lateConfigure(setConf = False) {
|
|||||||
*/
|
*/
|
||||||
def configure() {
|
def configure() {
|
||||||
log.debug "Configuring Device..."
|
log.debug "Configuring Device..."
|
||||||
|
// Device wakes up every 4 hours, this interval allows us to miss one wakeup notification before marking offline
|
||||||
|
sendEvent(name: "checkInterval", value: 8 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
|
||||||
|
|
||||||
|
// default initial state
|
||||||
|
sendEvent(name: "water", value: "dry")
|
||||||
|
|
||||||
def cmds = []
|
def cmds = []
|
||||||
|
|
||||||
// send associate to group 2 to get alarm data
|
// send associate to group 2 to get alarm data
|
||||||
@@ -314,13 +315,15 @@ def configure() {
|
|||||||
// send associate to group 3 to get sensor data reported only to hub
|
// send associate to group 3 to get sensor data reported only to hub
|
||||||
cmds << zwave.associationV2.associationSet(groupingIdentifier:3, nodeId:[zwaveHubNodeId]).format()
|
cmds << zwave.associationV2.associationSet(groupingIdentifier:3, nodeId:[zwaveHubNodeId]).format()
|
||||||
|
|
||||||
// temp hysteresis set to .5 degrees celcius
|
|
||||||
cmds << zwave.configurationV1.configurationSet(configurationValue: [0,50], parameterNumber: 12, size: 2).format()
|
|
||||||
cmds << zwave.configurationV1.configurationGet(parameterNumber: 12).format()
|
|
||||||
|
|
||||||
// reporting frequency of temps and battery set to one hour
|
// reporting frequency of temps and battery set to one hour
|
||||||
cmds << zwave.configurationV1.configurationSet(configurationValue: [0,60*60], parameterNumber: 10, size: 2).format()
|
cmds << zwave.configurationV1.configurationSet(configurationValue: [0,60*60], parameterNumber: 10, size: 2).format()
|
||||||
cmds << zwave.configurationV1.configurationGet(parameterNumber: 10).format()
|
// cmds << zwave.configurationV1.configurationGet(parameterNumber: 10).format()
|
||||||
|
|
||||||
|
// temp hysteresis set to .5 degrees celcius
|
||||||
|
cmds << zwave.configurationV1.configurationSet(configurationValue: [0,50], parameterNumber: 12, size: 2).format()
|
||||||
|
// cmds << zwave.configurationV1.configurationGet(parameterNumber: 12).format()
|
||||||
|
|
||||||
|
cmds << zwave.batteryV1.batteryGet().format()
|
||||||
|
|
||||||
cmds << zwave.wakeUpV1.wakeUpNoMoreInformation().format()
|
cmds << zwave.wakeUpV1.wakeUpNoMoreInformation().format()
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@
|
|||||||
* @return none
|
* @return none
|
||||||
*/
|
*/
|
||||||
metadata {
|
metadata {
|
||||||
definition (name: "Fibaro Motion Sensor", namespace: "smartthings", author: "SmartThings") {
|
definition (name: "Fibaro Motion Sensor", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "x.com.st.d.sensor.motion") {
|
||||||
capability "Motion Sensor"
|
capability "Motion Sensor"
|
||||||
capability "Temperature Measurement"
|
capability "Temperature Measurement"
|
||||||
capability "Acceleration Sensor"
|
capability "Acceleration Sensor"
|
||||||
@@ -46,6 +46,7 @@
|
|||||||
capability "Illuminance Measurement"
|
capability "Illuminance Measurement"
|
||||||
capability "Sensor"
|
capability "Sensor"
|
||||||
capability "Battery"
|
capability "Battery"
|
||||||
|
capability "Health Check"
|
||||||
|
|
||||||
command "resetParams2StDefaults"
|
command "resetParams2StDefaults"
|
||||||
command "listCurrentParams"
|
command "listCurrentParams"
|
||||||
@@ -81,8 +82,8 @@
|
|||||||
|
|
||||||
tiles {
|
tiles {
|
||||||
standardTile("motion", "device.motion", width: 2, height: 2) {
|
standardTile("motion", "device.motion", width: 2, height: 2) {
|
||||||
state "active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#53a7c0"
|
state "active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#00a0dc"
|
||||||
state "inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#ffffff"
|
state "inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#cccccc"
|
||||||
}
|
}
|
||||||
valueTile("temperature", "device.temperature", inactiveLabel: false) {
|
valueTile("temperature", "device.temperature", inactiveLabel: false) {
|
||||||
state "temperature", label:'${currentValue}°',
|
state "temperature", label:'${currentValue}°',
|
||||||
@@ -125,6 +126,9 @@
|
|||||||
*/
|
*/
|
||||||
def configure() {
|
def configure() {
|
||||||
log.debug "Configuring Device For SmartThings Use"
|
log.debug "Configuring Device For SmartThings Use"
|
||||||
|
// Device-Watch simply pings if no device events received for 8 hrs & 2 minutes
|
||||||
|
sendEvent(name: "checkInterval", value: 8 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
|
||||||
|
|
||||||
def cmds = []
|
def cmds = []
|
||||||
|
|
||||||
// send associate to group 3 to get sensor data reported only to hub
|
// send associate to group 3 to get sensor data reported only to hub
|
||||||
@@ -432,4 +436,3 @@ def listCurrentParams() {
|
|||||||
|
|
||||||
delayBetween(cmds, 500)
|
delayBetween(cmds, 500)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -89,9 +89,9 @@
|
|||||||
state "whiteLevel", action:"setWhiteLevel", label:'White Level'
|
state "whiteLevel", action:"setWhiteLevel", label:'White Level'
|
||||||
}
|
}
|
||||||
standardTile("switch", "device.switch", width: 1, height: 1, canChangeIcon: true) {
|
standardTile("switch", "device.switch", width: 1, height: 1, canChangeIcon: true) {
|
||||||
state "on", label:'${name}', action:"switch.off", icon:"st.illuminance.illuminance.bright", backgroundColor:"#79b821", nextState:"turningOff"
|
state "on", label:'${name}', action:"switch.off", icon:"st.illuminance.illuminance.bright", backgroundColor:"#00A0DC", nextState:"turningOff"
|
||||||
state "off", label:'${name}', action:"switch.on", icon:"st.illuminance.illuminance.dark", backgroundColor:"#ffffff", nextState:"turningOn"
|
state "off", label:'${name}', action:"switch.on", icon:"st.illuminance.illuminance.dark", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
state "turningOn", label:'${name}', icon:"st.illuminance.illuminance.bright", backgroundColor:"#79b821"
|
state "turningOn", label:'${name}', icon:"st.illuminance.illuminance.bright", backgroundColor:"#00A0DC"
|
||||||
state "turningOff", label:'${name}', icon:"st.illuminance.illuminance.dark", backgroundColor:"#ffffff"
|
state "turningOff", label:'${name}', icon:"st.illuminance.illuminance.dark", backgroundColor:"#ffffff"
|
||||||
}
|
}
|
||||||
valueTile("power", "device.power", decoration: "flat") {
|
valueTile("power", "device.power", decoration: "flat") {
|
||||||
@@ -546,7 +546,7 @@ def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport
|
|||||||
def value = "when off"
|
def value = "when off"
|
||||||
if (cmd.configurationValue[0] == 1) {value = "when on"}
|
if (cmd.configurationValue[0] == 1) {value = "when on"}
|
||||||
if (cmd.configurationValue[0] == 2) {value = "never"}
|
if (cmd.configurationValue[0] == 2) {value = "never"}
|
||||||
[name: "indicatorStatus", value: value, display: false]
|
[name: "indicatorStatus", value: value, displayed: false]
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
def createEvent(physicalgraph.zwave.Command cmd, Map map) {
|
def createEvent(physicalgraph.zwave.Command cmd, Map map) {
|
||||||
@@ -829,7 +829,7 @@ def toggleTiles(color) {
|
|||||||
state.colorTiles.each({
|
state.colorTiles.each({
|
||||||
if ( it == color ) {
|
if ( it == color ) {
|
||||||
log.debug "Turning ${it} on"
|
log.debug "Turning ${it} on"
|
||||||
cmds << sendEvent(name: it, value: "on${it}", display: True, descriptionText: "${device.displayName} ${color} is 'ON'", isStateChange: true)
|
cmds << sendEvent(name: it, value: "on${it}", displayed: True, descriptionText: "${device.displayName} ${color} is 'ON'", isStateChange: true)
|
||||||
} else {
|
} else {
|
||||||
//log.debug "Turning ${it} off"
|
//log.debug "Turning ${it} off"
|
||||||
cmds << sendEvent(name: it, value: "off${it}", displayed: false)
|
cmds << sendEvent(name: it, value: "off${it}", displayed: false)
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ metadata {
|
|||||||
attribute "tamper", "enum", ["detected", "clear"]
|
attribute "tamper", "enum", ["detected", "clear"]
|
||||||
attribute "heatAlarm", "enum", ["overheat detected", "clear", "rapid temperature rise", "underheat detected"]
|
attribute "heatAlarm", "enum", ["overheat detected", "clear", "rapid temperature rise", "underheat detected"]
|
||||||
fingerprint deviceId: "0x0701", inClusters: "0x5E, 0x86, 0x72, 0x5A, 0x59, 0x85, 0x73, 0x84, 0x80, 0x71, 0x56, 0x70, 0x31, 0x8E, 0x22, 0x9C, 0x98, 0x7A", outClusters: "0x20, 0x8B"
|
fingerprint deviceId: "0x0701", inClusters: "0x5E, 0x86, 0x72, 0x5A, 0x59, 0x85, 0x73, 0x84, 0x80, 0x71, 0x56, 0x70, 0x31, 0x8E, 0x22, 0x9C, 0x98, 0x7A", outClusters: "0x20, 0x8B"
|
||||||
|
fingerprint mfr:"010F", prod:"0C02", model:"1002"
|
||||||
}
|
}
|
||||||
simulator {
|
simulator {
|
||||||
//battery
|
//battery
|
||||||
|
|||||||
@@ -682,7 +682,7 @@ def setHeatingSetpoint(degrees) {
|
|||||||
def temperatureScale = getTemperatureScale()
|
def temperatureScale = getTemperatureScale()
|
||||||
|
|
||||||
def degreesInteger = degrees as Integer
|
def degreesInteger = degrees as Integer
|
||||||
sendEvent("name":"heatingSetpoint", "value":degreesInteger)
|
sendEvent("name":"heatingSetpoint", "value":degreesInteger, "unit":temperatureScale)
|
||||||
|
|
||||||
def celsius = (getTemperatureScale() == "C") ? degreesInteger : (fahrenheitToCelsius(degreesInteger) as Double).round(2)
|
def celsius = (getTemperatureScale() == "C") ? degreesInteger : (fahrenheitToCelsius(degreesInteger) as Double).round(2)
|
||||||
"st wattr 0x${device.deviceNetworkId} 1 0x201 0x12 0x29 {" + hex(celsius*100) + "}"
|
"st wattr 0x${device.deviceNetworkId} 1 0x201 0x12 0x29 {" + hex(celsius*100) + "}"
|
||||||
@@ -691,7 +691,7 @@ def setHeatingSetpoint(degrees) {
|
|||||||
|
|
||||||
def setCoolingSetpoint(degrees) {
|
def setCoolingSetpoint(degrees) {
|
||||||
def degreesInteger = degrees as Integer
|
def degreesInteger = degrees as Integer
|
||||||
sendEvent("name":"coolingSetpoint", "value":degreesInteger)
|
sendEvent("name":"coolingSetpoint", "value":degreesInteger, "unit":temperatureScale)
|
||||||
def celsius = (getTemperatureScale() == "C") ? degreesInteger : (fahrenheitToCelsius(degreesInteger) as Double).round(2)
|
def celsius = (getTemperatureScale() == "C") ? degreesInteger : (fahrenheitToCelsius(degreesInteger) as Double).round(2)
|
||||||
"st wattr 0x${device.deviceNetworkId} 1 0x201 0x11 0x29 {" + hex(celsius*100) + "}"
|
"st wattr 0x${device.deviceNetworkId} 1 0x201 0x11 0x29 {" + hex(celsius*100) + "}"
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
.st-ignore
|
||||||
|
README.md
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
# FortrezZ Water Valve
|
||||||
|
|
||||||
|
Cloud Execution
|
||||||
|
|
||||||
|
Works with:
|
||||||
|
|
||||||
|
* [FortrezZ Water Valve](https://www.smartthings.com/works-with-smartthings/other/fortrezz-water-valve)
|
||||||
|
|
||||||
|
## Table of contents
|
||||||
|
|
||||||
|
* [Capabilities](#capabilities)
|
||||||
|
* [Health](#device-health)
|
||||||
|
* [Troubleshooting](#troubleshooting)
|
||||||
|
|
||||||
|
## Capabilities
|
||||||
|
|
||||||
|
* **Actuator** - represents that a Device has commands
|
||||||
|
* **Health Check** - indicates ability to get device health notifications
|
||||||
|
* **Valve** - allows for the control of a valve device
|
||||||
|
* **Refresh** - _refresh()_ command for status updates
|
||||||
|
* **Sensor** - detects sensor events
|
||||||
|
|
||||||
|
## Device Health
|
||||||
|
|
||||||
|
FortrezZ Water Valve is polled by the hub.
|
||||||
|
As of hubCore version 0.14.38 the hub sends up reports every 15 minutes regardless of whether the state changed.
|
||||||
|
Device-Watch allows 2 check-in misses from device plus some lag time. So Check-in interval = (2*15 + 2)mins = 32 mins.
|
||||||
|
Not to mention after going OFFLINE when the device is plugged back in, it might take a considerable amount of time for
|
||||||
|
the device to appear as ONLINE again. This is because if this listening device does not respond to two poll requests in a row,
|
||||||
|
it is not polled for 5 minutes by the hub. This can delay up the process of being marked ONLINE by quite some time.
|
||||||
|
|
||||||
|
* __32min__ checkInterval
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the device is out of range.
|
||||||
|
Pairing needs to be tried again by placing the device closer to the hub.
|
||||||
|
Instructions related to pairing, resetting and removing the device from SmartThings can be found in the following link:
|
||||||
|
* [FortrezZ Water Valve Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/202088434-FortrezZ-Water-Valve-Shutoff)
|
||||||
@@ -14,11 +14,13 @@
|
|||||||
metadata {
|
metadata {
|
||||||
definition (name: "Fortrezz Water Valve", namespace: "smartthings", author: "SmartThings") {
|
definition (name: "Fortrezz Water Valve", namespace: "smartthings", author: "SmartThings") {
|
||||||
capability "Actuator"
|
capability "Actuator"
|
||||||
|
capability "Health Check"
|
||||||
capability "Valve"
|
capability "Valve"
|
||||||
capability "Refresh"
|
capability "Refresh"
|
||||||
capability "Sensor"
|
capability "Sensor"
|
||||||
|
|
||||||
fingerprint deviceId: "0x1000", inClusters: "0x25,0x72,0x86,0x71,0x22,0x70"
|
fingerprint deviceId: "0x1000", inClusters: "0x25,0x72,0x86,0x71,0x22,0x70"
|
||||||
|
fingerprint mfr:"0084", prod:"0213", model:"0215", deviceJoinName: "FortrezZ Water Valve"
|
||||||
}
|
}
|
||||||
|
|
||||||
// simulator metadata
|
// simulator metadata
|
||||||
@@ -34,10 +36,10 @@ metadata {
|
|||||||
// tile definitions
|
// tile definitions
|
||||||
tiles {
|
tiles {
|
||||||
standardTile("contact", "device.contact", width: 2, height: 2, canChangeIcon: true) {
|
standardTile("contact", "device.contact", width: 2, height: 2, canChangeIcon: true) {
|
||||||
state "open", label: '${name}', action: "valve.close", icon: "st.valves.water.open", backgroundColor: "#53a7c0", nextState:"closing"
|
state "open", label: '${name}', action: "valve.close", icon: "st.valves.water.open", backgroundColor: "#00A0DC", nextState:"closing"
|
||||||
state "closed", label: '${name}', action: "valve.open", icon: "st.valves.water.closed", backgroundColor: "#e86d13", nextState:"opening"
|
state "closed", label: '${name}', action: "valve.open", icon: "st.valves.water.closed", backgroundColor: "#ffffff", nextState:"opening"
|
||||||
state "opening", label: '${name}', action: "valve.close", icon: "st.valves.water.open", backgroundColor: "#ffe71e"
|
state "opening", label: '${name}', action: "valve.close", icon: "st.valves.water.open", backgroundColor: "#00A0DC"
|
||||||
state "closing", label: '${name}', action: "valve.open", icon: "st.valves.water.closed", backgroundColor: "#ffe71e"
|
state "closing", label: '${name}', action: "valve.open", icon: "st.valves.water.closed", backgroundColor: "#ffffff"
|
||||||
}
|
}
|
||||||
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat") {
|
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat") {
|
||||||
state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh"
|
state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh"
|
||||||
@@ -48,6 +50,16 @@ metadata {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def installed(){
|
||||||
|
// Device-Watch simply pings if no device events received for 32min(checkInterval)
|
||||||
|
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
|
||||||
|
}
|
||||||
|
|
||||||
|
def updated(){
|
||||||
|
// Device-Watch simply pings if no device events received for 32min(checkInterval)
|
||||||
|
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
|
||||||
|
}
|
||||||
|
|
||||||
def parse(String description) {
|
def parse(String description) {
|
||||||
log.trace description
|
log.trace description
|
||||||
def result = null
|
def result = null
|
||||||
@@ -76,6 +88,13 @@ def close() {
|
|||||||
zwave.switchBinaryV1.switchBinarySet(switchValue: 0xFF).format()
|
zwave.switchBinaryV1.switchBinarySet(switchValue: 0xFF).format()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PING is used by Device-Watch in attempt to reach the Device
|
||||||
|
* */
|
||||||
|
def ping() {
|
||||||
|
refresh()
|
||||||
|
}
|
||||||
|
|
||||||
def refresh() {
|
def refresh() {
|
||||||
zwave.switchBinaryV1.switchBinaryGet().format()
|
zwave.switchBinaryV1.switchBinaryGet().format()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,7 @@
|
|||||||
|
|
||||||
standardTile("take", "device.image", width: 1, height: 1, canChangeIcon: false, inactiveLabel: true, canChangeBackground: false) {
|
standardTile("take", "device.image", width: 1, height: 1, canChangeIcon: false, inactiveLabel: true, canChangeBackground: false) {
|
||||||
state "take", label: "Take", action: "Image Capture.take", icon: "st.camera.dropcam", backgroundColor: "#FFFFFF", nextState:"taking"
|
state "take", label: "Take", action: "Image Capture.take", icon: "st.camera.dropcam", backgroundColor: "#FFFFFF", nextState:"taking"
|
||||||
state "taking", label:'Taking', action: "", icon: "st.camera.dropcam", backgroundColor: "#53a7c0"
|
state "taking", label:'Taking', action: "", icon: "st.camera.dropcam", backgroundColor: "#00A0DC"
|
||||||
state "image", label: "Take", action: "Image Capture.take", icon: "st.camera.dropcam", backgroundColor: "#FFFFFF", nextState:"taking"
|
state "image", label: "Take", action: "Image Capture.take", icon: "st.camera.dropcam", backgroundColor: "#FFFFFF", nextState:"taking"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/**
|
/**
|
||||||
* GE Link Bulb
|
* GE Link Bulb
|
||||||
*
|
*
|
||||||
* Copyright 2014 SmartThings
|
* Copyright 2016 SmartThings
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||||
* in compliance with the License. You may obtain a copy of the License at:
|
* in compliance with the License. You may obtain a copy of the License at:
|
||||||
@@ -42,7 +42,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
metadata {
|
metadata {
|
||||||
definition (name: "GE Link Bulb", namespace: "smartthings", author: "SmartThings") {
|
definition (name: "GE Link Bulb", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.light") {
|
||||||
|
|
||||||
capability "Actuator"
|
capability "Actuator"
|
||||||
capability "Configuration"
|
capability "Configuration"
|
||||||
@@ -53,15 +53,17 @@ metadata {
|
|||||||
capability "Polling"
|
capability "Polling"
|
||||||
|
|
||||||
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,1000", outClusters: "0019", manufacturer: "GE_Appliances", model: "ZLL Light", deviceJoinName: "GE Link Bulb"
|
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,1000", outClusters: "0019", manufacturer: "GE_Appliances", model: "ZLL Light", deviceJoinName: "GE Link Bulb"
|
||||||
|
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,1000", outClusters: "0019", manufacturer: "GE", model: "SoftWhite", deviceJoinName: "GE Link Soft White Bulb"
|
||||||
|
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,1000", outClusters: "0019", manufacturer: "GE", model: "Daylight", deviceJoinName: "GE Link Daylight Bulb"
|
||||||
}
|
}
|
||||||
|
|
||||||
// UI tile definitions
|
// UI tile definitions
|
||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
||||||
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
||||||
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#79b821", nextState:"turningOff"
|
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#00a0dc", nextState:"turningOff"
|
||||||
attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#79b821", nextState:"turningOff"
|
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#00a0dc", nextState:"turningOff"
|
||||||
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
}
|
}
|
||||||
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
|
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
|
||||||
@@ -85,7 +87,7 @@ metadata {
|
|||||||
def parse(String description) {
|
def parse(String description) {
|
||||||
def resultMap = zigbee.getEvent(description)
|
def resultMap = zigbee.getEvent(description)
|
||||||
if (resultMap) {
|
if (resultMap) {
|
||||||
if ((resultMap.name == "level" && state.trigger == "setLevel") || resultMap.name != "level") { //doing this to account for weird level reporting bug with GE Link Bulbs
|
if (resultMap.name != "level" || resultMap.value != 0) { // Ignore level reports of 0 sent when bulb turns off
|
||||||
sendEvent(resultMap)
|
sendEvent(resultMap)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -97,7 +99,7 @@ def parse(String description) {
|
|||||||
|
|
||||||
def poll() {
|
def poll() {
|
||||||
def refreshCmds = [
|
def refreshCmds = [
|
||||||
"st wattr 0x${device.deviceNetworkId} 1 8 0x10 0x21 {${state?.dOnOff ?: '0000'}}", "delay 500"
|
"st wattr 0x${device.deviceNetworkId} 1 8 0x10 0x21 {${state?.dOnOff ?: '0000'}}", "delay 2000"
|
||||||
]
|
]
|
||||||
|
|
||||||
return refreshCmds + zigbee.onOffRefresh() + zigbee.levelRefresh()
|
return refreshCmds + zigbee.onOffRefresh() + zigbee.levelRefresh()
|
||||||
@@ -186,25 +188,22 @@ def updated() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def on() {
|
def on() {
|
||||||
state.trigger = "on/off"
|
|
||||||
zigbee.on()
|
zigbee.on()
|
||||||
}
|
}
|
||||||
|
|
||||||
def off() {
|
def off() {
|
||||||
state.trigger = "on/off"
|
|
||||||
zigbee.off()
|
zigbee.off()
|
||||||
}
|
}
|
||||||
|
|
||||||
def refresh() {
|
def refresh() {
|
||||||
def refreshCmds = [
|
def refreshCmds = [
|
||||||
"st wattr 0x${device.deviceNetworkId} 1 8 0x10 0x21 {${state?.dOnOff ?: '0000'}}", "delay 500"
|
"st wattr 0x${device.deviceNetworkId} 1 8 0x10 0x21 {${state?.dOnOff ?: '0000'}}", "delay 2000"
|
||||||
]
|
]
|
||||||
|
|
||||||
return refreshCmds + zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.onOffConfig()
|
return refreshCmds + zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.onOffConfig()
|
||||||
}
|
}
|
||||||
|
|
||||||
def setLevel(value) {
|
def setLevel(value) {
|
||||||
state.trigger = "setLevel"
|
|
||||||
def cmd
|
def cmd
|
||||||
def delayForRefresh = 500
|
def delayForRefresh = 500
|
||||||
if (dimRate && (state?.rate != null)) {
|
if (dimRate && (state?.rate != null)) {
|
||||||
|
|||||||
@@ -1,351 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright 2015 SmartThings
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License. You may obtain a copy of the License at:
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
|
||||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
|
|
||||||
* for the specific language governing permissions and limitations under the License.
|
|
||||||
*
|
|
||||||
* GE/Jasco ZigBee Dimmer
|
|
||||||
*
|
|
||||||
* Author: SmartThings
|
|
||||||
* Date: 2015-07-01
|
|
||||||
*/
|
|
||||||
|
|
||||||
metadata {
|
|
||||||
definition (name: "GE ZigBee Dimmer", namespace: "smartthings", author: "SmartThings") {
|
|
||||||
capability "Switch"
|
|
||||||
capability "Switch Level"
|
|
||||||
capability "Power Meter"
|
|
||||||
capability "Configuration"
|
|
||||||
capability "Refresh"
|
|
||||||
capability "Actuator"
|
|
||||||
capability "Sensor"
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// simulator metadata
|
|
||||||
simulator {
|
|
||||||
// status messages
|
|
||||||
status "on": "on/off: 1"
|
|
||||||
status "off": "on/off: 0"
|
|
||||||
|
|
||||||
// reply messages
|
|
||||||
reply "zcl on-off on": "on/off: 1"
|
|
||||||
reply "zcl on-off off": "on/off: 0"
|
|
||||||
}
|
|
||||||
|
|
||||||
tiles(scale: 2) {
|
|
||||||
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
|
||||||
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
|
||||||
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"turningOff"
|
|
||||||
attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
|
||||||
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"turningOff"
|
|
||||||
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
|
||||||
}
|
|
||||||
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
|
|
||||||
attributeState "level", action:"switch level.setLevel"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
valueTile("level", "device.level", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
|
||||||
state "level", label: 'Level ${currentValue}%'
|
|
||||||
}
|
|
||||||
valueTile("power", "device.power", decoration: "flat", width: 2, height: 2) {
|
|
||||||
state "power", label:'${currentValue} W'
|
|
||||||
}
|
|
||||||
standardTile("refresh", "device.power", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
|
||||||
state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh"
|
|
||||||
}
|
|
||||||
main "switch"
|
|
||||||
details(["switch", "level", "power","levelSliderControl","refresh"])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse incoming device messages to generate events
|
|
||||||
def parse(String description) {
|
|
||||||
log.debug "description is $description"
|
|
||||||
|
|
||||||
def finalResult = isKnownDescription(description)
|
|
||||||
if (finalResult != "false") {
|
|
||||||
log.info finalResult
|
|
||||||
if (finalResult.type == "update") {
|
|
||||||
log.info "$device updates: ${finalResult.value}"
|
|
||||||
}
|
|
||||||
else if (finalResult.type == "power") {
|
|
||||||
def powerValue = (finalResult.value as Integer)/10
|
|
||||||
sendEvent(name: "power", value: powerValue)
|
|
||||||
|
|
||||||
/*
|
|
||||||
Dividing by 10 as the Divisor is 10000 and unit is kW for the device. AttrId: 0302 and 0300. Simplifying to 10
|
|
||||||
|
|
||||||
power level is an integer. The exact power level with correct units needs to be handled in the device type
|
|
||||||
to account for the different Divisor value (AttrId: 0302) and POWER Unit (AttrId: 0300). CLUSTER for simple metering is 0702
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
sendEvent(name: finalResult.type, value: finalResult.value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
log.warn "DID NOT PARSE MESSAGE for description : $description"
|
|
||||||
log.debug parseDescriptionAsMap(description)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Commands to device
|
|
||||||
def zigbeeCommand(cluster, attribute){
|
|
||||||
["st cmd 0x${device.deviceNetworkId} ${endpointId} ${cluster} ${attribute} {}"]
|
|
||||||
}
|
|
||||||
|
|
||||||
def off() {
|
|
||||||
zigbeeCommand("6", "0")
|
|
||||||
}
|
|
||||||
|
|
||||||
def on() {
|
|
||||||
zigbeeCommand("6", "1")
|
|
||||||
}
|
|
||||||
|
|
||||||
def setLevel(value) {
|
|
||||||
value = value as Integer
|
|
||||||
if (value == 0) {
|
|
||||||
off()
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
sendEvent(name: "level", value: value)
|
|
||||||
setLevelWithRate(value, "0000") + ["delay 1000"] + on() //value is between 0 to 100; GE does NOT switch on if OFF
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def refresh() {
|
|
||||||
[
|
|
||||||
"st rattr 0x${device.deviceNetworkId} ${endpointId} 6 0", "delay 500",
|
|
||||||
"st rattr 0x${device.deviceNetworkId} ${endpointId} 8 0", "delay 500",
|
|
||||||
"st rattr 0x${device.deviceNetworkId} ${endpointId} 0x0702 0x0400", "delay 500"
|
|
||||||
]
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
def configure() {
|
|
||||||
onOffConfig() + levelConfig() + powerConfig() + refresh()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private getEndpointId() {
|
|
||||||
new BigInteger(device.endpointId, 16).toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
private hex(value, width=2) {
|
|
||||||
def s = new BigInteger(Math.round(value).toString()).toString(16)
|
|
||||||
while (s.size() < width) {
|
|
||||||
s = "0" + s
|
|
||||||
}
|
|
||||||
s
|
|
||||||
}
|
|
||||||
|
|
||||||
private String swapEndianHex(String hex) {
|
|
||||||
reverseArray(hex.decodeHex()).encodeHex()
|
|
||||||
}
|
|
||||||
|
|
||||||
private Integer convertHexToInt(hex) {
|
|
||||||
Integer.parseInt(hex,16)
|
|
||||||
}
|
|
||||||
|
|
||||||
//Need to reverse array of size 2
|
|
||||||
private byte[] reverseArray(byte[] array) {
|
|
||||||
byte tmp;
|
|
||||||
tmp = array[1];
|
|
||||||
array[1] = array[0];
|
|
||||||
array[0] = tmp;
|
|
||||||
return array
|
|
||||||
}
|
|
||||||
|
|
||||||
def parseDescriptionAsMap(description) {
|
|
||||||
if (description?.startsWith("read attr -")) {
|
|
||||||
(description - "read attr - ").split(",").inject([:]) { map, param ->
|
|
||||||
def nameAndValue = param.split(":")
|
|
||||||
map += [(nameAndValue[0].trim()): nameAndValue[1].trim()]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (description?.startsWith("catchall: ")) {
|
|
||||||
def seg = (description - "catchall: ").split(" ")
|
|
||||||
def zigbeeMap = [:]
|
|
||||||
zigbeeMap += [raw: (description - "catchall: ")]
|
|
||||||
zigbeeMap += [profileId: seg[0]]
|
|
||||||
zigbeeMap += [clusterId: seg[1]]
|
|
||||||
zigbeeMap += [sourceEndpoint: seg[2]]
|
|
||||||
zigbeeMap += [destinationEndpoint: seg[3]]
|
|
||||||
zigbeeMap += [options: seg[4]]
|
|
||||||
zigbeeMap += [messageType: seg[5]]
|
|
||||||
zigbeeMap += [dni: seg[6]]
|
|
||||||
zigbeeMap += [isClusterSpecific: Short.valueOf(seg[7], 16) != 0]
|
|
||||||
zigbeeMap += [isManufacturerSpecific: Short.valueOf(seg[8], 16) != 0]
|
|
||||||
zigbeeMap += [manufacturerId: seg[9]]
|
|
||||||
zigbeeMap += [command: seg[10]]
|
|
||||||
zigbeeMap += [direction: seg[11]]
|
|
||||||
zigbeeMap += [data: seg.size() > 12 ? seg[12].split("").findAll { it }.collate(2).collect {
|
|
||||||
it.join('')
|
|
||||||
} : []]
|
|
||||||
|
|
||||||
zigbeeMap
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def isKnownDescription(description) {
|
|
||||||
if ((description?.startsWith("catchall:")) || (description?.startsWith("read attr -"))) {
|
|
||||||
def descMap = parseDescriptionAsMap(description)
|
|
||||||
if (descMap.cluster == "0006" || descMap.clusterId == "0006") {
|
|
||||||
isDescriptionOnOff(descMap)
|
|
||||||
}
|
|
||||||
else if (descMap.cluster == "0008" || descMap.clusterId == "0008"){
|
|
||||||
isDescriptionLevel(descMap)
|
|
||||||
}
|
|
||||||
else if (descMap.cluster == "0702" || descMap.clusterId == "0702"){
|
|
||||||
isDescriptionPower(descMap)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return "false"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(description?.startsWith("on/off:")) {
|
|
||||||
def switchValue = description?.endsWith("1") ? "on" : "off"
|
|
||||||
return [type: "switch", value : switchValue]
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return "false"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def isDescriptionOnOff(descMap) {
|
|
||||||
def switchValue = "undefined"
|
|
||||||
if (descMap.cluster == "0006") { //cluster info from read attr
|
|
||||||
value = descMap.value
|
|
||||||
if (value == "01"){
|
|
||||||
switchValue = "on"
|
|
||||||
}
|
|
||||||
else if (value == "00"){
|
|
||||||
switchValue = "off"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (descMap.clusterId == "0006") {
|
|
||||||
//cluster info from catch all
|
|
||||||
//command 0B is Default response and the last two bytes are [on/off][success]. on/off=00, success=00
|
|
||||||
//command 01 is Read attr response. the last two bytes are [datatype][value]. boolean datatype=10; on/off value = 01/00
|
|
||||||
if ((descMap.command=="0B" && descMap.raw.endsWith("0100")) || (descMap.command=="01" && descMap.raw.endsWith("1001"))){
|
|
||||||
switchValue = "on"
|
|
||||||
}
|
|
||||||
else if ((descMap.command=="0B" && descMap.raw.endsWith("0000")) || (descMap.command=="01" && descMap.raw.endsWith("1000"))){
|
|
||||||
switchValue = "off"
|
|
||||||
}
|
|
||||||
else if(descMap.command=="07"){
|
|
||||||
return [type: "update", value : "switch (0006) capability configured successfully"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (switchValue != "undefined"){
|
|
||||||
return [type: "switch", value : switchValue]
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return "false"
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//@return - false or "success" or level [0-100]
|
|
||||||
def isDescriptionLevel(descMap) {
|
|
||||||
def dimmerValue = -1
|
|
||||||
if (descMap.cluster == "0008"){
|
|
||||||
//TODO: the message returned with catchall is command 0B with clusterId 0008. That is just a confirmation message
|
|
||||||
def value = convertHexToInt(descMap.value)
|
|
||||||
dimmerValue = Math.round(value * 100 / 255)
|
|
||||||
if(dimmerValue==0 && value > 0) {
|
|
||||||
dimmerValue = 1 //handling for non-zero hex value less than 3
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(descMap.clusterId == "0008") {
|
|
||||||
if(descMap.command=="0B"){
|
|
||||||
return [type: "update", value : "level updated successfully"] //device updating the level change was successful. no value sent.
|
|
||||||
}
|
|
||||||
else if(descMap.command=="07"){
|
|
||||||
return [type: "update", value : "level (0008) capability configured successfully"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dimmerValue != -1){
|
|
||||||
return [type: "level", value : dimmerValue]
|
|
||||||
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return "false"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def isDescriptionPower(descMap) {
|
|
||||||
def powerValue = "undefined"
|
|
||||||
if (descMap.cluster == "0702") {
|
|
||||||
if (descMap.attrId == "0400") {
|
|
||||||
powerValue = convertHexToInt(descMap.value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (descMap.clusterId == "0702") {
|
|
||||||
if(descMap.command=="07"){
|
|
||||||
return [type: "update", value : "power (0702) capability configured successfully"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (powerValue != "undefined"){
|
|
||||||
return [type: "power", value : powerValue]
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return "false"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def onOffConfig() {
|
|
||||||
[
|
|
||||||
"zdo bind 0x${device.deviceNetworkId} 1 ${endpointId} 6 {${device.zigbeeId}} {}", "delay 200",
|
|
||||||
"zcl global send-me-a-report 6 0 0x10 0 600 {01}",
|
|
||||||
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 1500"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
//level config for devices with min reporting interval as 5 seconds and reporting interval if no activity as 1hour (3600s)
|
|
||||||
//min level change is 01
|
|
||||||
def levelConfig() {
|
|
||||||
[
|
|
||||||
"zdo bind 0x${device.deviceNetworkId} 1 ${endpointId} 8 {${device.zigbeeId}} {}", "delay 200",
|
|
||||||
"zcl global send-me-a-report 8 0 0x20 1 3600 {01}",
|
|
||||||
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 1500"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
//power config for devices with min reporting interval as 1 seconds and reporting interval if no activity as 10min (600s)
|
|
||||||
//min change in value is 05
|
|
||||||
def powerConfig() {
|
|
||||||
[
|
|
||||||
//Meter (Power) Reporting
|
|
||||||
"zdo bind 0x${device.deviceNetworkId} 1 ${endpointId} 0x0702 {${device.zigbeeId}} {}", "delay 200",
|
|
||||||
"zcl global send-me-a-report 0x0702 0x0400 0x2A 1 600 {05}",
|
|
||||||
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 1500"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
def setLevelWithRate(level, rate) {
|
|
||||||
if(rate == null){
|
|
||||||
rate = "0000"
|
|
||||||
}
|
|
||||||
level = convertToHexString(level * 255 / 100) //Converting the 0-100 range to 0-FF range in hex
|
|
||||||
["st cmd 0x${device.deviceNetworkId} ${endpointId} 8 4 {$level $rate}"]
|
|
||||||
}
|
|
||||||
|
|
||||||
String convertToHexString(value, width=2) {
|
|
||||||
def s = new BigInteger(Math.round(value).toString()).toString(16)
|
|
||||||
while (s.size() < width) {
|
|
||||||
s = "0" + s
|
|
||||||
}
|
|
||||||
s
|
|
||||||
}
|
|
||||||
@@ -1,284 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright 2015 SmartThings
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License. You may obtain a copy of the License at:
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
|
||||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
|
|
||||||
* for the specific language governing permissions and limitations under the License.
|
|
||||||
*
|
|
||||||
* GE/Jasco ZigBee Switch
|
|
||||||
*
|
|
||||||
* Author: SmartThings
|
|
||||||
* Date: 2015-07-01
|
|
||||||
*/
|
|
||||||
|
|
||||||
metadata {
|
|
||||||
// Automatically generated. Make future change here.
|
|
||||||
definition (name: "GE ZigBee Switch", namespace: "smartthings", author: "SmartThings") {
|
|
||||||
capability "Switch"
|
|
||||||
capability "Power Meter"
|
|
||||||
capability "Configuration"
|
|
||||||
capability "Refresh"
|
|
||||||
capability "Actuator"
|
|
||||||
capability "Sensor"
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// simulator metadata
|
|
||||||
simulator {
|
|
||||||
// status messages
|
|
||||||
status "on": "on/off: 1"
|
|
||||||
status "off": "on/off: 0"
|
|
||||||
|
|
||||||
// reply messages
|
|
||||||
reply "zcl on-off on": "on/off: 1"
|
|
||||||
reply "zcl on-off off": "on/off: 0"
|
|
||||||
}
|
|
||||||
|
|
||||||
tiles(scale: 2) {
|
|
||||||
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
|
||||||
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
|
||||||
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"turningOff"
|
|
||||||
attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
|
||||||
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"turningOff"
|
|
||||||
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
|
||||||
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
|
|
||||||
}
|
|
||||||
valueTile("power", "device.power", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
|
||||||
state "power", label:'${currentValue} Watts'
|
|
||||||
}
|
|
||||||
main "switch"
|
|
||||||
details(["switch", "power", "refresh"])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse incoming device messages to generate events
|
|
||||||
def parse(String description) {
|
|
||||||
log.debug "description is $description"
|
|
||||||
|
|
||||||
def finalResult = isKnownDescription(description)
|
|
||||||
if (finalResult != "false") {
|
|
||||||
log.info finalResult
|
|
||||||
if (finalResult.type == "update") {
|
|
||||||
log.info "$device updates: ${finalResult.value}"
|
|
||||||
}
|
|
||||||
else if (finalResult.type == "power") {
|
|
||||||
def powerValue = (finalResult.value as Integer)/10
|
|
||||||
sendEvent(name: "power", value: powerValue)
|
|
||||||
|
|
||||||
/*
|
|
||||||
Dividing by 10 as the Divisor is 10000 and unit is kW for the device. AttrId: 0302 and 0300. Simplifying to 10
|
|
||||||
|
|
||||||
power level is an integer. The exact power level with correct units needs to be handled in the device type
|
|
||||||
to account for the different Divisor value (AttrId: 0302) and POWER Unit (AttrId: 0300). CLUSTER for simple metering is 0702
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
sendEvent(name: finalResult.type, value: finalResult.value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
log.warn "DID NOT PARSE MESSAGE for description : $description"
|
|
||||||
log.debug parseDescriptionAsMap(description)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Commands to device
|
|
||||||
def zigbeeCommand(cluster, attribute){
|
|
||||||
"st cmd 0x${device.deviceNetworkId} ${endpointId} ${cluster} ${attribute} {}"
|
|
||||||
}
|
|
||||||
|
|
||||||
def off() {
|
|
||||||
zigbeeCommand("6", "0")
|
|
||||||
}
|
|
||||||
|
|
||||||
def on() {
|
|
||||||
zigbeeCommand("6", "1")
|
|
||||||
}
|
|
||||||
|
|
||||||
def refresh() {
|
|
||||||
[
|
|
||||||
"st rattr 0x${device.deviceNetworkId} ${endpointId} 6 0", "delay 500",
|
|
||||||
"st rattr 0x${device.deviceNetworkId} ${endpointId} 8 0", "delay 500",
|
|
||||||
"st rattr 0x${device.deviceNetworkId} ${endpointId} 0x0702 0x0400", "delay 500"
|
|
||||||
]
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
def configure() {
|
|
||||||
onOffConfig() + powerConfig() + refresh()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private getEndpointId() {
|
|
||||||
new BigInteger(device.endpointId, 16).toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
private hex(value, width=2) {
|
|
||||||
def s = new BigInteger(Math.round(value).toString()).toString(16)
|
|
||||||
while (s.size() < width) {
|
|
||||||
s = "0" + s
|
|
||||||
}
|
|
||||||
s
|
|
||||||
}
|
|
||||||
|
|
||||||
private String swapEndianHex(String hex) {
|
|
||||||
reverseArray(hex.decodeHex()).encodeHex()
|
|
||||||
}
|
|
||||||
|
|
||||||
private Integer convertHexToInt(hex) {
|
|
||||||
Integer.parseInt(hex,16)
|
|
||||||
}
|
|
||||||
|
|
||||||
//Need to reverse array of size 2
|
|
||||||
private byte[] reverseArray(byte[] array) {
|
|
||||||
byte tmp;
|
|
||||||
tmp = array[1];
|
|
||||||
array[1] = array[0];
|
|
||||||
array[0] = tmp;
|
|
||||||
return array
|
|
||||||
}
|
|
||||||
|
|
||||||
def parseDescriptionAsMap(description) {
|
|
||||||
if (description?.startsWith("read attr -")) {
|
|
||||||
(description - "read attr - ").split(",").inject([:]) { map, param ->
|
|
||||||
def nameAndValue = param.split(":")
|
|
||||||
map += [(nameAndValue[0].trim()): nameAndValue[1].trim()]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (description?.startsWith("catchall: ")) {
|
|
||||||
def seg = (description - "catchall: ").split(" ")
|
|
||||||
def zigbeeMap = [:]
|
|
||||||
zigbeeMap += [raw: (description - "catchall: ")]
|
|
||||||
zigbeeMap += [profileId: seg[0]]
|
|
||||||
zigbeeMap += [clusterId: seg[1]]
|
|
||||||
zigbeeMap += [sourceEndpoint: seg[2]]
|
|
||||||
zigbeeMap += [destinationEndpoint: seg[3]]
|
|
||||||
zigbeeMap += [options: seg[4]]
|
|
||||||
zigbeeMap += [messageType: seg[5]]
|
|
||||||
zigbeeMap += [dni: seg[6]]
|
|
||||||
zigbeeMap += [isClusterSpecific: Short.valueOf(seg[7], 16) != 0]
|
|
||||||
zigbeeMap += [isManufacturerSpecific: Short.valueOf(seg[8], 16) != 0]
|
|
||||||
zigbeeMap += [manufacturerId: seg[9]]
|
|
||||||
zigbeeMap += [command: seg[10]]
|
|
||||||
zigbeeMap += [direction: seg[11]]
|
|
||||||
zigbeeMap += [data: seg.size() > 12 ? seg[12].split("").findAll { it }.collate(2).collect {
|
|
||||||
it.join('')
|
|
||||||
} : []]
|
|
||||||
|
|
||||||
zigbeeMap
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def isKnownDescription(description) {
|
|
||||||
if ((description?.startsWith("catchall:")) || (description?.startsWith("read attr -"))) {
|
|
||||||
def descMap = parseDescriptionAsMap(description)
|
|
||||||
if (descMap.cluster == "0006" || descMap.clusterId == "0006") {
|
|
||||||
isDescriptionOnOff(descMap)
|
|
||||||
}
|
|
||||||
else if (descMap.cluster == "0702" || descMap.clusterId == "0702"){
|
|
||||||
isDescriptionPower(descMap)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return "false"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(description?.startsWith("on/off:")) {
|
|
||||||
def switchValue = description?.endsWith("1") ? "on" : "off"
|
|
||||||
return [type: "switch", value : switchValue]
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return "false"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def isDescriptionOnOff(descMap) {
|
|
||||||
def switchValue = "undefined"
|
|
||||||
if (descMap.cluster == "0006") { //cluster info from read attr
|
|
||||||
value = descMap.value
|
|
||||||
if (value == "01"){
|
|
||||||
switchValue = "on"
|
|
||||||
}
|
|
||||||
else if (value == "00"){
|
|
||||||
switchValue = "off"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (descMap.clusterId == "0006") {
|
|
||||||
//cluster info from catch all
|
|
||||||
//command 0B is Default response and the last two bytes are [on/off][success]. on/off=00, success=00
|
|
||||||
//command 01 is Read attr response. the last two bytes are [datatype][value]. boolean datatype=10; on/off value = 01/00
|
|
||||||
if ((descMap.command=="0B" && descMap.raw.endsWith("0100")) || (descMap.command=="01" && descMap.raw.endsWith("1001"))){
|
|
||||||
switchValue = "on"
|
|
||||||
}
|
|
||||||
else if ((descMap.command=="0B" && descMap.raw.endsWith("0000")) || (descMap.command=="01" && descMap.raw.endsWith("1000"))){
|
|
||||||
switchValue = "off"
|
|
||||||
}
|
|
||||||
else if(descMap.command=="07"){
|
|
||||||
return [type: "update", value : "switch (0006) capability configured successfully"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (switchValue != "undefined"){
|
|
||||||
return [type: "switch", value : switchValue]
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return "false"
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
def isDescriptionPower(descMap) {
|
|
||||||
def powerValue = "undefined"
|
|
||||||
if (descMap.cluster == "0702") {
|
|
||||||
if (descMap.attrId == "0400") {
|
|
||||||
powerValue = convertHexToInt(descMap.value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (descMap.clusterId == "0702") {
|
|
||||||
if(descMap.command=="07"){
|
|
||||||
return [type: "update", value : "power (0702) capability configured successfully"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (powerValue != "undefined"){
|
|
||||||
return [type: "power", value : powerValue]
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return "false"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def onOffConfig() {
|
|
||||||
[
|
|
||||||
"zdo bind 0x${device.deviceNetworkId} 1 ${endpointId} 6 {${device.zigbeeId}} {}", "delay 200",
|
|
||||||
"zcl global send-me-a-report 6 0 0x10 0 600 {01}",
|
|
||||||
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 1500"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
//power config for devices with min reporting interval as 1 seconds and reporting interval if no activity as 10min (600s)
|
|
||||||
//min change in value is 05
|
|
||||||
def powerConfig() {
|
|
||||||
[
|
|
||||||
//Meter (Power) Reporting
|
|
||||||
"zdo bind 0x${device.deviceNetworkId} 1 ${endpointId} 0x0702 {${device.zigbeeId}} {}", "delay 200",
|
|
||||||
"zcl global send-me-a-report 0x0702 0x0400 0x2A 1 600 {05}",
|
|
||||||
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 1500"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
String convertToHexString(value, width=2) {
|
|
||||||
def s = new BigInteger(Math.round(value).toString()).toString(16)
|
|
||||||
while (s.size() < width) {
|
|
||||||
s = "0" + s
|
|
||||||
}
|
|
||||||
s
|
|
||||||
}
|
|
||||||
+2
-2
@@ -31,7 +31,7 @@ metadata {
|
|||||||
tileAttribute("sessionStatus", key: "PRIMARY_CONTROL") {
|
tileAttribute("sessionStatus", key: "PRIMARY_CONTROL") {
|
||||||
attributeState "cancelled", action: "timed session.start", icon: "http://f.cl.ly/items/322n181j2K3f281r2s0A/playbutton.png", backgroundColor: "#ffffff", nextState: "running"
|
attributeState "cancelled", action: "timed session.start", icon: "http://f.cl.ly/items/322n181j2K3f281r2s0A/playbutton.png", backgroundColor: "#ffffff", nextState: "running"
|
||||||
attributeState "stopped", action: "timed session.start", icon: "http://f.cl.ly/items/322n181j2K3f281r2s0A/playbutton.png", backgroundColor: "#ffffff", nextState: "cancelled"
|
attributeState "stopped", action: "timed session.start", icon: "http://f.cl.ly/items/322n181j2K3f281r2s0A/playbutton.png", backgroundColor: "#ffffff", nextState: "cancelled"
|
||||||
attributeState "running", action: "timed session.stop", icon: "http://f.cl.ly/items/0B3y3p2V3X2l3P3y3W09/stopbutton.png", backgroundColor: "#79b821", nextState: "cancelled"
|
attributeState "running", action: "timed session.stop", icon: "http://f.cl.ly/items/0B3y3p2V3X2l3P3y3W09/stopbutton.png", backgroundColor: "#00A0DC", nextState: "cancelled"
|
||||||
}
|
}
|
||||||
tileAttribute("timeRemaining", key: "SECONDARY_CONTROL") {
|
tileAttribute("timeRemaining", key: "SECONDARY_CONTROL") {
|
||||||
attributeState "timeRemaining", label:'${currentValue} remaining'
|
attributeState "timeRemaining", label:'${currentValue} remaining'
|
||||||
@@ -45,7 +45,7 @@ metadata {
|
|||||||
standardTile("sessionStatusTile", "sessionStatus", width: 1, height: 1, canChangeIcon: true) {
|
standardTile("sessionStatusTile", "sessionStatus", width: 1, height: 1, canChangeIcon: true) {
|
||||||
state "cancelled", label: "Stopped", action: "timed session.start", backgroundColor: "#ffffff", icon: "http://f.cl.ly/items/1J1g0H2P0S1G1f2O1s1s/icon.png"
|
state "cancelled", label: "Stopped", action: "timed session.start", backgroundColor: "#ffffff", icon: "http://f.cl.ly/items/1J1g0H2P0S1G1f2O1s1s/icon.png"
|
||||||
state "stopped", label: "Stopped", action: "timed session.start", backgroundColor: "#ffffff", icon: "http://f.cl.ly/items/1J1g0H2P0S1G1f2O1s1s/icon.png"
|
state "stopped", label: "Stopped", action: "timed session.start", backgroundColor: "#ffffff", icon: "http://f.cl.ly/items/1J1g0H2P0S1G1f2O1s1s/icon.png"
|
||||||
state "running", label: "Running", action: "timed session.stop", backgroundColor: "#79b821", icon: "http://f.cl.ly/items/1J1g0H2P0S1G1f2O1s1s/icon.png"
|
state "running", label: "Running", action: "timed session.stop", backgroundColor: "#00A0DC", icon: "http://f.cl.ly/items/1J1g0H2P0S1G1f2O1s1s/icon.png"
|
||||||
}
|
}
|
||||||
|
|
||||||
// duration
|
// duration
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ metadata {
|
|||||||
tiles {
|
tiles {
|
||||||
standardTile("button", "device.switch", width: 2, height: 2, canChangeIcon: true) {
|
standardTile("button", "device.switch", width: 2, height: 2, canChangeIcon: true) {
|
||||||
state "off", label: 'Off', action: "switch.on", icon: "st.harmony.harmony-hub-icon", backgroundColor: "#ffffff", nextState: "on"
|
state "off", label: 'Off', action: "switch.on", icon: "st.harmony.harmony-hub-icon", backgroundColor: "#ffffff", nextState: "on"
|
||||||
state "on", label: 'On', action: "switch.off", icon: "st.harmony.harmony-hub-icon", backgroundColor: "#79b821", nextState: "off"
|
state "on", label: 'On', action: "switch.off", icon: "st.harmony.harmony-hub-icon", backgroundColor: "#00A0DC", nextState: "off"
|
||||||
}
|
}
|
||||||
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat") {
|
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat") {
|
||||||
state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh"
|
state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh"
|
||||||
|
|||||||
@@ -39,8 +39,8 @@ metadata {
|
|||||||
|
|
||||||
tiles {
|
tiles {
|
||||||
standardTile("motion", "device.motion", width: 2, height: 2) {
|
standardTile("motion", "device.motion", width: 2, height: 2) {
|
||||||
state "active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#53a7c0"
|
state "active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#00A0DC"
|
||||||
state "inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#ffffff"
|
state "inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#cccccc"
|
||||||
}
|
}
|
||||||
valueTile("temperature", "device.temperature", inactiveLabel: false) {
|
valueTile("temperature", "device.temperature", inactiveLabel: false) {
|
||||||
state "temperature", label:'${currentValue}°',
|
state "temperature", label:'${currentValue}°',
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ metadata {
|
|||||||
capability "Switch"
|
capability "Switch"
|
||||||
capability "Refresh"
|
capability "Refresh"
|
||||||
capability "Sensor"
|
capability "Sensor"
|
||||||
|
capability "Health Check"
|
||||||
|
capability "Light"
|
||||||
|
|
||||||
command "setAdjustedColor"
|
command "setAdjustedColor"
|
||||||
command "reset"
|
command "reset"
|
||||||
@@ -29,24 +31,21 @@ metadata {
|
|||||||
tiles (scale: 2){
|
tiles (scale: 2){
|
||||||
multiAttributeTile(name:"rich-control", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
multiAttributeTile(name:"rich-control", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
||||||
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
||||||
attributeState "on", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff"
|
attributeState "on", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#00A0DC", nextState:"turningOff"
|
||||||
attributeState "off", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
|
attributeState "off", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff"
|
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#00A0DC", nextState:"turningOff"
|
||||||
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
|
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
}
|
}
|
||||||
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
|
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
|
||||||
attributeState "level", action:"switch level.setLevel", range:"(0..100)"
|
attributeState "level", action:"switch level.setLevel", range:"(0..100)"
|
||||||
}
|
}
|
||||||
tileAttribute ("device.level", key: "SECONDARY_CONTROL") {
|
|
||||||
attributeState "level", label: 'Level ${currentValue}%'
|
|
||||||
}
|
|
||||||
tileAttribute ("device.color", key: "COLOR_CONTROL") {
|
tileAttribute ("device.color", key: "COLOR_CONTROL") {
|
||||||
attributeState "color", action:"setAdjustedColor"
|
attributeState "color", action:"setAdjustedColor"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
standardTile("reset", "device.reset", height: 2, width: 2, inactiveLabel: false, decoration: "flat") {
|
standardTile("reset", "device.reset", height: 2, width: 2, inactiveLabel: false, decoration: "flat") {
|
||||||
state "default", label:"Reset Color", action:"reset", icon:"st.lights.philips.hue-single"
|
state "default", label:"Reset To White", action:"reset", icon:"st.lights.philips.hue-single"
|
||||||
}
|
}
|
||||||
|
|
||||||
standardTile("refresh", "device.refresh", height: 2, width: 2, inactiveLabel: false, decoration: "flat") {
|
standardTile("refresh", "device.refresh", height: 2, width: 2, inactiveLabel: false, decoration: "flat") {
|
||||||
@@ -54,10 +53,24 @@ metadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
main(["rich-control"])
|
main(["rich-control"])
|
||||||
details(["rich-control", "colorTempSliderControl", "colorTemp", "reset", "refresh"])
|
details(["rich-control", "reset", "refresh"])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def initialize() {
|
||||||
|
sendEvent(name: "DeviceWatch-Enroll", value: "{\"protocol\": \"LAN\", \"scheme\":\"untracked\", \"hubHardwareId\": \"${device.hub.hardwareID}\"}", displayed: false)
|
||||||
|
}
|
||||||
|
|
||||||
|
void installed() {
|
||||||
|
log.debug "installed()"
|
||||||
|
initialize()
|
||||||
|
}
|
||||||
|
|
||||||
|
def updated() {
|
||||||
|
log.debug "updated()"
|
||||||
|
initialize()
|
||||||
|
}
|
||||||
|
|
||||||
// parse events into attributes
|
// parse events into attributes
|
||||||
def parse(description) {
|
def parse(description) {
|
||||||
log.debug "parse() - $description"
|
log.debug "parse() - $description"
|
||||||
@@ -78,118 +91,78 @@ def parse(description) {
|
|||||||
// handle commands
|
// handle commands
|
||||||
void on() {
|
void on() {
|
||||||
log.trace parent.on(this)
|
log.trace parent.on(this)
|
||||||
sendEvent(name: "switch", value: "on")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void off() {
|
void off() {
|
||||||
log.trace parent.off(this)
|
log.trace parent.off(this)
|
||||||
sendEvent(name: "switch", value: "off")
|
|
||||||
}
|
|
||||||
|
|
||||||
void nextLevel() {
|
|
||||||
def level = device.latestValue("level") as Integer ?: 0
|
|
||||||
if (level <= 100) {
|
|
||||||
level = Math.min(25 * (Math.round(level / 25) + 1), 100) as Integer
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
level = 25
|
|
||||||
}
|
|
||||||
setLevel(level)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setLevel(percent) {
|
void setLevel(percent) {
|
||||||
log.debug "Executing 'setLevel'"
|
log.debug "Executing 'setLevel'"
|
||||||
if (verifyPercent(percent)) {
|
if (verifyPercent(percent)) {
|
||||||
parent.setLevel(this, percent)
|
log.trace parent.setLevel(this, percent)
|
||||||
sendEvent(name: "level", value: percent, descriptionText: "Level has changed to ${percent}%")
|
|
||||||
sendEvent(name: "switch", value: "on")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setSaturation(percent) {
|
void setSaturation(percent) {
|
||||||
log.debug "Executing 'setSaturation'"
|
log.debug "Executing 'setSaturation'"
|
||||||
if (verifyPercent(percent)) {
|
if (verifyPercent(percent)) {
|
||||||
parent.setSaturation(this, percent)
|
log.trace parent.setSaturation(this, percent)
|
||||||
sendEvent(name: "saturation", value: percent, displayed: false)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setHue(percent) {
|
void setHue(percent) {
|
||||||
log.debug "Executing 'setHue'"
|
log.debug "Executing 'setHue'"
|
||||||
if (verifyPercent(percent)) {
|
if (verifyPercent(percent)) {
|
||||||
parent.setHue(this, percent)
|
log.trace parent.setHue(this, percent)
|
||||||
sendEvent(name: "hue", value: percent, displayed: false)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setColor(value) {
|
void setColor(value) {
|
||||||
log.debug "setColor: ${value}, $this"
|
|
||||||
def events = []
|
def events = []
|
||||||
def validValues = [:]
|
def validValues = [:]
|
||||||
|
|
||||||
if (verifyPercent(value.hue)) {
|
if (verifyPercent(value.hue)) {
|
||||||
events << createEvent(name: "hue", value: value.hue, displayed: false)
|
|
||||||
validValues.hue = value.hue
|
validValues.hue = value.hue
|
||||||
}
|
}
|
||||||
if (verifyPercent(value.saturation)) {
|
if (verifyPercent(value.saturation)) {
|
||||||
events << createEvent(name: "saturation", value: value.saturation, displayed: false)
|
|
||||||
validValues.saturation = value.saturation
|
validValues.saturation = value.saturation
|
||||||
}
|
}
|
||||||
if (value.hex != null) {
|
if (value.hex != null) {
|
||||||
if (value.hex ==~ /^\#([A-Fa-f0-9]){6}$/) {
|
if (value.hex ==~ /^\#([A-Fa-f0-9]){6}$/) {
|
||||||
events << createEvent(name: "color", value: value.hex)
|
|
||||||
validValues.hex = value.hex
|
validValues.hex = value.hex
|
||||||
} else {
|
} else {
|
||||||
log.warn "$value.hex is not a valid color"
|
log.warn "$value.hex is not a valid color"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (verifyPercent(value.level)) {
|
if (verifyPercent(value.level)) {
|
||||||
events << createEvent(name: "level", value: value.level, descriptionText: "Level has changed to ${value.level}%")
|
|
||||||
validValues.level = value.level
|
validValues.level = value.level
|
||||||
}
|
}
|
||||||
if (value.switch == "off" || (value.level != null && value.level <= 0)) {
|
if (value.switch == "off" || (value.level != null && value.level <= 0)) {
|
||||||
events << createEvent(name: "switch", value: "off")
|
|
||||||
validValues.switch = "off"
|
validValues.switch = "off"
|
||||||
} else {
|
} else {
|
||||||
events << createEvent(name: "switch", value: "on")
|
|
||||||
validValues.switch = "on"
|
validValues.switch = "on"
|
||||||
}
|
}
|
||||||
if (!events.isEmpty()) {
|
if (!validValues.isEmpty()) {
|
||||||
parent.setColor(this, validValues)
|
log.trace parent.setColor(this, validValues)
|
||||||
}
|
|
||||||
events.each {
|
|
||||||
sendEvent(it)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void reset() {
|
void reset() {
|
||||||
log.debug "Executing 'reset'"
|
log.debug "Executing 'reset'"
|
||||||
def value = [level:100, saturation:56, hue:23]
|
def value = [hue:20, saturation:2]
|
||||||
setAdjustedColor(value)
|
setAdjustedColor(value)
|
||||||
parent.poll()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setAdjustedColor(value) {
|
void setAdjustedColor(value) {
|
||||||
if (value) {
|
if (value) {
|
||||||
log.trace "setAdjustedColor: ${value}"
|
log.trace "setAdjustedColor: ${value}"
|
||||||
def adjusted = value + [:]
|
def adjusted = value + [:]
|
||||||
adjusted.hue = adjustOutgoingHue(value.hue)
|
|
||||||
// Needed because color picker always sends 100
|
// Needed because color picker always sends 100
|
||||||
adjusted.level = null
|
adjusted.level = null
|
||||||
setColor(adjusted)
|
setColor(adjusted)
|
||||||
} else {
|
} else {
|
||||||
log.warn "Invalid color input"
|
log.warn "Invalid color input $value"
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void setColorTemperature(value) {
|
|
||||||
if (value) {
|
|
||||||
log.trace "setColorTemperature: ${value}k"
|
|
||||||
parent.setColorTemperature(this, value)
|
|
||||||
sendEvent(name: "colorTemperature", value: value)
|
|
||||||
sendEvent(name: "switch", value: "on")
|
|
||||||
} else {
|
|
||||||
log.warn "Invalid color temperature"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,22 +171,6 @@ void refresh() {
|
|||||||
parent.manualRefresh()
|
parent.manualRefresh()
|
||||||
}
|
}
|
||||||
|
|
||||||
def adjustOutgoingHue(percent) {
|
|
||||||
def adjusted = percent
|
|
||||||
if (percent > 31) {
|
|
||||||
if (percent < 63.0) {
|
|
||||||
adjusted = percent + (7 * (percent -30 ) / 32)
|
|
||||||
}
|
|
||||||
else if (percent < 73.0) {
|
|
||||||
adjusted = 69 + (5 * (percent - 62) / 10)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
adjusted = percent + (2 * (100 - percent) / 28)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log.info "percent: $percent, adjusted: $adjusted"
|
|
||||||
adjusted
|
|
||||||
}
|
|
||||||
|
|
||||||
def verifyPercent(percent) {
|
def verifyPercent(percent) {
|
||||||
if (percent == null)
|
if (percent == null)
|
||||||
@@ -225,3 +182,4 @@ def verifyPercent(percent) {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,8 +7,16 @@
|
|||||||
metadata {
|
metadata {
|
||||||
// Automatically generated. Make future change here.
|
// Automatically generated. Make future change here.
|
||||||
definition (name: "Hue Bridge", namespace: "smartthings", author: "SmartThings") {
|
definition (name: "Hue Bridge", namespace: "smartthings", author: "SmartThings") {
|
||||||
attribute "serialNumber", "string"
|
capability "Bridge"
|
||||||
|
capability "Health Check"
|
||||||
|
|
||||||
attribute "networkAddress", "string"
|
attribute "networkAddress", "string"
|
||||||
|
// Used to indicate if bridge is reachable or not, i.e. is the bridge connected to the network
|
||||||
|
// Possible values "Online" or "Offline"
|
||||||
|
attribute "status", "string"
|
||||||
|
// Id is the number on the back of the hub, Hue uses last six digits of Mac address
|
||||||
|
// This is also used in the Hue application as ID
|
||||||
|
attribute "idNumber", "string"
|
||||||
}
|
}
|
||||||
|
|
||||||
simulator {
|
simulator {
|
||||||
@@ -17,25 +25,40 @@ metadata {
|
|||||||
|
|
||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
multiAttributeTile(name:"rich-control"){
|
multiAttributeTile(name:"rich-control"){
|
||||||
tileAttribute ("", key: "PRIMARY_CONTROL") {
|
tileAttribute ("device.status", key: "PRIMARY_CONTROL") {
|
||||||
attributeState "default", label: "Hue Bridge", action: "", icon: "st.Lighting.light99-hue", backgroundColor: "#F3C200"
|
attributeState "Offline", label: '${currentValue}', action: "", icon: "st.Lighting.light99-hue", backgroundColor: "#ffffff"
|
||||||
}
|
attributeState "Online", label: '${currentValue}', action: "", icon: "st.Lighting.light99-hue", backgroundColor: "#00A0DC"
|
||||||
tileAttribute ("serialNumber", key: "SECONDARY_CONTROL") {
|
|
||||||
attributeState "default", label:'SN: ${currentValue}'
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
valueTile("serialNumber", "device.serialNumber", decoration: "flat", height: 1, width: 2, inactiveLabel: false) {
|
valueTile("doNotRemove", "v", decoration: "flat", height: 2, width: 6, inactiveLabel: false) {
|
||||||
state "default", label:'SN: ${currentValue}'
|
state "default", label:'If removed, Hue lights will not work properly'
|
||||||
}
|
}
|
||||||
valueTile("networkAddress", "device.networkAddress", decoration: "flat", height: 2, width: 4, inactiveLabel: false) {
|
valueTile("idNumber", "device.idNumber", decoration: "flat", height: 2, width: 6, inactiveLabel: false) {
|
||||||
state "default", label:'${currentValue}', height: 1, width: 2, inactiveLabel: false
|
state "default", label:'ID: ${currentValue}'
|
||||||
|
}
|
||||||
|
valueTile("networkAddress", "device.networkAddress", decoration: "flat", height: 2, width: 6, inactiveLabel: false) {
|
||||||
|
state "default", label:'IP: ${currentValue}'
|
||||||
}
|
}
|
||||||
|
|
||||||
main (["rich-control"])
|
main (["rich-control"])
|
||||||
details(["rich-control", "networkAddress"])
|
details(["rich-control", "doNotRemove", "idNumber", "networkAddress"])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def initialize() {
|
||||||
|
sendEvent(name: "DeviceWatch-Enroll", value: "{\"protocol\": \"LAN\", \"scheme\":\"untracked\", \"hubHardwareId\": \"${device.hub.hardwareID}\"}", displayed: false)
|
||||||
|
}
|
||||||
|
|
||||||
|
void installed() {
|
||||||
|
log.debug "installed()"
|
||||||
|
initialize()
|
||||||
|
}
|
||||||
|
|
||||||
|
def updated() {
|
||||||
|
log.debug "updated()"
|
||||||
|
initialize()
|
||||||
|
}
|
||||||
|
|
||||||
// parse events into attributes
|
// parse events into attributes
|
||||||
def parse(description) {
|
def parse(description) {
|
||||||
log.debug "Parsing '${description}'"
|
log.debug "Parsing '${description}'"
|
||||||
@@ -64,13 +87,8 @@ def parse(description) {
|
|||||||
def bulbs = new groovy.json.JsonSlurper().parseText(msg.body)
|
def bulbs = new groovy.json.JsonSlurper().parseText(msg.body)
|
||||||
if (bulbs.state) {
|
if (bulbs.state) {
|
||||||
log.info "Bridge response: $msg.body"
|
log.info "Bridge response: $msg.body"
|
||||||
} else {
|
|
||||||
// Sending Bulbs List to parent"
|
|
||||||
if (parent.state.inBulbDiscovery)
|
|
||||||
log.info parent.bulbListHandler(device.hub.id, msg.body)
|
|
||||||
}
|
}
|
||||||
}
|
} else if (contentType?.contains("xml")) {
|
||||||
else if (contentType?.contains("xml")) {
|
|
||||||
log.debug "HUE BRIDGE ALREADY PRESENT"
|
log.debug "HUE BRIDGE ALREADY PRESENT"
|
||||||
parent.hubVerification(device.hub.id, msg.body)
|
parent.hubVerification(device.hub.id, msg.body)
|
||||||
}
|
}
|
||||||
@@ -79,3 +97,4 @@ def parse(description) {
|
|||||||
}
|
}
|
||||||
results
|
results
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ metadata {
|
|||||||
capability "Switch"
|
capability "Switch"
|
||||||
capability "Refresh"
|
capability "Refresh"
|
||||||
capability "Sensor"
|
capability "Sensor"
|
||||||
|
capability "Health Check"
|
||||||
|
capability "Light"
|
||||||
|
|
||||||
command "setAdjustedColor"
|
command "setAdjustedColor"
|
||||||
command "reset"
|
command "reset"
|
||||||
@@ -30,17 +32,14 @@ metadata {
|
|||||||
tiles (scale: 2){
|
tiles (scale: 2){
|
||||||
multiAttributeTile(name:"rich-control", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
multiAttributeTile(name:"rich-control", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
||||||
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
||||||
attributeState "on", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff"
|
attributeState "on", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#00A0DC", nextState:"turningOff"
|
||||||
attributeState "off", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
|
attributeState "off", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff"
|
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#00A0DC", nextState:"turningOff"
|
||||||
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
|
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
}
|
}
|
||||||
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
|
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
|
||||||
attributeState "level", action:"switch level.setLevel", range:"(0..100)"
|
attributeState "level", action:"switch level.setLevel", range:"(0..100)"
|
||||||
}
|
}
|
||||||
tileAttribute ("device.level", key: "SECONDARY_CONTROL") {
|
|
||||||
attributeState "level", label: 'Level ${currentValue}%'
|
|
||||||
}
|
|
||||||
tileAttribute ("device.color", key: "COLOR_CONTROL") {
|
tileAttribute ("device.color", key: "COLOR_CONTROL") {
|
||||||
attributeState "color", action:"setAdjustedColor"
|
attributeState "color", action:"setAdjustedColor"
|
||||||
}
|
}
|
||||||
@@ -51,11 +50,11 @@ metadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
valueTile("colorTemp", "device.colorTemperature", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
valueTile("colorTemp", "device.colorTemperature", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
||||||
state "colorTemperature", label: '${currentValue} K'
|
state "colorTemperature", label: 'WHITES'
|
||||||
}
|
}
|
||||||
|
|
||||||
standardTile("reset", "device.reset", height: 2, width: 2, inactiveLabel: false, decoration: "flat") {
|
standardTile("reset", "device.reset", height: 2, width: 2, inactiveLabel: false, decoration: "flat") {
|
||||||
state "default", label:"Reset Color", action:"reset", icon:"st.lights.philips.hue-single"
|
state "default", label:"Reset To White", action:"reset", icon:"st.lights.philips.hue-single"
|
||||||
}
|
}
|
||||||
|
|
||||||
standardTile("refresh", "device.refresh", height: 2, width: 2, inactiveLabel: false, decoration: "flat") {
|
standardTile("refresh", "device.refresh", height: 2, width: 2, inactiveLabel: false, decoration: "flat") {
|
||||||
@@ -67,6 +66,20 @@ metadata {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def initialize() {
|
||||||
|
sendEvent(name: "DeviceWatch-Enroll", value: "{\"protocol\": \"LAN\", \"scheme\":\"untracked\", \"hubHardwareId\": \"${device.hub.hardwareID}\"}", displayed: false)
|
||||||
|
}
|
||||||
|
|
||||||
|
void installed() {
|
||||||
|
log.debug "installed()"
|
||||||
|
initialize()
|
||||||
|
}
|
||||||
|
|
||||||
|
def updated() {
|
||||||
|
log.debug "updated()"
|
||||||
|
initialize()
|
||||||
|
}
|
||||||
|
|
||||||
// parse events into attributes
|
// parse events into attributes
|
||||||
def parse(description) {
|
def parse(description) {
|
||||||
log.debug "parse() - $description"
|
log.debug "parse() - $description"
|
||||||
@@ -87,141 +100,92 @@ def parse(description) {
|
|||||||
// handle commands
|
// handle commands
|
||||||
void on() {
|
void on() {
|
||||||
log.trace parent.on(this)
|
log.trace parent.on(this)
|
||||||
sendEvent(name: "switch", value: "on")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void off() {
|
void off() {
|
||||||
log.trace parent.off(this)
|
log.trace parent.off(this)
|
||||||
sendEvent(name: "switch", value: "off")
|
|
||||||
}
|
|
||||||
|
|
||||||
void nextLevel() {
|
|
||||||
def level = device.latestValue("level") as Integer ?: 0
|
|
||||||
if (level <= 100) {
|
|
||||||
level = Math.min(25 * (Math.round(level / 25) + 1), 100) as Integer
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
level = 25
|
|
||||||
}
|
|
||||||
setLevel(level)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setLevel(percent) {
|
void setLevel(percent) {
|
||||||
log.debug "Executing 'setLevel'"
|
log.debug "Executing 'setLevel'"
|
||||||
if (verifyPercent(percent)) {
|
if (verifyPercent(percent)) {
|
||||||
parent.setLevel(this, percent)
|
log.trace parent.setLevel(this, percent)
|
||||||
sendEvent(name: "level", value: percent, descriptionText: "Level has changed to ${percent}%")
|
|
||||||
sendEvent(name: "switch", value: "on")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setSaturation(percent) {
|
void setSaturation(percent) {
|
||||||
log.debug "Executing 'setSaturation'"
|
log.debug "Executing 'setSaturation'"
|
||||||
if (verifyPercent(percent)) {
|
if (verifyPercent(percent)) {
|
||||||
parent.setSaturation(this, percent)
|
log.trace parent.setSaturation(this, percent)
|
||||||
sendEvent(name: "saturation", value: percent, displayed: false)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setHue(percent) {
|
void setHue(percent) {
|
||||||
log.debug "Executing 'setHue'"
|
log.debug "Executing 'setHue'"
|
||||||
if (verifyPercent(percent)) {
|
if (verifyPercent(percent)) {
|
||||||
parent.setHue(this, percent)
|
log.trace parent.setHue(this, percent)
|
||||||
sendEvent(name: "hue", value: percent, displayed: false)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setColor(value) {
|
void setColor(value) {
|
||||||
log.debug "setColor: ${value}, $this"
|
|
||||||
def events = []
|
def events = []
|
||||||
def validValues = [:]
|
def validValues = [:]
|
||||||
|
|
||||||
if (verifyPercent(value.hue)) {
|
if (verifyPercent(value.hue)) {
|
||||||
events << createEvent(name: "hue", value: value.hue, displayed: false)
|
|
||||||
validValues.hue = value.hue
|
validValues.hue = value.hue
|
||||||
}
|
}
|
||||||
if (verifyPercent(value.saturation)) {
|
if (verifyPercent(value.saturation)) {
|
||||||
events << createEvent(name: "saturation", value: value.saturation, displayed: false)
|
|
||||||
validValues.saturation = value.saturation
|
validValues.saturation = value.saturation
|
||||||
}
|
}
|
||||||
if (value.hex != null) {
|
if (value.hex != null) {
|
||||||
if (value.hex ==~ /^\#([A-Fa-f0-9]){6}$/) {
|
if (value.hex ==~ /^\#([A-Fa-f0-9]){6}$/) {
|
||||||
events << createEvent(name: "color", value: value.hex)
|
|
||||||
validValues.hex = value.hex
|
validValues.hex = value.hex
|
||||||
} else {
|
} else {
|
||||||
log.warn "$value.hex is not a valid color"
|
log.warn "$value.hex is not a valid color"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (verifyPercent(value.level)) {
|
if (verifyPercent(value.level)) {
|
||||||
events << createEvent(name: "level", value: value.level, descriptionText: "Level has changed to ${value.level}%")
|
|
||||||
validValues.level = value.level
|
validValues.level = value.level
|
||||||
}
|
}
|
||||||
if (value.switch == "off" || (value.level != null && value.level <= 0)) {
|
if (value.switch == "off" || (value.level != null && value.level <= 0)) {
|
||||||
events << createEvent(name: "switch", value: "off")
|
|
||||||
validValues.switch = "off"
|
validValues.switch = "off"
|
||||||
} else {
|
} else {
|
||||||
events << createEvent(name: "switch", value: "on")
|
|
||||||
validValues.switch = "on"
|
validValues.switch = "on"
|
||||||
}
|
}
|
||||||
if (!events.isEmpty()) {
|
if (!validValues.isEmpty()) {
|
||||||
parent.setColor(this, validValues)
|
log.trace parent.setColor(this, validValues)
|
||||||
}
|
|
||||||
events.each {
|
|
||||||
sendEvent(it)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void reset() {
|
void reset() {
|
||||||
log.debug "Executing 'reset'"
|
log.debug "Executing 'reset'"
|
||||||
def value = [level:100, saturation:56, hue:23]
|
setColorTemperature(4000)
|
||||||
setAdjustedColor(value)
|
|
||||||
parent.poll()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setAdjustedColor(value) {
|
void setAdjustedColor(value) {
|
||||||
if (value) {
|
if (value) {
|
||||||
log.trace "setAdjustedColor: ${value}"
|
log.trace "setAdjustedColor: ${value}"
|
||||||
def adjusted = value + [:]
|
def adjusted = value + [:]
|
||||||
adjusted.hue = adjustOutgoingHue(value.hue)
|
|
||||||
// Needed because color picker always sends 100
|
// Needed because color picker always sends 100
|
||||||
adjusted.level = null
|
adjusted.level = null
|
||||||
setColor(adjusted)
|
setColor(adjusted)
|
||||||
} else {
|
} else {
|
||||||
log.warn "Invalid color input"
|
log.warn "Invalid color input $value"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setColorTemperature(value) {
|
void setColorTemperature(value) {
|
||||||
if (value) {
|
if (value) {
|
||||||
log.trace "setColorTemperature: ${value}k"
|
log.trace "setColorTemperature: ${value}k"
|
||||||
parent.setColorTemperature(this, value)
|
log.trace parent.setColorTemperature(this, value)
|
||||||
sendEvent(name: "colorTemperature", value: value)
|
|
||||||
sendEvent(name: "switch", value: "on")
|
|
||||||
} else {
|
} else {
|
||||||
log.warn "Invalid color temperature"
|
log.warn "Invalid color temperature $value"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void refresh() {
|
void refresh() {
|
||||||
log.debug "Executing 'refresh'"
|
log.debug "Executing 'refresh'"
|
||||||
parent.manualRefresh()
|
parent?.manualRefresh()
|
||||||
}
|
|
||||||
|
|
||||||
def adjustOutgoingHue(percent) {
|
|
||||||
def adjusted = percent
|
|
||||||
if (percent > 31) {
|
|
||||||
if (percent < 63.0) {
|
|
||||||
adjusted = percent + (7 * (percent -30 ) / 32)
|
|
||||||
}
|
|
||||||
else if (percent < 73.0) {
|
|
||||||
adjusted = 69 + (5 * (percent - 62) / 10)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
adjusted = percent + (2 * (100 - percent) / 28)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log.info "percent: $percent, adjusted: $adjusted"
|
|
||||||
adjusted
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def verifyPercent(percent) {
|
def verifyPercent(percent) {
|
||||||
@@ -234,3 +198,4 @@ def verifyPercent(percent) {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ metadata {
|
|||||||
capability "Switch"
|
capability "Switch"
|
||||||
capability "Refresh"
|
capability "Refresh"
|
||||||
capability "Sensor"
|
capability "Sensor"
|
||||||
|
capability "Health Check"
|
||||||
|
capability "Light"
|
||||||
|
|
||||||
command "refresh"
|
command "refresh"
|
||||||
}
|
}
|
||||||
@@ -25,17 +27,14 @@ metadata {
|
|||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
multiAttributeTile(name:"rich-control", type: "lighting", canChangeIcon: true){
|
multiAttributeTile(name:"rich-control", type: "lighting", canChangeIcon: true){
|
||||||
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
||||||
attributeState "on", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff"
|
attributeState "on", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#00A0DC", nextState:"turningOff"
|
||||||
attributeState "off", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
|
attributeState "off", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff"
|
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#00A0DC", nextState:"turningOff"
|
||||||
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
|
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
}
|
}
|
||||||
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
|
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
|
||||||
attributeState "level", action:"switch level.setLevel", range:"(0..100)"
|
attributeState "level", action:"switch level.setLevel", range:"(0..100)"
|
||||||
}
|
}
|
||||||
tileAttribute ("device.level", key: "SECONDARY_CONTROL") {
|
|
||||||
attributeState "level", label: 'Level ${currentValue}%'
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
controlTile("levelSliderControl", "device.level", "slider", height: 1, width: 2, inactiveLabel: false, range:"(0..100)") {
|
controlTile("levelSliderControl", "device.level", "slider", height: 1, width: 2, inactiveLabel: false, range:"(0..100)") {
|
||||||
@@ -51,6 +50,19 @@ metadata {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def initialize() {
|
||||||
|
sendEvent(name: "DeviceWatch-Enroll", value: "{\"protocol\": \"LAN\", \"scheme\":\"untracked\", \"hubHardwareId\": \"${device.hub.hardwareID}\"}", displayed: false)
|
||||||
|
}
|
||||||
|
|
||||||
|
void installed() {
|
||||||
|
log.debug "installed()"
|
||||||
|
initialize()
|
||||||
|
}
|
||||||
|
|
||||||
|
def updated() {
|
||||||
|
initialize()
|
||||||
|
}
|
||||||
|
|
||||||
// parse events into attributes
|
// parse events into attributes
|
||||||
def parse(description) {
|
def parse(description) {
|
||||||
log.debug "parse() - $description"
|
log.debug "parse() - $description"
|
||||||
@@ -71,20 +83,16 @@ def parse(description) {
|
|||||||
// handle commands
|
// handle commands
|
||||||
void on() {
|
void on() {
|
||||||
log.trace parent.on(this)
|
log.trace parent.on(this)
|
||||||
sendEvent(name: "switch", value: "on")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void off() {
|
void off() {
|
||||||
log.trace parent.off(this)
|
log.trace parent.off(this)
|
||||||
sendEvent(name: "switch", value: "off")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setLevel(percent) {
|
void setLevel(percent) {
|
||||||
log.debug "Executing 'setLevel'"
|
log.debug "Executing 'setLevel'"
|
||||||
if (percent != null && percent >= 0 && percent <= 100) {
|
if (percent != null && percent >= 0 && percent <= 100) {
|
||||||
parent.setLevel(this, percent)
|
parent.setLevel(this, percent)
|
||||||
sendEvent(name: "level", value: percent)
|
|
||||||
sendEvent(name: "switch", value: "on")
|
|
||||||
} else {
|
} else {
|
||||||
log.warn "$percent is not 0-100"
|
log.warn "$percent is not 0-100"
|
||||||
}
|
}
|
||||||
@@ -94,3 +102,4 @@ void refresh() {
|
|||||||
log.debug "Executing 'refresh'"
|
log.debug "Executing 'refresh'"
|
||||||
parent.manualRefresh()
|
parent.manualRefresh()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,120 @@
|
|||||||
|
/**
|
||||||
|
* Hue White Ambiance Bulb
|
||||||
|
*
|
||||||
|
* Philips Hue Type "Color Temperature Light"
|
||||||
|
*
|
||||||
|
* Author: SmartThings
|
||||||
|
*/
|
||||||
|
|
||||||
|
// for the UI
|
||||||
|
metadata {
|
||||||
|
// Automatically generated. Make future change here.
|
||||||
|
definition (name: "Hue White Ambiance Bulb", namespace: "smartthings", author: "SmartThings") {
|
||||||
|
capability "Switch Level"
|
||||||
|
capability "Actuator"
|
||||||
|
capability "Color Temperature"
|
||||||
|
capability "Switch"
|
||||||
|
capability "Refresh"
|
||||||
|
capability "Health Check"
|
||||||
|
capability "Light"
|
||||||
|
|
||||||
|
command "refresh"
|
||||||
|
}
|
||||||
|
|
||||||
|
simulator {
|
||||||
|
// TODO: define status and reply messages here
|
||||||
|
}
|
||||||
|
|
||||||
|
tiles (scale: 2){
|
||||||
|
multiAttributeTile(name:"rich-control", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
||||||
|
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
||||||
|
attributeState "on", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#00A0DC", nextState:"turningOff"
|
||||||
|
attributeState "off", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
|
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#00A0DC", nextState:"turningOff"
|
||||||
|
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
|
}
|
||||||
|
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
|
||||||
|
attributeState "level", action:"switch level.setLevel", range:"(0..100)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
controlTile("colorTempSliderControl", "device.colorTemperature", "slider", width: 4, height: 2, inactiveLabel: false, range:"(2200..6500)") {
|
||||||
|
state "colorTemperature", action:"color temperature.setColorTemperature"
|
||||||
|
}
|
||||||
|
|
||||||
|
valueTile("colorTemp", "device.colorTemperature", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
||||||
|
state "colorTemperature", label: 'WHITES'
|
||||||
|
}
|
||||||
|
|
||||||
|
standardTile("refresh", "device.refresh", height: 2, width: 2, inactiveLabel: false, decoration: "flat") {
|
||||||
|
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
|
||||||
|
}
|
||||||
|
|
||||||
|
main(["rich-control"])
|
||||||
|
details(["rich-control", "colorTempSliderControl", "colorTemp", "refresh"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def initialize() {
|
||||||
|
sendEvent(name: "DeviceWatch-Enroll", value: "{\"protocol\": \"LAN\", \"scheme\":\"untracked\", \"hubHardwareId\": \"${device.hub.hardwareID}\"}", displayed: false)
|
||||||
|
}
|
||||||
|
|
||||||
|
void installed() {
|
||||||
|
log.debug "installed()"
|
||||||
|
initialize()
|
||||||
|
}
|
||||||
|
|
||||||
|
def updated() {
|
||||||
|
log.debug "updated()"
|
||||||
|
initialize()
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse events into attributes
|
||||||
|
def parse(description) {
|
||||||
|
log.debug "parse() - $description"
|
||||||
|
def results = []
|
||||||
|
|
||||||
|
def map = description
|
||||||
|
if (description instanceof String) {
|
||||||
|
log.debug "Hue Ambience Bulb stringToMap - ${map}"
|
||||||
|
map = stringToMap(description)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (map?.name && map?.value) {
|
||||||
|
results << createEvent(name: "${map?.name}", value: "${map?.value}")
|
||||||
|
}
|
||||||
|
results
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle commands
|
||||||
|
void on() {
|
||||||
|
log.trace parent.on(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
void off() {
|
||||||
|
log.trace parent.off(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
void setLevel(percent) {
|
||||||
|
log.debug "Executing 'setLevel'"
|
||||||
|
if (percent != null && percent >= 0 && percent <= 100) {
|
||||||
|
log.trace parent.setLevel(this, percent)
|
||||||
|
} else {
|
||||||
|
log.warn "$percent is not 0-100"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setColorTemperature(value) {
|
||||||
|
if (value) {
|
||||||
|
log.trace "setColorTemperature: ${value}k"
|
||||||
|
log.trace parent.setColorTemperature(this, value)
|
||||||
|
} else {
|
||||||
|
log.warn "Invalid color temperature"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void refresh() {
|
||||||
|
log.debug "Executing 'refresh'"
|
||||||
|
parent.manualRefresh()
|
||||||
|
}
|
||||||
|
|
||||||
@@ -29,7 +29,7 @@ metadata {
|
|||||||
|
|
||||||
tiles {
|
tiles {
|
||||||
standardTile("presence", "device.presence", width: 2, height: 2, canChangeBackground: true) {
|
standardTile("presence", "device.presence", width: 2, height: 2, canChangeBackground: true) {
|
||||||
state("present", labelIcon:"st.presence.tile.mobile-present", backgroundColor:"#53a7c0")
|
state("present", labelIcon:"st.presence.tile.mobile-present", backgroundColor:"#00A0DC")
|
||||||
state("not present", labelIcon:"st.presence.tile.mobile-not-present", backgroundColor:"#ffffff")
|
state("not present", labelIcon:"st.presence.tile.mobile-not-present", backgroundColor:"#ffffff")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@ metadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def generatePresenceEvent(boolean present) {
|
def generatePresenceEvent(boolean present) {
|
||||||
log.debug "Here in generatePresenceEvent!"
|
log.info "Life360 generatePresenceEvent($present)"
|
||||||
def value = formatValue(present)
|
def value = formatValue(present)
|
||||||
def linkText = getLinkText(device)
|
def linkText = getLinkText(device)
|
||||||
def descriptionText = formatDescriptionText(linkText, present)
|
def descriptionText = formatDescriptionText(linkText, present)
|
||||||
|
|||||||
@@ -5,15 +5,16 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
metadata {
|
metadata {
|
||||||
definition (name: "LIFX Color Bulb", namespace: "smartthings", author: "LIFX") {
|
definition (name: "LIFX Color Bulb", namespace: "smartthings", author: "LIFX", ocfDeviceType: "oic.d.light") {
|
||||||
capability "Actuator"
|
capability "Actuator"
|
||||||
capability "Color Control"
|
capability "Color Control"
|
||||||
capability "Color Temperature"
|
capability "Color Temperature"
|
||||||
capability "Switch"
|
capability "Switch"
|
||||||
capability "Switch Level" // brightness
|
capability "Switch Level" // brightness
|
||||||
capability "Polling"
|
|
||||||
capability "Refresh"
|
capability "Refresh"
|
||||||
capability "Sensor"
|
capability "Sensor"
|
||||||
|
capability "Health Check"
|
||||||
|
capability "Light"
|
||||||
}
|
}
|
||||||
|
|
||||||
simulator {
|
simulator {
|
||||||
@@ -23,10 +24,9 @@ metadata {
|
|||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
||||||
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
||||||
attributeState "unreachable", label: "?", action:"refresh.refresh", icon:"http://hosted.lifx.co/smartthings/v1/196xUnreachable.png", backgroundColor:"#666666"
|
attributeState "on", label:'${name}', action:"switch.off", icon:"http://hosted.lifx.co/smartthings/v1/196xOn.png", backgroundColor:"#00A0DC", nextState:"turningOff"
|
||||||
attributeState "on", label:'${name}', action:"switch.off", icon:"http://hosted.lifx.co/smartthings/v1/196xOn.png", backgroundColor:"#79b821", nextState:"turningOff"
|
|
||||||
attributeState "off", label:'${name}', action:"switch.on", icon:"http://hosted.lifx.co/smartthings/v1/196xOff.png", backgroundColor:"#ffffff", nextState:"turningOn"
|
attributeState "off", label:'${name}', action:"switch.on", icon:"http://hosted.lifx.co/smartthings/v1/196xOff.png", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
attributeState "turningOn", label:'Turning on', action:"switch.off", icon:"http://hosted.lifx.co/smartthings/v1/196xOn.png", backgroundColor:"#79b821", nextState:"turningOff"
|
attributeState "turningOn", label:'Turning on', action:"switch.off", icon:"http://hosted.lifx.co/smartthings/v1/196xOn.png", backgroundColor:"#00A0DC", nextState:"turningOff"
|
||||||
attributeState "turningOff", label:'Turning off', action:"switch.on", icon:"http://hosted.lifx.co/smartthings/v1/196xOff.png", backgroundColor:"#ffffff", nextState:"turningOn"
|
attributeState "turningOff", label:'Turning off', action:"switch.on", icon:"http://hosted.lifx.co/smartthings/v1/196xOff.png", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,12 +64,18 @@ metadata {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse events into attributes
|
def initialize() {
|
||||||
def parse(String description) {
|
sendEvent(name: "DeviceWatch-Enroll", value: "{\"protocol\": \"cloud\", \"scheme\":\"untracked\", \"hubHardwareId\": \"${device?.hub?.hardwareID}\"}", displayed: false)
|
||||||
if (description == 'updated') {
|
|
||||||
return // don't poll when config settings is being updated as it may time out
|
|
||||||
}
|
}
|
||||||
poll()
|
|
||||||
|
void installed() {
|
||||||
|
log.debug "installed()"
|
||||||
|
initialize()
|
||||||
|
}
|
||||||
|
|
||||||
|
def updated() {
|
||||||
|
log.debug "updated()"
|
||||||
|
initialize()
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle commands
|
// handle commands
|
||||||
@@ -141,7 +147,6 @@ def setLevel(percentage) {
|
|||||||
percentage = 1 // clamp to 1%
|
percentage = 1 // clamp to 1%
|
||||||
}
|
}
|
||||||
if (percentage == 0) {
|
if (percentage == 0) {
|
||||||
sendEvent(name: "level", value: 0) // Otherwise the level value tile does not update
|
|
||||||
return off() // if the brightness is set to 0, just turn it off
|
return off() // if the brightness is set to 0, just turn it off
|
||||||
}
|
}
|
||||||
parent.logErrors(logObject:log) {
|
parent.logErrors(logObject:log) {
|
||||||
@@ -193,14 +198,17 @@ def off() {
|
|||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
def poll() {
|
def refresh() {
|
||||||
log.debug "Executing 'poll' for ${device} ${this} ${device.deviceNetworkId}"
|
log.debug "Executing 'refresh'"
|
||||||
|
|
||||||
def resp = parent.apiGET("/lights/${selector()}")
|
def resp = parent.apiGET("/lights/${selector()}")
|
||||||
if (resp.status == 404) {
|
if (resp.status == 404) {
|
||||||
sendEvent(name: "switch", value: "unreachable")
|
state.online = false
|
||||||
|
sendEvent(name: "DeviceWatch-DeviceStatusUpdate", value: "offline", displayed: false)
|
||||||
|
log.warn "$device is Offline"
|
||||||
return []
|
return []
|
||||||
} else if (resp.status != 200) {
|
} else if (resp.status != 200) {
|
||||||
log.error("Unexpected result in poll(): [${resp.status}] ${resp.data}")
|
log.error("Unexpected result in refresh(): [${resp.status}] ${resp.data}")
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
def data = resp.data[0]
|
def data = resp.data[0]
|
||||||
@@ -209,19 +217,20 @@ def poll() {
|
|||||||
sendEvent(name: "label", value: data.label)
|
sendEvent(name: "label", value: data.label)
|
||||||
sendEvent(name: "level", value: Math.round((data.brightness ?: 1) * 100))
|
sendEvent(name: "level", value: Math.round((data.brightness ?: 1) * 100))
|
||||||
sendEvent(name: "switch.setLevel", value: Math.round((data.brightness ?: 1) * 100))
|
sendEvent(name: "switch.setLevel", value: Math.round((data.brightness ?: 1) * 100))
|
||||||
sendEvent(name: "switch", value: data.connected ? data.power : "unreachable")
|
sendEvent(name: "switch", value: data.power)
|
||||||
sendEvent(name: "color", value: colorUtil.hslToHex((data.color.hue / 3.6) as int, (data.color.saturation * 100) as int))
|
sendEvent(name: "color", value: colorUtil.hslToHex((data.color.hue / 3.6) as int, (data.color.saturation * 100) as int))
|
||||||
sendEvent(name: "hue", value: data.color.hue / 3.6)
|
sendEvent(name: "hue", value: data.color.hue / 3.6)
|
||||||
sendEvent(name: "saturation", value: data.color.saturation * 100)
|
sendEvent(name: "saturation", value: data.color.saturation * 100)
|
||||||
sendEvent(name: "colorTemperature", value: data.color.kelvin)
|
sendEvent(name: "colorTemperature", value: data.color.kelvin)
|
||||||
sendEvent(name: "model", value: "${data.product.company} ${data.product.name}")
|
sendEvent(name: "model", value: data.product.name)
|
||||||
|
|
||||||
return []
|
if (data.connected) {
|
||||||
|
sendEvent(name: "DeviceWatch-DeviceStatus", value: "online", displayed: false)
|
||||||
|
log.debug "$device is Online"
|
||||||
|
} else {
|
||||||
|
sendEvent(name: "DeviceWatch-DeviceStatus", value: "offline", displayed: false)
|
||||||
|
log.warn "$device is Offline"
|
||||||
}
|
}
|
||||||
|
|
||||||
def refresh() {
|
|
||||||
log.debug "Executing 'refresh'"
|
|
||||||
poll()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def selector() {
|
def selector() {
|
||||||
|
|||||||
@@ -5,14 +5,15 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
metadata {
|
metadata {
|
||||||
definition (name: "LIFX White Bulb", namespace: "smartthings", author: "LIFX") {
|
definition (name: "LIFX White Bulb", namespace: "smartthings", author: "LIFX", ocfDeviceType: "oic.d.light") {
|
||||||
capability "Actuator"
|
capability "Actuator"
|
||||||
capability "Color Temperature"
|
capability "Color Temperature"
|
||||||
capability "Switch"
|
capability "Switch"
|
||||||
capability "Switch Level" // brightness
|
capability "Switch Level" // brightness
|
||||||
capability "Polling"
|
|
||||||
capability "Refresh"
|
capability "Refresh"
|
||||||
capability "Sensor"
|
capability "Sensor"
|
||||||
|
capability "Health Check"
|
||||||
|
capability "Light"
|
||||||
}
|
}
|
||||||
|
|
||||||
simulator {
|
simulator {
|
||||||
@@ -22,13 +23,12 @@ metadata {
|
|||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
||||||
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
||||||
attributeState "unreachable", label: "?", action:"refresh.refresh", icon:"http://hosted.lifx.co/smartthings/v1/196xUnreachable.png", backgroundColor:"#666666"
|
attributeState "on", label:'${name}', action:"switch.off", icon:"http://hosted.lifx.co/smartthings/v1/196xOn.png", backgroundColor:"#00A0DC", nextState:"turningOff"
|
||||||
attributeState "on", label:'${name}', action:"switch.off", icon:"http://hosted.lifx.co/smartthings/v1/196xOn.png", backgroundColor:"#79b821", nextState:"turningOff"
|
|
||||||
attributeState "off", label:'${name}', action:"switch.on", icon:"http://hosted.lifx.co/smartthings/v1/196xOff.png", backgroundColor:"#ffffff", nextState:"turningOn"
|
attributeState "off", label:'${name}', action:"switch.on", icon:"http://hosted.lifx.co/smartthings/v1/196xOff.png", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
attributeState "turningOn", label:'Turning on', action:"switch.off", icon:"http://hosted.lifx.co/smartthings/v1/196xOn.png", backgroundColor:"#79b821", nextState:"turningOff"
|
attributeState "turningOn", label:'Turning on', action:"switch.off", icon:"http://hosted.lifx.co/smartthings/v1/196xOn.png", backgroundColor:"#00A0DC", nextState:"turningOff"
|
||||||
attributeState "turningOff", label:'Turning off', action:"switch.on", icon:"http://hosted.lifx.co/smartthings/v1/196xOff.png", backgroundColor:"#ffffff", nextState:"turningOn"
|
attributeState "turningOff", label:'Turning off', action:"switch.on", icon:"http://hosted.lifx.co/smartthings/v1/196xOff.png", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
|
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
|
||||||
attributeState "level", action:"switch level.setLevel"
|
attributeState "level", action:"switch level.setLevel"
|
||||||
}
|
}
|
||||||
@@ -53,15 +53,20 @@ metadata {
|
|||||||
main "switch"
|
main "switch"
|
||||||
details(["switch", "colorTempSliderControl", "colorTemp", "refresh"])
|
details(["switch", "colorTempSliderControl", "colorTemp", "refresh"])
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse events into attributes
|
def initialize() {
|
||||||
def parse(String description) {
|
sendEvent(name: "DeviceWatch-Enroll", value: "{\"protocol\": \"cloud\", \"scheme\":\"untracked\", \"hubHardwareId\": \"${device?.hub?.hardwareID}\"}", displayed: false)
|
||||||
if (description == 'updated') {
|
|
||||||
return // don't poll when config settings is being updated as it may time out
|
|
||||||
}
|
}
|
||||||
poll()
|
|
||||||
|
void installed() {
|
||||||
|
log.debug "installed()"
|
||||||
|
initialize()
|
||||||
|
}
|
||||||
|
|
||||||
|
def updated() {
|
||||||
|
log.debug "updated()"
|
||||||
|
initialize()
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle commands
|
// handle commands
|
||||||
@@ -71,7 +76,6 @@ def setLevel(percentage) {
|
|||||||
percentage = 1 // clamp to 1%
|
percentage = 1 // clamp to 1%
|
||||||
}
|
}
|
||||||
if (percentage == 0) {
|
if (percentage == 0) {
|
||||||
sendEvent(name: "level", value: 0) // Otherwise the level value tile does not update
|
|
||||||
return off() // if the brightness is set to 0, just turn it off
|
return off() // if the brightness is set to 0, just turn it off
|
||||||
}
|
}
|
||||||
parent.logErrors(logObject:log) {
|
parent.logErrors(logObject:log) {
|
||||||
@@ -123,14 +127,17 @@ def off() {
|
|||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
def poll() {
|
def refresh() {
|
||||||
log.debug "Executing 'poll' for ${device} ${this} ${device.deviceNetworkId}"
|
log.debug "Executing 'refresh'"
|
||||||
|
|
||||||
def resp = parent.apiGET("/lights/${selector()}")
|
def resp = parent.apiGET("/lights/${selector()}")
|
||||||
if (resp.status == 404) {
|
if (resp.status == 404) {
|
||||||
sendEvent(name: "switch", value: "unreachable")
|
state.online = false
|
||||||
|
sendEvent(name: "DeviceWatch-DeviceStatusUpdate", value: "offline", displayed: false)
|
||||||
|
log.warn "$device is Offline"
|
||||||
return []
|
return []
|
||||||
} else if (resp.status != 200) {
|
} else if (resp.status != 200) {
|
||||||
log.error("Unexpected result in poll(): [${resp.status}] ${resp.data}")
|
log.error("Unexpected result in refresh(): [${resp.status}] ${resp.data}")
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
def data = resp.data[0]
|
def data = resp.data[0]
|
||||||
@@ -138,16 +145,17 @@ def poll() {
|
|||||||
sendEvent(name: "label", value: data.label)
|
sendEvent(name: "label", value: data.label)
|
||||||
sendEvent(name: "level", value: Math.round((data.brightness ?: 1) * 100))
|
sendEvent(name: "level", value: Math.round((data.brightness ?: 1) * 100))
|
||||||
sendEvent(name: "switch.setLevel", value: Math.round((data.brightness ?: 1) * 100))
|
sendEvent(name: "switch.setLevel", value: Math.round((data.brightness ?: 1) * 100))
|
||||||
sendEvent(name: "switch", value: data.connected ? data.power : "unreachable")
|
sendEvent(name: "switch", value: data.power)
|
||||||
sendEvent(name: "colorTemperature", value: data.color.kelvin)
|
sendEvent(name: "colorTemperature", value: data.color.kelvin)
|
||||||
sendEvent(name: "model", value: data.product.name)
|
sendEvent(name: "model", value: data.product.name)
|
||||||
|
|
||||||
return []
|
if (data.connected) {
|
||||||
|
sendEvent(name: "DeviceWatch-DeviceStatus", value: "online", displayed: false)
|
||||||
|
log.debug "$device is Online"
|
||||||
|
} else {
|
||||||
|
sendEvent(name: "DeviceWatch-DeviceStatus", value: "offline", displayed: false)
|
||||||
|
log.warn "$device is Offline"
|
||||||
}
|
}
|
||||||
|
|
||||||
def refresh() {
|
|
||||||
log.debug "Executing 'refresh'"
|
|
||||||
poll()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def selector() {
|
def selector() {
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user