mirror of
https://github.com/letscontrolit/ESPEasy.git
synced 2026-07-28 04:07:47 +00:00
Compare commits
442
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6313d4344d | ||
|
|
d7dcd9cff0 | ||
|
|
bdf0e6e05c | ||
|
|
75e411f458 | ||
|
|
bc9a697792 | ||
|
|
dfe90363b7 | ||
|
|
d8dd25593e | ||
|
|
38d08d6902 | ||
|
|
a7b32273ae | ||
|
|
5ccbdfff11 | ||
|
|
4ff3de5482 | ||
|
|
d52435264d | ||
|
|
cd76c88860 | ||
|
|
429fa31ee5 | ||
|
|
6b33cee8ea | ||
|
|
a182ca8097 | ||
|
|
f7feeff9b4 | ||
|
|
a5cfa1713d | ||
|
|
04edfae8de | ||
|
|
1e9debf67c | ||
|
|
250d8aca59 | ||
|
|
19ec7a90cf | ||
|
|
74e591ac81 | ||
|
|
29fb32225a | ||
|
|
f90f97e3d0 | ||
|
|
fd634a12a1 | ||
|
|
19b59359e0 | ||
|
|
0fe9566d14 | ||
|
|
9e49f6f7b1 | ||
|
|
660377ea02 | ||
|
|
4e171993ff | ||
|
|
dfdaa831d5 | ||
|
|
946c1a8390 | ||
|
|
f7c7d176f1 | ||
|
|
0a72b711f9 | ||
|
|
2f8962ec52 | ||
|
|
b68d91fc58 | ||
|
|
a8c565ee5f | ||
|
|
6f06b57d14 | ||
|
|
cf949ab167 | ||
|
|
21cc1faf25 | ||
|
|
99030621b7 | ||
|
|
33199ceb12 | ||
|
|
6175adddd1 | ||
|
|
35461643ff | ||
|
|
9397f560dc | ||
|
|
6de76f8817 | ||
|
|
ae9deeb702 | ||
|
|
1bdbc97d33 | ||
|
|
bec97768f4 | ||
|
|
abdc9a0454 | ||
|
|
c9bb2750a3 | ||
|
|
eda3326615 | ||
|
|
d2644b2da7 | ||
|
|
8650bc6aa3 | ||
|
|
dee5f6df1a | ||
|
|
0085986701 | ||
|
|
7a72836d0f | ||
|
|
cec830fe83 | ||
|
|
894a59e10b | ||
|
|
e28f46697a | ||
|
|
14ced058b5 | ||
|
|
fabc514f8e | ||
|
|
4ae5e2ce7b | ||
|
|
0585d48ffa | ||
|
|
be9a5d622a | ||
|
|
821fcb9e54 | ||
|
|
1a9584134a | ||
|
|
d2e9337d76 | ||
|
|
6c5c12a6f2 | ||
|
|
9eb2ebe210 | ||
|
|
1d5fbd926e | ||
|
|
4d3ac95e5a | ||
|
|
1f1e47530a | ||
|
|
3b1d26b541 | ||
|
|
8a86ee9b89 | ||
|
|
ed592a3a0a | ||
|
|
f2b330424c | ||
|
|
542a758fde | ||
|
|
11e4addb41 | ||
|
|
8921ebbcaa | ||
|
|
d05d669284 | ||
|
|
71a6b344e7 | ||
|
|
c67becac0c | ||
|
|
0ec06161c5 | ||
|
|
a2b2cd857a | ||
|
|
0e581f0288 | ||
|
|
fffcd0f2a4 | ||
|
|
1d923a527f | ||
|
|
356ebbc875 | ||
|
|
25fadfc1ed | ||
|
|
54d892e162 | ||
|
|
007ef78f2b | ||
|
|
d16daeca56 | ||
|
|
90fdb8f809 | ||
|
|
383206b149 | ||
|
|
ac20349854 | ||
|
|
1a972d61a6 | ||
|
|
d6cf2e141b | ||
|
|
7a2e9ba203 | ||
|
|
e3591aceb2 | ||
|
|
ad3514e765 | ||
|
|
f543995d86 | ||
|
|
97ccb8eca1 | ||
|
|
f291c9d25a | ||
|
|
bd9ead3851 | ||
|
|
43ea0039fd | ||
|
|
74eb638bcb | ||
|
|
c87b035908 | ||
|
|
0f450eaa3d | ||
|
|
02df033fc6 | ||
|
|
74d05e58f0 | ||
|
|
3d88537677 | ||
|
|
95b0a7bed9 | ||
|
|
bc3434532e | ||
|
|
1f7639cb42 | ||
|
|
923642bb27 | ||
|
|
a09cb906eb | ||
|
|
72b0a32839 | ||
|
|
e279e5504b | ||
|
|
6d5ddf06ce | ||
|
|
7f544b7a10 | ||
|
|
fc407e86e1 | ||
|
|
a35c3051df | ||
|
|
f8f2ddd33b | ||
|
|
6592b57615 | ||
|
|
6e8e8214b2 | ||
|
|
24b6611c54 | ||
|
|
8135defa6f | ||
|
|
d5e9cfb081 | ||
|
|
ffc8e1fb97 | ||
|
|
0255f41897 | ||
|
|
e88973861f | ||
|
|
d6ec7aa736 | ||
|
|
8aa5866dd9 | ||
|
|
0c384c332e | ||
|
|
7a4f3b15b3 | ||
|
|
c38e532e67 | ||
|
|
f983dd924d | ||
|
|
f0ff52b76b | ||
|
|
3c0e5d1965 | ||
|
|
14489a2e98 | ||
|
|
a920b95cfb | ||
|
|
a111175a8f | ||
|
|
4fd2166b5e | ||
|
|
db76aeb959 | ||
|
|
b313957311 | ||
|
|
9d0f741e84 | ||
|
|
7c0f1551b8 | ||
|
|
8a59811392 | ||
|
|
e2e715d7de | ||
|
|
ccb4cf6a7a | ||
|
|
1b4a217bc9 | ||
|
|
19ecf36358 | ||
|
|
bdea34a583 | ||
|
|
b7b5028c0c | ||
|
|
c519d887db | ||
|
|
29c8b850ba | ||
|
|
d01cb9b9a2 | ||
|
|
9d894d7c83 | ||
|
|
a418cb2bd0 | ||
|
|
907a672fa0 | ||
|
|
2f10274da2 | ||
|
|
399b344779 | ||
|
|
2e06ed14c0 | ||
|
|
b0032bebdb | ||
|
|
a525ec34b0 | ||
|
|
024ec7b727 | ||
|
|
1ff0141e38 | ||
|
|
125db8046b | ||
|
|
720317c829 | ||
|
|
bbe9005a32 | ||
|
|
afa16e80b6 | ||
|
|
37f5c92aa7 | ||
|
|
684b89ae4c | ||
|
|
8c4612c300 | ||
|
|
0afab53659 | ||
|
|
e6e98345fe | ||
|
|
2394e4a75f | ||
|
|
e1c4691325 | ||
|
|
3f84c35014 | ||
|
|
bc0bafa96b | ||
|
|
4e7e66822d | ||
|
|
6f226e6d65 | ||
|
|
a50a035238 | ||
|
|
d560c635f5 | ||
|
|
f8db0c0a05 | ||
|
|
79616022df | ||
|
|
559d294607 | ||
|
|
d2588c5e01 | ||
|
|
ba45a51576 | ||
|
|
8321caaeed | ||
|
|
b35ed7d809 | ||
|
|
a4583d150e | ||
|
|
cadc0a885d | ||
|
|
061eb20ae5 | ||
|
|
9a9799eee7 | ||
|
|
f4615bb76b | ||
|
|
ecc498c359 | ||
|
|
e0e10fa6c8 | ||
|
|
228f09f394 | ||
|
|
19ac19778b | ||
|
|
5e2d517ba2 | ||
|
|
7a4b17983e | ||
|
|
6eba74ccc1 | ||
|
|
27a05b674c | ||
|
|
4a66bbf081 | ||
|
|
109bddb5c3 | ||
|
|
8158a919d8 | ||
|
|
706b91168b | ||
|
|
d047999c5e | ||
|
|
42f361aacd | ||
|
|
3dd076cf25 | ||
|
|
c0d155dd99 | ||
|
|
c433174d71 | ||
|
|
b805b59baf | ||
|
|
9fae0477d8 | ||
|
|
f7ac04dc96 | ||
|
|
d50e661efb | ||
|
|
57b5338af6 | ||
|
|
bd035c8f81 | ||
|
|
ac63d93e1a | ||
|
|
4cff0d0e02 | ||
|
|
ca83983fd2 | ||
|
|
d808f7e79b | ||
|
|
e469350ad9 | ||
|
|
60536b1a93 | ||
|
|
b9e45bd515 | ||
|
|
a0992b8383 | ||
|
|
9315581858 | ||
|
|
9a763303ca | ||
|
|
7df9379f47 | ||
|
|
c32fe50521 | ||
|
|
e4569b26f7 | ||
|
|
48998886fe | ||
|
|
36f97d7909 | ||
|
|
0e3b9c9e47 | ||
|
|
acecff4108 | ||
|
|
3322b954a7 | ||
|
|
4c4b844a4d | ||
|
|
cf4d28eb4f | ||
|
|
555b5386ae | ||
|
|
1903fdc7f2 | ||
|
|
918353461e | ||
|
|
e648a20fd0 | ||
|
|
1d7ea5e129 | ||
|
|
6ce5240dd7 | ||
|
|
692fb248ce | ||
|
|
5a87397ee0 | ||
|
|
99ba09b024 | ||
|
|
3dea091d21 | ||
|
|
ca13317cbd | ||
|
|
f68516d5bb | ||
|
|
8102a0096d | ||
|
|
73cec59bd5 | ||
|
|
96ecf9bf29 | ||
|
|
ef1e371514 | ||
|
|
45d67292a3 | ||
|
|
b5662baad4 | ||
|
|
12c3e5f81f | ||
|
|
dececf24ee | ||
|
|
3fb6dec382 | ||
|
|
cef962c5f1 | ||
|
|
cca2335070 | ||
|
|
ffd0d26ed3 | ||
|
|
9b457ed77b | ||
|
|
f787a9a9a6 | ||
|
|
a0ae104794 | ||
|
|
2b78810457 | ||
|
|
43081c3ac8 | ||
|
|
33281c08c2 | ||
|
|
461aee26ad | ||
|
|
2b0b14b2e8 | ||
|
|
b7404666b1 | ||
|
|
da25aa87dd | ||
|
|
10a1e634e2 | ||
|
|
83f86449b9 | ||
|
|
eee337d3e3 | ||
|
|
c549ecd329 | ||
|
|
d9e682668d | ||
|
|
e38072ac24 | ||
|
|
6aebeba5dc | ||
|
|
da01c8f469 | ||
|
|
d3c86b9824 | ||
|
|
9621a91d90 | ||
|
|
b3b68856f0 | ||
|
|
bec5cb5334 | ||
|
|
bda6011390 | ||
|
|
f3fdb93a52 | ||
|
|
200b060b15 | ||
|
|
ff41cb2f94 | ||
|
|
c134eb6d13 | ||
|
|
f9e2a211e1 | ||
|
|
bd3d3f66f4 | ||
|
|
3bad683211 | ||
|
|
68f6e913a2 | ||
|
|
0b9c550fd7 | ||
|
|
96420faa2f | ||
|
|
8eea77e4ed | ||
|
|
3d1f723787 | ||
|
|
5d459003e4 | ||
|
|
ad208c357c | ||
|
|
b1c777e6fd | ||
|
|
f5ab15c255 | ||
|
|
001ec6dcd2 | ||
|
|
15e5edccd8 | ||
|
|
651353cc99 | ||
|
|
85f97551c5 | ||
|
|
6a158f68f5 | ||
|
|
1933714de5 | ||
|
|
545117ddf7 | ||
|
|
8eb479c411 | ||
|
|
b39f51ca3c | ||
|
|
4511e08d3c | ||
|
|
086e836956 | ||
|
|
3e20f617ea | ||
|
|
8d9aacb6a4 | ||
|
|
0670fa98a6 | ||
|
|
2b3d1517c9 | ||
|
|
0be79759d1 | ||
|
|
d47bede215 | ||
|
|
2988a244b2 | ||
|
|
8d87dc0175 | ||
|
|
21c86e666a | ||
|
|
e6fdd3380a | ||
|
|
e04f71ab47 | ||
|
|
90ae0720cf | ||
|
|
4ec2af24a3 | ||
|
|
c8ecd8d374 | ||
|
|
7a451dd672 | ||
|
|
b06f6aa360 | ||
|
|
6b67415c71 | ||
|
|
b095465d3a | ||
|
|
81a5d911ba | ||
|
|
48060d8d99 | ||
|
|
d303fa023f | ||
|
|
29b0cc1b32 | ||
|
|
584abd1e75 | ||
|
|
b4d8be0e59 | ||
|
|
30f5c5cb7d | ||
|
|
6e7286c6fb | ||
|
|
ae1db543ce | ||
|
|
947e1e0343 | ||
|
|
0578d720f4 | ||
|
|
3fee6794f2 | ||
|
|
019e33331b | ||
|
|
211d79bbd5 | ||
|
|
8a751a0922 | ||
|
|
450eca8dc5 | ||
|
|
ce0bfbf717 | ||
|
|
bb316bbd30 | ||
|
|
91c5d60af9 | ||
|
|
0d9bc8027d | ||
|
|
bd2bdab95c | ||
|
|
c4f98fbc8e | ||
|
|
b332a513b5 | ||
|
|
e36bb714f1 | ||
|
|
6e1cde343f | ||
|
|
cce9ddd2dc | ||
|
|
51be17a436 | ||
|
|
66d27a6697 | ||
|
|
a033e458fb | ||
|
|
494436bbff | ||
|
|
23bacd0762 | ||
|
|
9bdfab3fa2 | ||
|
|
9d446745cc | ||
|
|
d2ab946d17 | ||
|
|
fcc71a56b6 | ||
|
|
f131254853 | ||
|
|
657d15d962 | ||
|
|
60910da48d | ||
|
|
6cee2d0f32 | ||
|
|
533cb88a64 | ||
|
|
ffa32fe851 | ||
|
|
b900cc9389 | ||
|
|
8e11c19af6 | ||
|
|
f33ca6df78 | ||
|
|
194a230d20 | ||
|
|
7a5a432016 | ||
|
|
07511fe144 | ||
|
|
9a390136f9 | ||
|
|
27a03f166a | ||
|
|
0a63aeb8f0 | ||
|
|
22c10ac615 | ||
|
|
ac83cfa249 | ||
|
|
6ef0c08bc4 | ||
|
|
1ee965067d | ||
|
|
e46a873fce | ||
|
|
784e956c96 | ||
|
|
b6eebb330a | ||
|
|
a4fe8d42d2 | ||
|
|
fa42cadfa1 | ||
|
|
17dc6fa859 | ||
|
|
1432726dec | ||
|
|
7ba6ffa407 | ||
|
|
ab555e4d6b | ||
|
|
d4259f4e23 | ||
|
|
aef45c06f6 | ||
|
|
828f9e6a30 | ||
|
|
e79d778cf4 | ||
|
|
965eb2d994 | ||
|
|
657fccf49f | ||
|
|
228b41a1ac | ||
|
|
3bba294eb7 | ||
|
|
0254181b3e | ||
|
|
3b67282abb | ||
|
|
38af765935 | ||
|
|
ff180b085c | ||
|
|
e0785eb796 | ||
|
|
75a83787a4 | ||
|
|
65bea6343c | ||
|
|
6fe61411a0 | ||
|
|
4552e91022 | ||
|
|
cc94d70e6c | ||
|
|
2435078f76 | ||
|
|
dd2cd50d4b | ||
|
|
fe38eb629d | ||
|
|
e961507456 | ||
|
|
e5ee5644bf | ||
|
|
ac6d85e214 | ||
|
|
39c2d54aee | ||
|
|
68efd5ff9e | ||
|
|
627f516f85 | ||
|
|
a45fadf42e | ||
|
|
2ae52b849c | ||
|
|
639685ea0d | ||
|
|
867209de6d | ||
|
|
1d8b6d346b | ||
|
|
2a5ac327d3 | ||
|
|
886101d4d4 | ||
|
|
8fc6486855 | ||
|
|
eeb1cc71b3 | ||
|
|
13837830e8 | ||
|
|
f86ff46a82 | ||
|
|
e901bc957a | ||
|
|
e7e10c5305 | ||
|
|
5511ee9f38 | ||
|
|
427a22d23b | ||
|
|
d271898968 | ||
|
|
4051f0bd2e | ||
|
|
60925778c6 | ||
|
|
15233bf100 |
@@ -1,3 +1,25 @@
|
||||
### Checklist
|
||||
- [ ] The title of this issue is "to the point" and descriptive.
|
||||
- [ ] This issue describes what is happening.
|
||||
- [ ] This issue describes what components are affected (e.g. name of plugin/controller)
|
||||
- [ ] This issue describes how to reproduce it.
|
||||
- [ ] This issue describes when it was introduced (when known) and what version is now showing the problem.
|
||||
|
||||
### I have...
|
||||
- [ ] searched the [issue tracker](https://github.com/letscontrolit/ESPEasy/issues) or the [forum](https://www.letscontrolit.com/forum/viewforum.php?f=1) for a similar issue. (include links when applicable)
|
||||
- [ ] entered a system description using "Copy info to clipboard" on the sysinfo page. (when possible)
|
||||
- [ ] entered the full filename of the used version (e.g. `ESP_Easy_mega-20181001_test_ESP8266_4096_VCC.bin` )
|
||||
- [ ] given a list of active plugins or controllers when applicable.
|
||||
- [ ] filled out all applicable fields below.
|
||||
|
||||
### Steps already tried...
|
||||
- [ ] Tried a clean install (empty `.bin` files are included in the ZIP)
|
||||
- [ ] Tested previous/other build (mention which one already tested)
|
||||
- [ ] Tested on other node to make sure hardware isn't defective.
|
||||
- [ ] Verified if the problem is limited to a single plugin/controller
|
||||
|
||||
|
||||
|
||||
### If you self compile, please state this and PLEASE try to ONLY REPORT ISSUES WITH OFFICIAL BUILDS! ###
|
||||
<!--- If you self compile, please state this and PLEASE try to ONLY REPORT ISSUES WITH OFFICIAL BUILDS! --->
|
||||
<!--- NOTE: This is not a support forum! For questions and support go here: --->
|
||||
@@ -5,6 +27,7 @@
|
||||
<!--- Remove topics that are not applicable to your feature request of issue --->
|
||||
<!--- Remember to have a "to the point" TITLE --->
|
||||
|
||||
|
||||
### Summarize of the problem/feature request
|
||||
<!--- Describe the problem or feature request --->
|
||||
YOUR TEXT GOES HERE
|
||||
|
||||
@@ -18,3 +18,9 @@ lib/readme.txt
|
||||
src/Custom.h
|
||||
/ESPEasy
|
||||
test/output_export.cpp
|
||||
.vscode
|
||||
.vscode/.browse.c_cpp.db*
|
||||
.vscode/c_cpp_properties.json
|
||||
.vscode/launch.json
|
||||
|
||||
docs/build/
|
||||
|
||||
+6
-7
@@ -22,20 +22,19 @@ addons:
|
||||
|
||||
|
||||
install:
|
||||
- pip install -U platformio
|
||||
- pip install -U platformio sphinx recommonmark sphinx_bootstrap_theme
|
||||
|
||||
script:
|
||||
- platformio update
|
||||
# patch platformio core libs for PUYA bug (https://github.com/letscontrolit/ESPEasy/issues/650)
|
||||
- cd patches; ./check_puya_patch; cd ..
|
||||
|
||||
# - bash ./preflight.sh # make sure input files are OK before wasting time with prereqs
|
||||
# - cppcheck --enable=warning src/*.ino -q --force -I src --include=src/ESPEasy.ino --error-exitcode=1
|
||||
# - ./memanalyzer.py ~/.platformio/packages/toolchain-xtensa/bin/xtensa-lx106-elf-objdump
|
||||
- PLATFORMIO_BUILD_FLAGS="-D CONTINUOUS_INTEGRATION" platformio run
|
||||
- PLATFORMIO_BUILD_FLAGS="-D CONTINUOUS_INTEGRATION" platformio run
|
||||
|
||||
# patch platformio core libs for PUYA bug (https://github.com/letscontrolit/ESPEasy/issues/650)
|
||||
- cd patches; ./check_puya_patch; cd ..
|
||||
- PLATFORMIO_BUILD_FLAGS="-D CONTINUOUS_INTEGRATION" platformio run -s --environment dev_ESP8266PUYA_1024
|
||||
- PLATFORMIO_BUILD_FLAGS="-D CONTINUOUS_INTEGRATION" platformio run -s --environment dev_ESP8266PUYA_1024
|
||||
|
||||
|
||||
before_deploy:
|
||||
- ./before_deploy
|
||||
- export RELEASE_FILE=$(ls ESPEasy*.zip)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
|Latest Nightly | Build Status | Patreon | Ko-Fi |
|
||||
|-------|-------|-------|-------|
|
||||
| [](https://github.com/letscontrolit/ESPEasy/releases/latest) | [](https://travis-ci.org/letscontrolit/ESPEasy) | [](https://www.patreon.com/GrovkillenTDer) | [](https://ko-fi.com/grovkillentder) |
|
||||
|Latest Nightly | Build Status | Patreon | Ko-Fi | PayPal |
|
||||
|-------|-------|-------|-------|-------|
|
||||
| [](https://github.com/letscontrolit/ESPEasy/releases/latest) | [](https://travis-ci.org/letscontrolit/ESPEasy) | [](https://www.patreon.com/GrovkillenTDer) | [](https://ko-fi.com/grovkillentder) | [](https://www.paypal.me/espeasy) |
|
||||
|
||||
For ways to *support* us, see [this announcement on the forum](https://www.letscontrolit.com/forum/viewtopic.php?f=14&t=5787), or have a look at the [Patreon](https://www.patreon.com/GrovkillenTDer) or [Ko-Fi](https://ko-fi.com/grovkillentder) links above.
|
||||
For ways to *support* us, see [this announcement on the forum](https://www.letscontrolit.com/forum/viewtopic.php?f=14&t=5787), or have a look at the [Patreon](https://www.patreon.com/GrovkillenTDer), [Ko-Fi](https://ko-fi.com/grovkillentder) or [PayPal](https://www.paypal.me/espeasy) links above.
|
||||
|
||||
# ESPEasy (development branch)
|
||||
|
||||
@@ -41,4 +41,4 @@ ESPEasy_mega-20180102_dev_ESP8285_1024.bin | ESP8285 with 1Mb flash | Stabl
|
||||
|
||||
Details and discussion are on the Experimental forum: https://www.letscontrolit.com/forum/viewforum.php?f=18
|
||||
|
||||
We're also on IRC: #ESPEasy @freenode
|
||||
Automated builds of the (new) documentation can be found at [ESPEasy.readthedocs.io](https://espeasy.readthedocs.io/en/latest/)
|
||||
|
||||
+17
-10
@@ -11,6 +11,8 @@ for ENV in \
|
||||
normal_ESP8266_4096 \
|
||||
normal_ESP8285_1024 \
|
||||
normal_IR_ESP8266_4096 \
|
||||
normal_core_241_ESP8266_1024 \
|
||||
normal_core_241_ESP8266_4096 \
|
||||
test_ESP8266_1024\
|
||||
test_ESP8266_4096\
|
||||
test_ESP8266_4096_VCC\
|
||||
@@ -18,27 +20,32 @@ for ENV in \
|
||||
dev_ESP8266_1024\
|
||||
dev_ESP8266_4096\
|
||||
dev_ESP8285_1024\
|
||||
dev_ESP8266PUYA_1024\
|
||||
dev_ESP8266PUYA_1024_VCC\
|
||||
hard_SONOFF_POW\
|
||||
hard_Shelly_1\
|
||||
esp32dev;\
|
||||
hard_SONOFF_POW_R2_4M\
|
||||
minimal_ESP8266_1024_OTA\
|
||||
minimal_ESP8285_1024_OTA\
|
||||
esp32dev\
|
||||
esp32test_1M8_partition;\
|
||||
do
|
||||
echo
|
||||
echo "### Deploying environment $ENV for version $VERSION"
|
||||
BIN=.pioenvs/${ENV}/ESP_Easy_${VERSION}_${ENV}.bin
|
||||
cp .pioenvs/${ENV}/firmware.bin $BIN
|
||||
python2 crc2.py $BIN
|
||||
mv $BIN "dist/ESP_Easy_${VERSION}_${ENV}.bin"
|
||||
mv $BIN "dist/bin/ESP_Easy_${VERSION}_${ENV}.bin"
|
||||
done
|
||||
|
||||
|
||||
#create a source structure that is the same as the original ESPEasy project (and works with the howto on the wiki)
|
||||
rm -rf dist/Source 2>/dev/null
|
||||
mkdir dist/Source
|
||||
cp -r lib dist/Source/
|
||||
cp -r src dist/Source/
|
||||
cp platformio.ini dist/Source/
|
||||
#rm -rf dist/Source 2>/dev/null
|
||||
rm -rf dist/Docs 2>/dev/null
|
||||
|
||||
mkdir -p dist/source
|
||||
#mkdir -p dist/docs
|
||||
cp -r lib dist/source/
|
||||
cp -r src dist/source/
|
||||
#cp -r docs/build/ dist/docs/
|
||||
cp platformio.ini dist/source/
|
||||
|
||||
cd dist
|
||||
|
||||
|
||||
Vendored
BIN
Binary file not shown.
Vendored
+66
@@ -0,0 +1,66 @@
|
||||
_____ ____ ____
|
||||
| ____/ ___|| _ \ ___ __ _ ___ _ _
|
||||
| _| \___ \| |_) / _ \/ _` / __| | | |
|
||||
| |___ ___) | __/ __/ (_| \__ \ |_| |
|
||||
|_____|____/|_| \___|\__,_|___/\__, |
|
||||
|___/
|
||||
|
||||
|
||||
This is the distribution folder for ESPeasy.
|
||||
In here you will find a flash tool to program the ESP module.
|
||||
|
||||
Also a number of binary images is included.
|
||||
|
||||
The filename is quite descriptive:
|
||||
ESP_Easy_mega-<date>_<buildType>_<chip>_<memorySize>.bin
|
||||
|
||||
Build type can be: (differ in included plugins)
|
||||
- normal => Only Stable plugins and controllers
|
||||
- test => Stable + Testing
|
||||
- dev => Stable + Testing + Development
|
||||
|
||||
There is also a number of special builds:
|
||||
- normal_IR => "Normal" + IR receiver/transmitter plugins and library
|
||||
- hard_xxxxx => Special builds for some off-the-shelf hardware.
|
||||
- normal_core_241 => "Normal" using core 2.4.1, since 2.4.2 has issues with PWM
|
||||
- minimal_ESP82xx_1024_OTA => Minimum number of plugins and a limited set of controllers included to be able to perform a 2-step OTA on 1 MB flash nodes.
|
||||
|
||||
Chip can be:
|
||||
- ESP8266 => Most likely option
|
||||
- ESP8285 => Used in some Sonoff modules
|
||||
- ESP32 => Experimental support at this moment
|
||||
|
||||
MemorySize can be:
|
||||
- 1024 => 1 MB flash modules (e.g. almost all Sonoff modules)
|
||||
- 2048 => 2 MB flash modules (e.g. Shelly1/WROOM02)
|
||||
- 4096 => 4 MB flash modules (e.g. NodeMCU/ESP32)
|
||||
|
||||
ESP32 now has 2 builds:
|
||||
- esp32dev Using the default partition layout (1.4 MB for the sketch)
|
||||
- esp32test_1M8_partition Larger sketch partition (1.8MB) smaller SPIFFS (316 kB)
|
||||
|
||||
Please note that changing between those versions will destroy the settings!
|
||||
The SPIFFS partition will be lost and that contains all settings.
|
||||
|
||||
|
||||
To help recover from a bad flash, there are also blank images included.
|
||||
- blank_1MB.bin
|
||||
- blank_2MB.bin
|
||||
- blank_4MB.bin
|
||||
|
||||
When the wrong image is flashed, or the module behaves unstable, or is in a reboot loop,
|
||||
flash these images first and then the right image for the module.
|
||||
|
||||
ESP.Easy.Flasher.exe...
|
||||
... is the new flashing tool for ESP Easy. You need to run it in elevated mode (as admin)
|
||||
for it to fetch the COM ports correctly. If you want you may save YOUR settings using the
|
||||
"Save as default settings" button in the lower left corner. If the window is too big or
|
||||
too small you can experiment with the "Pixels Per Inch" variable in the
|
||||
..\Settings\Default.ini file. Setting it to =96 is working for most users but the
|
||||
application will try to find the most optimal value by default. Sometimes it fails to
|
||||
do that. More information about the tool is found here:
|
||||
https://github.com/Grovkillen/ESP_Easy_Flasher
|
||||
|
||||
Further reading:
|
||||
For more information, see: https://github.com/letscontrolit/ESPEasy
|
||||
Or our forum: https://www.letscontrolit.com/forum/
|
||||
Vendored
+746
@@ -1,3 +1,749 @@
|
||||
-------------------------------------------------
|
||||
Changes in release mega-20181110 (since mega-20181109)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Sat Nov 10 04:00:08 CET 2018
|
||||
|
||||
Bartlomiej Zimon (4):
|
||||
HTTP responses have duplicate Content-Types fix for #2018
|
||||
remove double strings for contenttype
|
||||
remove old duplication
|
||||
properly send content-type header fix for #2022
|
||||
|
||||
TD-er (2):
|
||||
[ESP32] Upgrade core lib to espressif32@1.5.0
|
||||
[WiFi] Improve disconnect detection and run delay(1) when not connected
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release mega-20181109 (since mega-20181108)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Fri Nov 9 04:00:10 CET 2018
|
||||
|
||||
Bartlomiej Zimon (1):
|
||||
add p078_dev_id to form save
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release mega-20181108 (since mega-20181107)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Thu Nov 8 04:00:09 CET 2018
|
||||
|
||||
Bartlomiej Zimon (2):
|
||||
Add optional DE PIN configuration Add gpio names to form fix for #1684
|
||||
Sysinfo update to 4 values
|
||||
|
||||
Plebs (4):
|
||||
bug fixes
|
||||
cleaned if from addLog as per uzi18 comment
|
||||
final cleanup
|
||||
BUG fix
|
||||
|
||||
TD-er (6):
|
||||
[PUYA] Apply generic patch on all builds checking for PUYA flash
|
||||
[Travis] Update platformIO packages before build
|
||||
[PUYA] Add PUYA patch v3 to check if patch is applied
|
||||
[PUYA] Fix patch v3 for PUYA support
|
||||
[PUYA] share static flash_chip_id among functions
|
||||
[PUYA] Fix typo in patch
|
||||
|
||||
stefan (2):
|
||||
Amend nosleep command to accept awake time
|
||||
Add System#NoSleep=<time> event
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release mega-20181107 (since mega-20181106)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Wed Nov 7 04:00:08 CET 2018
|
||||
|
||||
TD-er (14):
|
||||
[Cleanup] Reduce build image size by 2k by wrapping flash strings
|
||||
[Cleanup] Reduce length HTML form data IDs to reduce sketch size
|
||||
[Cleanup] Minify JavaScript and CSS to reduce sketch size
|
||||
[1MB OTA] Add small build to allow for 1MB OTA
|
||||
[Cleanup] Make single definition for pin description
|
||||
[OTA] Add ESP8285 1M OTA minimal build
|
||||
[Cleanup] Strip HTML templates into sections to remove duplicate strings
|
||||
[Cleanup] Increase load speed and lower memory usage rendering web page
|
||||
[Cleanup] Do not use F-macro for short strings
|
||||
[timing stats] Add http://<ip>/stat/timing/json to view timing stats
|
||||
[timingstats] Implement HTML table of timing stats
|
||||
[timingstats] Disable timing stats in log
|
||||
[timingstats] Improve table layout of timing stats
|
||||
[timingstats] Show stats in msec instead of usec.
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release mega-20181106 (since mega-20181105)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Tue Nov 6 04:00:10 CET 2018
|
||||
|
||||
Grovkillen (1):
|
||||
[Flasher] fixed ip bug fixed
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release mega-20181105 (since mega-20181101)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Mon Nov 5 04:00:10 CET 2018
|
||||
|
||||
Bartlomiej Zimon (2):
|
||||
fix for #1986
|
||||
Eastron - save modbus id and enable SDM630 model partial fix for #1684
|
||||
|
||||
Grovkillen (1):
|
||||
[Memanalyzer] cmd args are back (un-commented)
|
||||
|
||||
Jimmy Westberg (2):
|
||||
Revert "[Flasher] updated flasher (some minor error)"
|
||||
[Memanalyzer] try to fix the memanalyzer not analyzing all plugins
|
||||
|
||||
kpalczewski (1):
|
||||
bump lib IRremoteESP8266 to 2.5.2 and add send Pioneer support for 035 IR plugin.
|
||||
|
||||
stefan (2):
|
||||
Add sent/return value check to client.print()
|
||||
Add comment why we check for %256
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release mega-20181101 (since mega-20181031)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Thu Nov 1 04:00:08 CET 2018
|
||||
|
||||
Bartłomiej Zimoń (1):
|
||||
BlynkGet add timeout 1,5s.
|
||||
|
||||
Grovkillen (4):
|
||||
[README] added more info about ESP.Easy.Flasher
|
||||
[README] fixed some \r\n
|
||||
[Deploy] "source" folder was named "Source"
|
||||
[README] removed IRC link... we're not there.
|
||||
|
||||
Jimmy Westberg (1):
|
||||
[Flasher] updated flasher (some minor error)
|
||||
|
||||
Plebs (2):
|
||||
Update src/Misc.ino
|
||||
Update src/Misc.ino
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release mega-20181031 (since mega-20181030)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Wed Oct 31 04:00:10 CET 2018
|
||||
|
||||
Bartłomiej Zimoń (1):
|
||||
BlynkGet fix loop #1951
|
||||
|
||||
Jimmy Westberg (7):
|
||||
[Flasher] Added ESP.Easy.Flasher.exe
|
||||
[Deploy] Added sub folder for BIN files
|
||||
[Flasher] Updated to 0.02.001
|
||||
[Deploy] small letters are the standard
|
||||
[Flasher] Updated to 0.02.002
|
||||
[Path] folder rename 1
|
||||
[Path] folder rename 2
|
||||
|
||||
TD-er (1):
|
||||
[OTA] Add OTA info and disable when not enough space
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release mega-20181030 (since mega-20181029)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Tue Oct 30 04:00:07 CET 2018
|
||||
|
||||
James Tutton (2):
|
||||
Added Special Case to allow Servo to be disabled
|
||||
Fixed missing ;
|
||||
|
||||
TD-er (1):
|
||||
[Core 2.4.2] Set core 2.4.2 as default platform
|
||||
|
||||
svmac (1):
|
||||
P022_PCA9685 Enhancements
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release mega-20181029 (since mega-20181028)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Mon Oct 29 04:00:08 CET 2018
|
||||
|
||||
Bartlomiej Zimon (2):
|
||||
Dallas: add ScratchPad to debug log - OK suffix means data integrity ok (no communication problems)
|
||||
Dallas: use reset timming from OneWire lib
|
||||
|
||||
TD-er (2):
|
||||
[NTP] Improve NTP accuracy
|
||||
[NTP] Change log level for NTP success to INFO
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release mega-20181028 (since mega-20181027)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Sun Oct 28 04:00:09 CET 2018
|
||||
|
||||
Saverio Cisternino (5):
|
||||
[CRON] Replace timeStruct with standard tm
|
||||
[CRON] Plugin
|
||||
[CRON] Add event PLUGIN_TIME_CHANGE
|
||||
[CRON] Intercept event PLUGIN_TIME_CHANGE
|
||||
[CRON] Fixed Daily flash write rate exceeded!
|
||||
|
||||
TD-er (2):
|
||||
[Cron] Rename plugin name to match naming convention
|
||||
[Eastron] Make configurable and allow for multiple values read (#1684)
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release mega-20181027 (since mega-20181026)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Sat Oct 27 04:00:12 CEST 2018
|
||||
|
||||
Bartlomiej Zimon (1):
|
||||
CSE7766 - fix stats plus add buffer fill level
|
||||
|
||||
Gilad (7):
|
||||
Add IR RAW2 Reading / Transmitting.
|
||||
Add IR RAW2 Reading / Transmitting.
|
||||
Add IR RAW2 Reading / Transmitting - fixed ambiguity.
|
||||
Add IR RAW2 Reading / Transmitting - added a safety check.
|
||||
Improved IR RAW2 format to support RLE.
|
||||
Fixed warnings...
|
||||
Fixed warnings...
|
||||
|
||||
Gilad Raz (1):
|
||||
Increased buffer size. Added constants.
|
||||
|
||||
Plebs (4):
|
||||
doubleclick and longpress for PCF and MCP
|
||||
fixed a display bug
|
||||
final fixes
|
||||
fixed as requested
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release mega-20181026 (since mega-20181025)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Fri Oct 26 04:00:22 CEST 2018
|
||||
|
||||
Bartlomiej Zimon (7):
|
||||
CSE7766 uses 8E1 serial connection
|
||||
Ser2Net catch serial data only if plugin used
|
||||
CSE7766 add online checksumming, autosyncing without data loos
|
||||
move to PLUGIN_TEN_PER_SECOND update comments
|
||||
move to PLUGIN_SERIAL_IN from PLUGIN_TEN_PER_SECOND - serial commandline uses our data
|
||||
optimization - remove double checksum check
|
||||
CSE7766 - add some stats to debug log
|
||||
|
||||
Saverio Cisternino (1):
|
||||
Fixed plugin timer processing do not start, when call setPluginTaskTimer in PLUGIN_TIMER_IN
|
||||
|
||||
TD-er (1):
|
||||
[C009] Reduce memory usage for C009 controller.
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release mega-20181025 (since mega-20181023)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Thu Oct 25 04:00:13 CEST 2018
|
||||
|
||||
Saverio Cisternino (1):
|
||||
Added auto redirect to home after run reboot command from web page.
|
||||
|
||||
TD-er (5):
|
||||
[WDT] Change yield() to delay(0)
|
||||
[Build] Add Sonoff POW R2 (4MB)
|
||||
[Sonoff] Add pre-defined switch and relay + rules on factory reset
|
||||
[Info] Remove MD5 check fail on self-built images
|
||||
[Travis] Use variables even when no predefined plugins are added.
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release mega-20181023 (since mega-20181022)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Tue Oct 23 04:00:14 CEST 2018
|
||||
|
||||
Kurairaito (2):
|
||||
Update _P067_HX711_Load_Cell.ino
|
||||
Update _P067_HX711_Load_Cell.ino
|
||||
|
||||
TD-er (6):
|
||||
[#1486] Allow multiple instances of rotary encoder
|
||||
[JavaScript] Fix update values on Devices tab
|
||||
[JavaScript] Cleanup some code duplication
|
||||
[PubSubClient] Add delay when waiting for data and flush on disconnect
|
||||
[WiFi timeout] Set default to 1000 msec again
|
||||
[Docs] Add some WiFi related information to docs
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release mega-20181022 (since mega-20181021)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Mon Oct 22 04:00:15 CEST 2018
|
||||
|
||||
TD-er (2):
|
||||
[Webserver] Generate copyText id names
|
||||
[Webserver] Uniform row labels to reduce flash string size
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release mega-20181021 (since mega-20181020)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Sun Oct 21 04:00:16 CEST 2018
|
||||
|
||||
Bartlomiej Zimon (2):
|
||||
fix for #1920 fix for out of sync, check both header bytes proper check for abnormal state
|
||||
Revert "fix for #1920"
|
||||
|
||||
TD-er (6):
|
||||
[stack usage] Allocate temp char array on heap for parsing arguments
|
||||
Proper look for connection.
|
||||
[Rules] Early exit on rules processing when rules not enabled
|
||||
[#1910] Notification settings extra strings on stack
|
||||
[#1891] Send all values for Generic UDP controller
|
||||
[#1870] Feature request build date as system info
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release mega-20181020 (since mega-20181017)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Sat Oct 20 04:00:16 CEST 2018
|
||||
|
||||
Plebs (22):
|
||||
Added [plugin#pcfgpio#pinstate#xx]
|
||||
added [plugin#mcpgpio#pinstate#xx]
|
||||
code optimization
|
||||
some code optimizations
|
||||
Update src/_P001_Switch.ino
|
||||
Update src/_P001_Switch.ino
|
||||
small fixes
|
||||
few changes
|
||||
Update src/_P001_Switch.ino
|
||||
Update src/_P001_Switch.ino
|
||||
some fixes
|
||||
added global variables for rules
|
||||
some fixes
|
||||
fixes
|
||||
fixed length check
|
||||
some optimizations
|
||||
modified command and variable name
|
||||
Update src/_P001_Switch.ino
|
||||
Update src/_P001_Switch.ino
|
||||
optimizations
|
||||
Update src/StringConverter.ino
|
||||
added 4 variables to verify the system status
|
||||
|
||||
kpalczewski (1):
|
||||
add support for 64bit IR codes.
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release mega-20181017 (since mega-20181016)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Wed Oct 17 04:00:18 CEST 2018
|
||||
|
||||
Gijs Noorlander (1):
|
||||
Added checklist to the Issue_template
|
||||
|
||||
TD-er (3):
|
||||
[#1906] Allocate NotificationSettings on the heap
|
||||
[#1906] Allocate ControllerSettings on the heap
|
||||
[Stack] Add Free Stack to System Info plugin
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release mega-20181016 (since mega-20181015)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Tue Oct 16 04:00:06 CEST 2018
|
||||
|
||||
Plebs (1):
|
||||
Fix for togglegpio without gpio initialization
|
||||
|
||||
TD-er (1):
|
||||
[Revert] Safe_strncpy cannot be used as generic strncpy replacement
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release mega-20181015 (since mega-20181014)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Mon Oct 15 04:00:10 CEST 2018
|
||||
|
||||
Plebs (2):
|
||||
fix for bug #1864
|
||||
Update src/_P023_OLED.ino
|
||||
|
||||
TD-er (1):
|
||||
[safe strncpy] Add warning when entered string is too large
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release mega-20181014 (since mega-20181011)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Sun Oct 14 04:00:13 CEST 2018
|
||||
|
||||
Gijs Noorlander (1):
|
||||
[#1799] Add SSID to main page
|
||||
|
||||
TD-er (5):
|
||||
[#1891] Generic UPD controller - send only first value from sensor
|
||||
[Controller] Fix send only first value
|
||||
Time#Initialized event in rules before %syshour% is set
|
||||
[UX] Warn user for incomplete network IP settings
|
||||
[#1895] Incorrect number bytes read I2C_read32_reg
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release mega-20181011 (since mega-20181010)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Thu Oct 11 04:00:24 CEST 2018
|
||||
|
||||
TD-er (5):
|
||||
[C009] Reduce memory usage of FHEM HTTP delay queue
|
||||
[Controller] Set default timeout to 300 msec (was 100 msec)
|
||||
Make sure to load ExtraTaskSettings when needed
|
||||
[Travis Doc] Remove building documentation by Travis
|
||||
[WebLog] Disable weblog when it is not being read
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release mega-20181010 (since mega-20181009)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Wed Oct 10 04:00:09 CEST 2018
|
||||
|
||||
Plebs (1):
|
||||
Update src/_P019_PCF8574.ino
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release mega-20181009 (since mega-20181008)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Tue Oct 9 04:00:18 CEST 2018
|
||||
|
||||
TD-er (7):
|
||||
[Docs] Add favicon to documentation
|
||||
[Docs] Add Travis check for documentation and stop build for docs only
|
||||
[Docs] Run Travic documentation check before compiling project
|
||||
[Docs] Disable travis_terminate for now
|
||||
[JSON] Replace \n and \r in text fields
|
||||
[LWIP1.4] Move back to LWIP1.4
|
||||
[StringConverter] Some optimisations to reduce memory allocation
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release mega-20181008 (since mega-20181007)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Mon Oct 8 04:00:09 CEST 2018
|
||||
|
||||
Gijs Noorlander (1):
|
||||
Added link to ReadTheDocs
|
||||
|
||||
Grovkillen (1):
|
||||
[Sphinx] added extension "sphinx.ext.imgconverter"
|
||||
|
||||
TD-er (3):
|
||||
[Sphinx] Initial setup for Sphinx documentation
|
||||
[Docs] First ESPEasy documentation (Controllers)
|
||||
[Docs] Added some directory structure and template
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release mega-20181007 (since mega-20181006)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Sun Oct 7 04:00:09 CEST 2018
|
||||
|
||||
Max (2):
|
||||
Force slash to be converted in htmlEscape
|
||||
Fix XSS-Vulnerabilites on wifi configuration pages
|
||||
|
||||
Plebs (3):
|
||||
Add three new TOGGLE commands
|
||||
fixed float to int conversion
|
||||
added "mcpgpiotoggle" command
|
||||
|
||||
TD-er (3):
|
||||
[ESP32] Allow Wrover dev kit to be used for PIO debug
|
||||
[Stack] Move Arduino 'cont' stack into user RAM
|
||||
[SPIFFS] Make sure to close open files on SPIFFS
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release mega-20181006 (since mega-20181004)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Sat Oct 6 04:00:13 CEST 2018
|
||||
|
||||
TD-er (3):
|
||||
[Stack] Increase stack to 5k and reduce stack allocations in rules
|
||||
[WiFi] Add delay to connection attempts in ControllerSettings
|
||||
[Build flags] Remove NO_EXTRA_4K_HEAP
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release mega-20181004 (since mega-20181003)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Thu Oct 4 04:00:08 CEST 2018
|
||||
|
||||
Bartlomiej Zimon (1):
|
||||
- partial fix for #1723
|
||||
|
||||
JojoS (1):
|
||||
added error checking and logging
|
||||
|
||||
JojoS62 (5):
|
||||
added float calculation for time to distance conversion
|
||||
added more settings: unit, filtertype and size
|
||||
max distance depends on measurement unit
|
||||
code clean up
|
||||
fixed 'unused variable' warning
|
||||
|
||||
TD-er (3):
|
||||
[sendHttp] #1830 Set timeout and early exit on timeout reached
|
||||
[WiFiClient] Set timeout and make it configurable for controllers
|
||||
[Core 2.4.1] Move back to core 2.4.1 from 2.4.2
|
||||
|
||||
Thomas (1):
|
||||
Update _P075_Nextion.ino (#1)
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release mega-20181003 (since mega-20181002)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Wed Oct 3 04:00:18 CEST 2018
|
||||
|
||||
David Conran (2):
|
||||
Acknowledge credit & origin of code used in IRTX
|
||||
Acknowledge credit & origin of code used in _P016IR.ino
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release mega-20181002 (since mega-20181001)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Tue Oct 2 04:00:29 CEST 2018
|
||||
|
||||
Plebs (1):
|
||||
split parseTemplate function
|
||||
|
||||
TD-er (4):
|
||||
[#1798] Bugfix Sonoff Si7021 stability
|
||||
[ESP32] Add default partition table for reference
|
||||
[ESP32] Update to PIO espressif32@1.4.0
|
||||
[Stack] Report stack usage on ESP32 and increase stack for ESP8266normal
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release mega-20181001 (since mega-20180930)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Mon Oct 1 13:13:13 CEST 2018
|
||||
|
||||
TD-er (4):
|
||||
[#1824] Show stack size on main page
|
||||
[Heap] Use NO_EXTRA_4K_HEAP to get old stack address space
|
||||
[Stack] Check if a block sent to save on SPIFFS is stack allocated
|
||||
[Stack] Revert move Settings from stack to heap
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release mega-20180930 (since mega-20180927)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Sun Sep 30 04:00:24 CEST 2018
|
||||
|
||||
JojoS (5):
|
||||
fixed distance reading
|
||||
on INIT, delete sensordef before adding new
|
||||
removed sensordefs helper structure
|
||||
changed implementation to use shared_ptr instead of helper structure
|
||||
minor change: unit was missing for threshold in 'state' mode
|
||||
|
||||
TD-er (2):
|
||||
[Default Settings] Properly clear settings when reset to default
|
||||
[Defaults] Other default initializations
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release mega-20180927 (since mega-20180924)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Thu Sep 27 04:00:17 CEST 2018
|
||||
|
||||
TD-er (7):
|
||||
[ESP32] Change partition size (will clear all settings) and add plugins
|
||||
[Travis] Uninitialized variable in P073_7DGT
|
||||
[Stack] Move Settings from stack to heap
|
||||
[ESP32] RTOS move handle_schedule() to core1 and increase stack
|
||||
[Info] Add board name to the sysinfo page.
|
||||
[ESP32] Split new partition layout to separate build
|
||||
[Build] Add esp32test_1M8_partition build and warning on ESP32 partition
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release mega-20180924 (since mega-20180923)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Mon Sep 24 04:00:20 CEST 2018
|
||||
|
||||
Benno Eigenmann (1):
|
||||
Fix platformio
|
||||
|
||||
TD-er (2):
|
||||
[MQTT] Work around for lost MQTT connection
|
||||
[ESP32] Fix I2C handling to allow I2C devices to work
|
||||
|
||||
sakinit (1):
|
||||
change to platform version core_esp32_1_3_0
|
||||
|
||||
stefan (1):
|
||||
Change type of sensor for MCP and PCF devices
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release mega-20180923 (since mega-20180922)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Sun Sep 23 04:00:12 CEST 2018
|
||||
|
||||
TD-er (2):
|
||||
[MQTT import] Fix crash at boot when plugin is enabled
|
||||
[BME280] Fix slow reading of BME280 causing watchdog resets
|
||||
|
||||
sakinit (5):
|
||||
ESP32 build issues fixed
|
||||
Fix ESP32 stack overflow in addPinSelect when called from P1WifiGateway
|
||||
ESP32: Split webserver spiffs filelist into pages
|
||||
Reverted Webserver change
|
||||
ESP32 platform updated to 1.2.0; Webserver replaced by platform one
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release mega-20180922 (since mega-20180916)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Sat Sep 22 04:00:22 CEST 2018
|
||||
|
||||
Gijs Noorlander (1):
|
||||
Revert "Revert "Added 2 new operators in Calculate() function""
|
||||
|
||||
TD-er (2):
|
||||
Revert "[Scheduler] Disable command scheduler"
|
||||
Revert "Revert "Fix elseif & Add if-elseif-else nesting levels""
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release mega-20180916 (since mega-20180915)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Sun Sep 16 04:00:11 CEST 2018
|
||||
|
||||
Gijs Noorlander (3):
|
||||
Revert "Added 2 new operators in Calculate() function"
|
||||
Revert "Fix elseif & Add if-elseif-else nesting levels"
|
||||
Added warning to release notes 20180915
|
||||
|
||||
TD-er (1):
|
||||
[HW Watchdog] Backgroundtasks instead of yield during rules handling
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release mega-20180915 (since mega-20180914)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Sat Sep 15 04:00:15 CEST 2018
|
||||
Known issue:
|
||||
Causes reboots. (see [#1748](https://github.com/letscontrolit/ESPEasy/issues/1748) )
|
||||
|
||||
|
||||
Plebs (1):
|
||||
Added 2 new operators in Calculate
|
||||
|
||||
TD-er (4):
|
||||
[Scheduler] Disable command scheduler
|
||||
[Controller settings] Validate settings on load/save
|
||||
[#1713] Make hostname-unitnumber optional & validate settings
|
||||
[#1698] Incorrect sunrise value southern hemisphere
|
||||
|
||||
svmac (4):
|
||||
Fix elseif & Add if-elseif-else nesting levels
|
||||
reenabled code about !
|
||||
some code optimization
|
||||
fix mistake
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release mega-20180914 (since mega-20180910)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Fri Sep 14 04:00:17 CEST 2018
|
||||
|
||||
Gijs Noorlander (1):
|
||||
Added PayPal link
|
||||
|
||||
giddyhup (1):
|
||||
Fix IR plugin passing received code
|
||||
|
||||
Plebs (7):
|
||||
Use parameters inside rules when calling commands
|
||||
few changes
|
||||
fixed ESP32 compatibility issue
|
||||
fixed calls to F-macro
|
||||
adding more parameters to EVENT
|
||||
final version with '=' sign as a prefix to identify the formula in rules
|
||||
added %eventvalue4%
|
||||
|
||||
TD-er (2):
|
||||
[Flash tools] Add blank files and README.txt
|
||||
[CrashRecover] Disable failing step based on failed boot count
|
||||
|
||||
sakinit (1):
|
||||
Feature: Split webserver spiffs filelist into pages
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release mega-20180910 (since mega-20180909)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Mon Sep 10 04:00:22 CEST 2018
|
||||
|
||||
TD-er (2):
|
||||
[HTTP] Command SendToHttp cannot connect
|
||||
[Domoticz IDX] Allow for IDX of > 9999
|
||||
|
||||
sakinit (1):
|
||||
Reduced buffer size to prevent stack overflow
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release mega-20180909 (since mega-20180908)
|
||||
-------------------------------------------------
|
||||
|
||||
BIN
Binary file not shown.
Vendored
+1
File diff suppressed because one or more lines are too long
Vendored
+1
File diff suppressed because one or more lines are too long
Vendored
+1
File diff suppressed because one or more lines are too long
@@ -0,0 +1,19 @@
|
||||
# Minimal makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS =
|
||||
SPHINXBUILD = sphinx-build
|
||||
SOURCEDIR = source
|
||||
BUILDDIR = build
|
||||
|
||||
# Put it first so that "make" without argument is like "make help".
|
||||
help:
|
||||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
|
||||
.PHONY: help Makefile
|
||||
|
||||
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||
%: Makefile
|
||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
@@ -0,0 +1,35 @@
|
||||
@ECHO OFF
|
||||
|
||||
pushd %~dp0
|
||||
|
||||
REM Command file for Sphinx documentation
|
||||
|
||||
if "%SPHINXBUILD%" == "" (
|
||||
set SPHINXBUILD=sphinx-build
|
||||
)
|
||||
set SOURCEDIR=source
|
||||
set BUILDDIR=build
|
||||
|
||||
if "%1" == "" goto help
|
||||
|
||||
%SPHINXBUILD% >NUL 2>NUL
|
||||
if errorlevel 9009 (
|
||||
echo.
|
||||
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
||||
echo.installed, then set the SPHINXBUILD environment variable to point
|
||||
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
||||
echo.may add the Sphinx directory to PATH.
|
||||
echo.
|
||||
echo.If you don't have Sphinx installed, grab it from
|
||||
echo.http://sphinx-doc.org/
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
|
||||
goto end
|
||||
|
||||
:help
|
||||
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
|
||||
|
||||
:end
|
||||
popd
|
||||
@@ -0,0 +1,3 @@
|
||||
recommonmark
|
||||
Sphinx
|
||||
sphinx-bootstrap-theme
|
||||
@@ -0,0 +1,66 @@
|
||||
Controller
|
||||
**********
|
||||
|
||||
A controller is a component to enable a plugin to send data elsewhere.
|
||||
|
||||
- Up-to 3 controllers can be active in ESPEasy.
|
||||
- Per plugin up-to 3 active controllers can be selected.
|
||||
- For some controllers an additional parameter can be given.
|
||||
|
||||
For example, Domoticz needs an 'IDX' value to identify the configured entry in
|
||||
Domoticz for which new data is sent.
|
||||
|
||||
Controller Parameters
|
||||
=====================
|
||||
|
||||
Generic fields
|
||||
--------------
|
||||
|
||||
- **Protocol** - The type of controller (e.g. ThingSpeak/OpenHAB MQTT/etc.)
|
||||
- **Locate Controller** - Selection between hostname/IP
|
||||
- **Controller Hostname/IP** - The address to reach the selected service
|
||||
- **Controller Port** - TCP/UDP Port number (0...65536)
|
||||
- **Enabled** - Whether or not the controller is active.
|
||||
|
||||
Send queue parameters
|
||||
---------------------
|
||||
|
||||
Controllers have a queue to keep unsent messages.
|
||||
This queue is used to handle message bursts and also store messages which are recorded
|
||||
before WiFi connection is made or during lost connection.
|
||||
|
||||
- **Minimum Send Interval** - Minimum time between two messages in msec.
|
||||
- **Max Queue Depth** - Maximum length of the buffer queue to keep unsent messages.
|
||||
- **Max Retries** - Maximum number of retries to send a message.
|
||||
- **Full Queue Action** - How to handle when queue is full, ignore new or delete oldest message.
|
||||
- **Client Timeout** - Timeout in msec for an network connection used by the controller.
|
||||
- **Check Reply** - When set to false, a sent message is considered always successful.
|
||||
|
||||
|
||||
Sample ThingSpeak configuration
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Some controllers, like ThingSpeak, need a specific configuration.
|
||||
ThingSpeak only allows a message every 15 seconds for the free accounts.
|
||||
|
||||
- **Minimum Send Interval** - 15000 msec
|
||||
- **Max Queue Depth** - 1 (only report the last value)
|
||||
- **Max Retries** - 2
|
||||
- **Full Queue Action** - Delete Oldest
|
||||
- **Client Timeout** - 500 msec (server is online, so timeout must be a bit longer)
|
||||
|
||||
|
||||
Controller user credentials
|
||||
---------------------------
|
||||
|
||||
- **Controller User** - User name (optional)
|
||||
- **Controller Password** - Password (optional)
|
||||
|
||||
MQTT related settings
|
||||
---------------------
|
||||
|
||||
- **Controller Subscribe** - Subscribe to the given topic.
|
||||
- **Controller Publish** - Publish to the given topic.
|
||||
- **Controller lwl topic** - Topic to which LWT (Last Will Testament) messages should be sent.
|
||||
- **LWT Connect Message** - Connection established message.
|
||||
- **LWT Disconnect Message** - Connection lost message (sent to broker during connect and published by broker when connection is lost)
|
||||
@@ -0,0 +1,2 @@
|
||||
About Us
|
||||
********
|
||||
@@ -0,0 +1,2 @@
|
||||
ESPEasy Function Blocks
|
||||
***********************
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 2.1 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
@@ -0,0 +1,35 @@
|
||||
Documentation
|
||||
*************
|
||||
|
||||
For documentation we use Sphinx and this will be read by ReadTheDocs.
|
||||
We use the `Sphinx Bootstrap Theme <https://github.com/ryan-roemer/sphinx-bootstrap-theme>`_
|
||||
|
||||
This documentation is included in the GitHub repository.
|
||||
It allows us to create documentation per version of ESPEasy.
|
||||
|
||||
See also the `ESPEasy wiki <https://www.letscontrolit.com/wiki/index.php/ESPEasy>`_
|
||||
for more documentation which has not been moved here.
|
||||
|
||||
Needed Python packages::
|
||||
|
||||
pip install sphinx recommonmark sphinx_bootstrap_theme
|
||||
|
||||
PlatformIO with Atom
|
||||
====================
|
||||
|
||||
With the ESPEasy project open in Atom, open the PIO terminal in Atom.
|
||||
|
||||
Install dependencies::
|
||||
|
||||
cd docs
|
||||
pip install ... (see needed Python packages above)
|
||||
|
||||
Build on Windows::
|
||||
|
||||
cd docs
|
||||
.\make.bat html
|
||||
|
||||
Build on Linux/Mac::
|
||||
|
||||
cd docs
|
||||
./make html
|
||||
@@ -0,0 +1,2 @@
|
||||
Plugins
|
||||
*******
|
||||
@@ -0,0 +1,2 @@
|
||||
Command Reference
|
||||
*****************
|
||||
@@ -0,0 +1,2 @@
|
||||
System Variables
|
||||
****************
|
||||
@@ -0,0 +1,2 @@
|
||||
Rules
|
||||
*****
|
||||
@@ -0,0 +1,25 @@
|
||||
WiFi
|
||||
****
|
||||
|
||||
WiFi disconnect reasons
|
||||
=======================
|
||||
|
||||
Beacon timeout (200)
|
||||
--------------------
|
||||
|
||||
For more information on the Beacon frame, see `Wikipedia <https://en.wikipedia.org/wiki/Beacon_frame>`_.
|
||||
|
||||
In short, the access point sends periodically a packet containing information about the network.
|
||||
This interval is typically 100 TU (102.4 msec).
|
||||
The ESP module is trying to listen to this beacon every time, but for a number of reasons it may
|
||||
miss a beacon frame.
|
||||
The timeout is longer than 100 TU, so it must miss a number of these beacon frames
|
||||
to report a beacon timeout.
|
||||
Reasons to miss such a beacon frame are:
|
||||
|
||||
- too busy processing other blocking tasks (very likely)
|
||||
- access point not sending a beacon due to high traffic demands of others (depending on brand/model/settings)
|
||||
- RF disturbances (not likely given how often this occurs)
|
||||
- clock drift (not really likely)
|
||||
|
||||
So the "beacon timeout" is happening every now and then on the ESP nodes and ESPeasy will try to reconnect.
|
||||
@@ -0,0 +1,286 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Configuration file for the Sphinx documentation builder.
|
||||
#
|
||||
# This file does only contain a selection of the most common options. For a
|
||||
# full list see the documentation:
|
||||
# http://www.sphinx-doc.org/en/master/config
|
||||
|
||||
# -- Path setup --------------------------------------------------------------
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#
|
||||
# import os
|
||||
# import sys
|
||||
# sys.path.insert(0, os.path.abspath('.'))
|
||||
from recommonmark.parser import CommonMarkParser
|
||||
import sphinx_bootstrap_theme
|
||||
|
||||
|
||||
# -- Project information -----------------------------------------------------
|
||||
|
||||
project = u'ESPEasy'
|
||||
copyright = u'2018, ESPEasy'
|
||||
author = u'Many'
|
||||
|
||||
# The short X.Y version
|
||||
version = u''
|
||||
# The full version, including alpha/beta/rc tags
|
||||
release = u'2.1b1'
|
||||
|
||||
|
||||
# -- General configuration ---------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
#
|
||||
# needs_sphinx = '1.0'
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = [
|
||||
'sphinx.ext.autodoc',
|
||||
'sphinx.ext.intersphinx',
|
||||
'sphinx.ext.todo',
|
||||
'sphinx.ext.imgmath',
|
||||
'sphinx.ext.imgconverter',
|
||||
]
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
source_parsers = {
|
||||
'.md': CommonMarkParser,
|
||||
}
|
||||
|
||||
# The suffix(es) of source filenames.
|
||||
# You can specify multiple suffix as a list of string:
|
||||
#
|
||||
source_suffix = ['.rst', '.md']
|
||||
#source_suffix = '.rst'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
#
|
||||
# This is also used if you do content translation via gettext catalogs.
|
||||
# Usually you set "language" from the command line for these cases.
|
||||
language = None
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
# This pattern also affects html_static_path and html_extra_path.
|
||||
exclude_patterns = []
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = None
|
||||
|
||||
|
||||
# -- Options for HTML output -------------------------------------------------
|
||||
html_logo = 'ESPEasy/espeasy_logo.png'
|
||||
html_favicon = 'ESPEasy/favicon.ico'
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
#
|
||||
#html_theme = 'sphinx_rtd_theme'
|
||||
html_theme = 'bootstrap'
|
||||
html_theme_path = sphinx_bootstrap_theme.get_html_theme_path()
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
#
|
||||
# html_theme_options = {}
|
||||
#html_theme_options = {
|
||||
# 'canonical_url': '',
|
||||
# 'analytics_id': '',
|
||||
# 'logo_only': False,
|
||||
# 'display_version': True,
|
||||
# 'prev_next_buttons_location': 'bottom',
|
||||
# 'style_external_links': False,
|
||||
# # Toc options
|
||||
# 'collapse_navigation': True,
|
||||
# 'sticky_navigation': True,
|
||||
# 'navigation_depth': 4,
|
||||
# 'includehidden': True,
|
||||
# 'titles_only': False
|
||||
#}
|
||||
|
||||
html_theme_options = {
|
||||
# Navigation bar title. (Default: ``project`` value)
|
||||
'navbar_title': "ESPEasy",
|
||||
|
||||
# Tab name for entire site. (Default: "Site")
|
||||
'navbar_site_name': "Site",
|
||||
|
||||
# A list of tuples containing pages or urls to link to.
|
||||
# Valid tuples should be in the following forms:
|
||||
# (name, page) # a link to a page
|
||||
# (name, "/aa/bb", 1) # a link to an arbitrary relative url
|
||||
# (name, "http://example.com", True) # arbitrary absolute url
|
||||
# Note the "1" or "True" value above as the third argument to indicate
|
||||
# an arbitrary url.
|
||||
'navbar_links': [
|
||||
("Rules", "rules"),
|
||||
("Forum", "https://www.letscontrolit.com/forum/viewforum.php?f=1", True),
|
||||
],
|
||||
|
||||
# Render the next and previous page links in navbar. (Default: true)
|
||||
'navbar_sidebarrel': True,
|
||||
|
||||
# Render the current pages TOC in the navbar. (Default: true)
|
||||
'navbar_pagenav': True,
|
||||
|
||||
# Tab name for the current pages TOC. (Default: "Page")
|
||||
'navbar_pagenav_name': "Page",
|
||||
|
||||
# Global TOC depth for "site" navbar tab. (Default: 1)
|
||||
# Switching to -1 shows all levels.
|
||||
'globaltoc_depth': 2,
|
||||
|
||||
# Include hidden TOCs in Site navbar?
|
||||
#
|
||||
# Note: If this is "false", you cannot have mixed ``:hidden:`` and
|
||||
# non-hidden ``toctree`` directives in the same page, or else the build
|
||||
# will break.
|
||||
#
|
||||
# Values: "true" (default) or "false"
|
||||
'globaltoc_includehidden': "true",
|
||||
|
||||
# HTML navbar class (Default: "navbar") to attach to <div> element.
|
||||
# For black navbar, do "navbar navbar-inverse"
|
||||
'navbar_class': "navbar navbar-inverse",
|
||||
|
||||
# Fix navigation bar to top of page?
|
||||
# Values: "true" (default) or "false"
|
||||
'navbar_fixed_top': "true",
|
||||
|
||||
# Location of link to source.
|
||||
# Options are "nav" (default), "footer" or anything else to exclude.
|
||||
'source_link_position': "none",
|
||||
|
||||
# Bootswatch (http://bootswatch.com/) theme.
|
||||
#
|
||||
# Options are nothing (default) or the name of a valid theme
|
||||
# such as "cosmo" or "sandstone".
|
||||
#
|
||||
# The set of valid themes depend on the version of Bootstrap
|
||||
# that's used (the next config option).
|
||||
#
|
||||
# Currently, the supported themes are:
|
||||
# - Bootstrap 2: https://bootswatch.com/2
|
||||
# - Bootstrap 3: https://bootswatch.com/3
|
||||
'bootswatch_theme': "cerulean",
|
||||
|
||||
# Choose Bootstrap version.
|
||||
# Values: "3" (default) or "2" (in quotes)
|
||||
'bootstrap_version': "3",
|
||||
}
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
|
||||
# Custom sidebar templates, must be a dictionary that maps document names
|
||||
# to template names.
|
||||
#
|
||||
# The default sidebars (for documents that don't match any pattern) are
|
||||
# defined by theme itself. Builtin themes are using these templates by
|
||||
# default: ``['localtoc.html', 'relations.html', 'sourcelink.html',
|
||||
# 'searchbox.html']``.
|
||||
#
|
||||
# html_sidebars = {}
|
||||
|
||||
|
||||
# -- Options for HTMLHelp output ---------------------------------------------
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'ESPEasydoc'
|
||||
|
||||
|
||||
# -- Options for LaTeX output ------------------------------------------------
|
||||
|
||||
latex_elements = {
|
||||
# The paper size ('letterpaper' or 'a4paper').
|
||||
#
|
||||
# 'papersize': 'letterpaper',
|
||||
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#
|
||||
# 'pointsize': '10pt',
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#
|
||||
# 'preamble': '',
|
||||
|
||||
# Latex figure (float) alignment
|
||||
#
|
||||
# 'figure_align': 'htbp',
|
||||
}
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title,
|
||||
# author, documentclass [howto, manual, or own class]).
|
||||
latex_documents = [
|
||||
(master_doc, 'ESPEasy.tex', u'ESPEasy Documentation',
|
||||
u'Many', 'manual'),
|
||||
]
|
||||
|
||||
|
||||
# -- Options for manual page output ------------------------------------------
|
||||
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
(master_doc, 'espeasy', u'ESPEasy Documentation',
|
||||
[author], 1)
|
||||
]
|
||||
|
||||
|
||||
# -- Options for Texinfo output ----------------------------------------------
|
||||
|
||||
# Grouping the document tree into Texinfo files. List of tuples
|
||||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
(master_doc, 'ESPEasy', u'ESPEasy Documentation',
|
||||
author, 'ESPEasy', 'ESP82xx/ESP32 firmware to connect people with any level of experience to system automation.',
|
||||
'Miscellaneous'),
|
||||
]
|
||||
|
||||
|
||||
# -- Options for Epub output -------------------------------------------------
|
||||
|
||||
# Bibliographic Dublin Core info.
|
||||
epub_title = project
|
||||
|
||||
# The unique identifier of the text. This can be a ISBN number
|
||||
# or the project homepage.
|
||||
#
|
||||
# epub_identifier = ''
|
||||
|
||||
# A unique identification for the text.
|
||||
#
|
||||
# epub_uid = ''
|
||||
|
||||
# A list of files that should not be packed into the epub file.
|
||||
epub_exclude_files = ['search.html']
|
||||
|
||||
|
||||
# -- Extension configuration -------------------------------------------------
|
||||
|
||||
# -- Options for intersphinx extension ---------------------------------------
|
||||
|
||||
# Example configuration for intersphinx: refer to the Python standard library.
|
||||
intersphinx_mapping = {'https://docs.python.org/': None}
|
||||
|
||||
# -- Options for todo extension ----------------------------------------------
|
||||
|
||||
# If true, `todo` and `todoList` produce output, else they produce nothing.
|
||||
todo_include_todos = True
|
||||
@@ -0,0 +1,39 @@
|
||||
.. ESPEasy documentation master file, created by
|
||||
sphinx-quickstart on Sat Oct 06 22:34:34 2018.
|
||||
You can adapt this file completely to your liking, but it should at least
|
||||
contain the root `toctree` directive.
|
||||
|
||||
Welcome to ESPEasy's documentation!
|
||||
===================================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:caption: Table of Contents
|
||||
|
||||
ESPEasy/AboutUs.rst
|
||||
ESPEasy/FunctionBlocks.rst
|
||||
Controller/Controller.rst
|
||||
Plugin/Plugin.rst
|
||||
Rules/Rules.rst
|
||||
WiFi/WiFi.rst
|
||||
|
||||
.. raw:: latex
|
||||
|
||||
\appendix
|
||||
|
||||
|
||||
.. toctree::
|
||||
:caption: Appendix
|
||||
|
||||
Participate/Documentation.rst
|
||||
Reference/Command.rst
|
||||
Reference/SystemVariable.rst
|
||||
|
||||
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
||||
@@ -0,0 +1,82 @@
|
||||
#!/bin/bash
|
||||
|
||||
#
|
||||
# This script walks through the assets folder and minifys all JS, HTML, CSS and SVG files. It also generates
|
||||
# the corresponding constants that are added to the data.h file on esp8266_deauther folder.
|
||||
#
|
||||
# @Author Erick B. Tedeschi < erickbt86 [at] gmail [dot] com >
|
||||
# @Author Wandmalfarbe https://github.com/Wandmalfarbe
|
||||
#
|
||||
# See: https://github.com/letscontrolit/ESPEasy/issues/1671#issuecomment-415144898
|
||||
|
||||
outputfile="$(pwd)/data_h_temp"
|
||||
|
||||
rm $outputfile
|
||||
|
||||
function minify_html_css {
|
||||
file=$1
|
||||
curl -X POST -s --data-urlencode "input@$file" http://html-minifier.com/raw > /tmp/converter.temp
|
||||
}
|
||||
|
||||
function minify_js {
|
||||
file=$1
|
||||
curl -X POST -s --data-urlencode "input@$file" https://javascript-minifier.com/raw > /tmp/converter.temp
|
||||
}
|
||||
|
||||
function minify_svg {
|
||||
file=$1
|
||||
svgo -i /Users/User/Desktop/icons/tools.svg -o - > /tmp/converter.temp
|
||||
}
|
||||
|
||||
function ascii2hexCstyle {
|
||||
file_name=$(constFileName $1)
|
||||
result=$(cat /tmp/converter.temp | hexdump -ve '1/1 "0x%.2x,"')
|
||||
result=$(echo $result | sed 's/,$//')
|
||||
echo "const char DATA_${file_name}[] PROGMEM = {$result};"
|
||||
}
|
||||
|
||||
function constFileName {
|
||||
extension=$(echo $1 | egrep -io "(json|svg|css|js|html)$" | tr "[:lower:]" "[:upper:]")
|
||||
file=$(echo $1 | sed 's/\.json//' | sed 's/\.svg//' | sed 's/\.css//' | sed 's/\.html//' | sed 's/\.js//' | sed 's/\.\///' | tr '/' '_' | tr '.' '_' | tr '-' '_' | tr "[:lower:]" "[:upper:]")
|
||||
underscore="_"
|
||||
echo $file$underscore$extension
|
||||
}
|
||||
|
||||
|
||||
cd static
|
||||
file_list=$(find . -type f)
|
||||
|
||||
for file in $file_list; do
|
||||
echo "Processing: $file"
|
||||
file_name=$(constFileName $file)
|
||||
echo " Array Name: $file_name"
|
||||
|
||||
if [[ "$file" == *.min.js ]]; then
|
||||
echo " JS already minified"
|
||||
cat $file > /tmp/converter.temp
|
||||
ascii2hexCstyle $file >> $outputfile
|
||||
elif [[ "$file" == *.js ]]; then
|
||||
echo " JS minify"
|
||||
minify_js $file
|
||||
ascii2hexCstyle $file >> $outputfile
|
||||
elif [[ "$file" == *.min.css ]]; then
|
||||
echo " CSS already minified"
|
||||
cat $file > /tmp/converter.temp
|
||||
ascii2hexCstyle $file >> $outputfile
|
||||
elif [[ "$file" == *.html ]] || [[ "$file" == *.css ]]; then
|
||||
echo " HTML and CSS minify"
|
||||
minify_html_css $file
|
||||
ascii2hexCstyle $file >> $outputfile
|
||||
elif [[ "$file" == *.svg ]]; then
|
||||
echo " SVG minify"
|
||||
minify_svg $file
|
||||
ascii2hexCstyle $file >> $outputfile
|
||||
else
|
||||
echo " without minifier"
|
||||
cat $file > /tmp/converter.temp
|
||||
ascii2hexCstyle $file >> $outputfile
|
||||
fi
|
||||
echo ""
|
||||
sleep 1
|
||||
done
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 0x9000, 0x5000,
|
||||
otadata, data, ota, 0xe000, 0x2000,
|
||||
app0, app, ota_0, 0x10000, 0x140000,
|
||||
app1, app, ota_1, 0x150000,0x140000,
|
||||
eeprom, data, 0x99, 0x290000,0x1000,
|
||||
spiffs, data, spiffs, 0x291000,0x16F000,
|
||||
|
@@ -0,0 +1,7 @@
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 0x9000, 0x5000,
|
||||
otadata, data, ota, 0xe000, 0x2000,
|
||||
app0, app, ota_0, 0x10000, 0x1D0000,
|
||||
app1, app, ota_1, 0x1E0000,0x1D0000,
|
||||
eeprom, data, 0x99, 0x3B0000,0x1000,
|
||||
spiffs, data, spiffs, 0x3B1000,0x4F000,
|
||||
|
@@ -163,7 +163,7 @@ void loop(void) {
|
||||
Serial.print(rgb_sensor.atime_ms);
|
||||
Serial.print(F("ms (0x"));
|
||||
Serial.print(rgb_sensor.atime, HEX);
|
||||
Serial.println(F(")"));
|
||||
Serial.println(")");
|
||||
|
||||
Serial.print(F("Raw R:"));
|
||||
Serial.print(rgb_sensor.r);
|
||||
@@ -182,7 +182,7 @@ void loop(void) {
|
||||
Serial.print(rgb_sensor.saturation);
|
||||
Serial.print(F(" Sat75:"));
|
||||
Serial.print(rgb_sensor.saturation75);
|
||||
Serial.print(F(" "));
|
||||
Serial.print(" ");
|
||||
Serial.println(rgb_sensor.isSaturated ? "*SATURATED*" : "");
|
||||
|
||||
Serial.print(F("CPL:"));
|
||||
|
||||
@@ -33,7 +33,7 @@ void displaySensorDetails(void)
|
||||
Serial.print (F("Min Value: ")); Serial.print(sensor.min_value); Serial.println(F(" lux"));
|
||||
Serial.print (F("Resolution: ")); Serial.print(sensor.resolution); Serial.println(F(" lux"));
|
||||
Serial.println(F("------------------------------------"));
|
||||
Serial.println(F(""));
|
||||
Serial.println("");
|
||||
delay(500);
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ void configureSensor(void)
|
||||
Serial.print((tsl.getTiming() + 1) * 100, DEC);
|
||||
Serial.println(F(" ms"));
|
||||
Serial.println(F("------------------------------------"));
|
||||
Serial.println(F(""));
|
||||
Serial.println("");
|
||||
}
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -4207,7 +4207,7 @@ namespace Tbc {
|
||||
}
|
||||
else {
|
||||
spliceLine( indent, remainder, width-1 );
|
||||
lines.back() += "-";
|
||||
lines.back() += '-';
|
||||
}
|
||||
if( lines.size() == 1 )
|
||||
indent = _attr.indent;
|
||||
|
||||
+2
@@ -10,6 +10,8 @@
|
||||
- [Jonny Graham](https://github.com/jonnygraham/)
|
||||
- [Stu Fisher](https://github.com/stufisher/)
|
||||
- [Jorge Cisneros](https://github.com/jorgecis/)
|
||||
- [Denes Varga](https://github.com/denxhun/)
|
||||
- [Brett T. Warden](https://github.com/bwarden/)
|
||||
|
||||
All contributors can be found on the [contributors site](https://github.com/markszabo/IRremoteESP8266/graphs/contributors).
|
||||
|
||||
|
||||
@@ -40,3 +40,6 @@ tools/gc_decode
|
||||
.piolibdeps
|
||||
.clang_complete
|
||||
.gcc-flags.json
|
||||
|
||||
#Cygwin builds
|
||||
*.exe
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
[submodule "lib/googletest"]
|
||||
path = lib/googletest
|
||||
url = https://github.com/google/googletest.git
|
||||
branch = v1.8.x
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
## Contributors of this project
|
||||
### Main contributors & maintainers
|
||||
- [Mark Szabo](https://github.com/markszabo/) : Initial IR sending on ESP8266
|
||||
- [Sébastien Warin](https://github.com/sebastienwarin/) (http://sebastien.warin.fr) : Initial IR receiving on ESP8266
|
||||
- [David Conran](https://github.com/crankyoldgit/)
|
||||
- [Roi Dayan](https://github.com/roidayan/)
|
||||
- [Marcos de Alcântara Marinho](https://github.com/marcosamarinho/)
|
||||
- [Massimiliano Pinto](https://github.com/pintomax/)
|
||||
- [Darsh Patel](https://github.com/darshkpatel/)
|
||||
|
||||
All contributors can be found on the [contributors site](https://github.com/markszabo/IRremoteESP8266/graphs/contributors).
|
||||
|
||||
### Contributors of the [original project](https://github.com/z3t0/Arduino-IRremote) can be found on the [original project's contributors page](https://github.com/z3t0/Arduino-IRremote/blob/master/Contributors.md)
|
||||
@@ -1,152 +0,0 @@
|
||||
/*
|
||||
An Arduino sketch to emulate IR Daikin ARC433** remote control unit
|
||||
Read more on http://harizanov.com/2012/02/control-daikin-air-conditioner-over-the-internet/
|
||||
*/
|
||||
|
||||
#include <IRDaikinESP.h>
|
||||
|
||||
IRDaikinESP::IRDaikinESP(int pin) : _irsend(pin)
|
||||
{
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR IRDaikinESP::begin()
|
||||
{
|
||||
_irsend.begin();
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR IRDaikinESP::send()
|
||||
{
|
||||
_irsend.sendDaikin(daikin);
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR IRDaikinESP::checksum()
|
||||
{
|
||||
uint8_t sum = 0;
|
||||
uint8_t i;
|
||||
|
||||
for(i = 0; i <= 6; i++){
|
||||
sum += daikin[i];
|
||||
}
|
||||
|
||||
daikin[7] = sum &0xFF;
|
||||
sum=0;
|
||||
for(i = 8; i <= 25; i++){
|
||||
sum += daikin[i];
|
||||
}
|
||||
daikin[26] = sum &0xFF;
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR IRDaikinESP::on()
|
||||
{
|
||||
//state = ON;
|
||||
daikin[13] |= 0x01;
|
||||
checksum();
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR IRDaikinESP::off()
|
||||
{
|
||||
//state = OFF;
|
||||
daikin[13] &= 0xFE;
|
||||
checksum();
|
||||
}
|
||||
|
||||
uint8_t ICACHE_FLASH_ATTR IRDaikinESP::getPower()
|
||||
{
|
||||
return (daikin[13])&0x01;
|
||||
}
|
||||
|
||||
// DAIKIN_SILENT or DAIKIN_POWERFUL
|
||||
void ICACHE_FLASH_ATTR IRDaikinESP::setAux(uint8_t aux)
|
||||
{
|
||||
daikin[21] = aux;
|
||||
checksum();
|
||||
}
|
||||
|
||||
uint8_t ICACHE_FLASH_ATTR IRDaikinESP::getAux(){
|
||||
return daikin[21];
|
||||
}
|
||||
|
||||
|
||||
// Set the temp in deg C
|
||||
void ICACHE_FLASH_ATTR IRDaikinESP::setTemp(uint8_t temp)
|
||||
{
|
||||
if (temp < 18)
|
||||
temp = 18;
|
||||
else if (temp > 32)
|
||||
temp = 32;
|
||||
daikin[14] = (temp)*2;
|
||||
checksum();
|
||||
}
|
||||
|
||||
uint8_t ICACHE_FLASH_ATTR IRDaikinESP::getTemp()
|
||||
{
|
||||
return (daikin[14])/2;
|
||||
}
|
||||
|
||||
// Set the speed of the fan, 0-5, 0 is auto, 1-5 is the speed
|
||||
void ICACHE_FLASH_ATTR IRDaikinESP::setFan(uint8_t fan)
|
||||
{
|
||||
// Set the fan speed bits, leave low 4 bits alone
|
||||
uint8_t fanset;
|
||||
daikin[16] = daikin[16] & 0x0F;
|
||||
if (fan >= 1 && fan <= 5)
|
||||
fanset = 0x20 + (0x10 * fan);
|
||||
else
|
||||
fanset = 0xA0;
|
||||
daikin[16] = daikin[16] | fanset;
|
||||
checksum();
|
||||
}
|
||||
|
||||
uint8_t ICACHE_FLASH_ATTR IRDaikinESP::getFan()
|
||||
{
|
||||
uint8_t fan = daikin[16] >> 4;
|
||||
fan = fan - 2;
|
||||
if (fan > 5)
|
||||
fan = 0;
|
||||
return fan;
|
||||
}
|
||||
|
||||
uint8_t ICACHE_FLASH_ATTR IRDaikinESP::getMode()
|
||||
{/*
|
||||
DAIKIN_COOL
|
||||
DAIKIN_HEAT
|
||||
DAIKIN_FAN
|
||||
DAIKIN_AUTO
|
||||
DAIKIN_DRY
|
||||
*/
|
||||
return (daikin[13])>>4;
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR IRDaikinESP::setMode(uint8_t mode)
|
||||
{
|
||||
daikin[13]=mode<<4 | getPower();
|
||||
checksum();
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR IRDaikinESP::setSwingVertical(uint8_t swing)
|
||||
{
|
||||
if (swing)
|
||||
daikin[16] = daikin[16] | 0x0F;
|
||||
else
|
||||
daikin[16] = daikin[16] & 0xF0;
|
||||
checksum();
|
||||
}
|
||||
|
||||
uint8_t ICACHE_FLASH_ATTR IRDaikinESP::getSwingVertical()
|
||||
{
|
||||
return (daikin[16])&0x01;
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR IRDaikinESP::setSwingHorizontal(uint8_t swing)
|
||||
{
|
||||
if (swing)
|
||||
daikin[17] = daikin[17] | 0x0F;
|
||||
else
|
||||
daikin[17] = daikin[17] & 0xF0;
|
||||
checksum();
|
||||
}
|
||||
|
||||
uint8_t ICACHE_FLASH_ATTR IRDaikinESP::getSwingHorizontal()
|
||||
{
|
||||
return (daikin[17])&0x01;
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
|
||||
#include <IRremoteESP8266.h>
|
||||
#include <Arduino.h>
|
||||
|
||||
#define DAIKIN_COOL B011
|
||||
#define DAIKIN_HEAT B100
|
||||
#define DAIKIN_FAN B110
|
||||
#define DAIKIN_AUTO B000
|
||||
#define DAIKIN_DRY B010
|
||||
|
||||
#define DAIKIN_POWERFUL B00000010
|
||||
#define DAIKIN_SILENT B00100000
|
||||
|
||||
/*
|
||||
Daikin AC map
|
||||
byte 7= checksum of the first part (and last byte before a 29ms pause)
|
||||
byte 13=mode
|
||||
b7 = 0
|
||||
b6+b5+b4 = Mode
|
||||
Modes: b6+b5+b4
|
||||
011 = Cool
|
||||
100 = Heat (temp 23)
|
||||
110 = FAN (temp not shown, but 25)
|
||||
000 = Fully Automatic (temp 25)
|
||||
010 = DRY (temp 0xc0 = 96 degrees c)
|
||||
b3 = 0
|
||||
b2 = OFF timer set
|
||||
b1 = ON timer set
|
||||
b0 = Air Conditioner ON
|
||||
byte 14=temp*2 (Temp should be between 18 - 32)
|
||||
byte 16=Fan
|
||||
FAN control
|
||||
b7+b6+b5+b4 = Fan speed
|
||||
Fan: b7+b6+b5+b4
|
||||
0×30 = 1 bar
|
||||
0×40 = 2 bar
|
||||
0×50 = 3 bar
|
||||
0×60 = 4 bar
|
||||
0×70 = 5 bar
|
||||
0xa0 = Auto
|
||||
0xb0 = Not auto, moon + tree
|
||||
b3+b2+b1+b0 = Swing control up/down
|
||||
Swing control up/down:
|
||||
0000 = Swing up/down off
|
||||
1111 = Swing up/down on
|
||||
byte 17
|
||||
Swing control left/right:
|
||||
0000 = Swing left/right off
|
||||
1111 = Swing left/right on
|
||||
byte 21=Aux -> Powerful (bit 1), Silent (bit 5)
|
||||
byte 24=Aux2 -> Intelligent eye on (bit 7)
|
||||
byte 26= checksum of the second part
|
||||
*/
|
||||
|
||||
#define DAIKIN_COMMAND_LENGTH 27
|
||||
|
||||
class IRDaikinESP
|
||||
{
|
||||
public:
|
||||
IRDaikinESP(int pin);
|
||||
//: IRsend(pin){};
|
||||
|
||||
void send();
|
||||
|
||||
void begin();
|
||||
void on();
|
||||
void off();
|
||||
uint8_t getPower();
|
||||
|
||||
void setAux(uint8_t aux);
|
||||
uint8_t getAux();
|
||||
|
||||
void setTemp(uint8_t temp);
|
||||
uint8_t getTemp();
|
||||
|
||||
void setFan(uint8_t fan);
|
||||
uint8_t getFan();
|
||||
|
||||
uint8_t getMode();
|
||||
void setMode(uint8_t mode);
|
||||
|
||||
void setSwingVertical(uint8_t swing);
|
||||
uint8_t getSwingVertical();
|
||||
void setSwingHorizontal(uint8_t swing);
|
||||
uint8_t getSwingHorizontal();
|
||||
|
||||
private:
|
||||
// # of bytes per command
|
||||
unsigned char daikin[DAIKIN_COMMAND_LENGTH] = {
|
||||
0x11,0xDA,0x27,0xF0,0x00,0x00,0x00,0x20,
|
||||
//0 1 2 3 4 5 6 7
|
||||
0x11,0xDA,0x27,0x00,0x00,0x41,0x1E,0x00,
|
||||
//8 9 10 11 12 13 14 15
|
||||
0xB0,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x00,0x00,0xE3 };
|
||||
//16 17 18 19 20 21 22 23 24 25 26
|
||||
|
||||
void checksum();
|
||||
|
||||
IRsend _irsend;
|
||||
};
|
||||
@@ -1,233 +0,0 @@
|
||||
/*
|
||||
Code to emulate IR Kelvinator YALIF remote control unit, which should control
|
||||
at least the following Kelvinator A/C units:
|
||||
KSV26CRC, KSV26HRC, KSV35CRC, KSV35HRC, KSV53HRC, KSV62HRC, KSV70CRC,
|
||||
KSV70HRC, KSV80HRC.
|
||||
|
||||
Note:
|
||||
* Unsupported:
|
||||
- All Sleep modes.
|
||||
- All Timer modes.
|
||||
- "I Feel" button & mode.
|
||||
- Energy Saving mode.
|
||||
- Low Heat mode.
|
||||
- Farenheit.
|
||||
*/
|
||||
|
||||
#include <IRKelvinator.h>
|
||||
|
||||
IRKelvinatorAC::IRKelvinatorAC(int pin) : _irsend(pin) {
|
||||
stateReset();
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR IRKelvinatorAC::stateReset() {
|
||||
for (uint8_t i = 0; i < KELVINATOR_STATE_LENGTH; i++)
|
||||
remote_state[i] = 0x0;
|
||||
remote_state[3] = 0x50;
|
||||
remote_state[11] = 0x70;
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR IRKelvinatorAC::begin() {
|
||||
_irsend.begin();
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR IRKelvinatorAC::fixup() {
|
||||
// X-Fan mode is only valid in COOL or DRY modes.
|
||||
if (getMode() != KELVINATOR_COOL && getMode() != KELVINATOR_DRY)
|
||||
setXFan(false);
|
||||
checksum(); // Calculate the checksums
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR IRKelvinatorAC::send() {
|
||||
fixup(); // Ensure correct settings before sending.
|
||||
_irsend.sendKelvinator(remote_state);
|
||||
}
|
||||
|
||||
uint8_t* ICACHE_FLASH_ATTR IRKelvinatorAC::getRaw() {
|
||||
fixup(); // Ensure correct settings before sending.
|
||||
return remote_state;
|
||||
}
|
||||
|
||||
// Many Bothans died to bring us this information.
|
||||
void ICACHE_FLASH_ATTR IRKelvinatorAC::checksum() {
|
||||
// For each command + options block.
|
||||
for (uint8_t offset = 0; offset < KELVINATOR_STATE_LENGTH; offset += 8) {
|
||||
uint8_t sum = KELVINATOR_CHECKSUM_START;
|
||||
// Sum the lower half of the first 4 bytes of this block.
|
||||
for(uint8_t i = 0; i < 4; i++) {
|
||||
sum += (remote_state[i + offset] & 0xFU);
|
||||
}
|
||||
// then sum the upper half of the next 3 bytes.
|
||||
for(uint8_t i = 4; i < 7; i++) {
|
||||
sum += (remote_state[i + offset] >> 4);
|
||||
}
|
||||
// Trim it down to fit into the 4 bits allowed. i.e. Mod 16.
|
||||
sum &= 0xFU;
|
||||
// Place it into the IR code in the top half of the 8th & 16th byte.
|
||||
remote_state[7 + offset] = (sum << 4) | (remote_state[7 + offset] & 0xFU);
|
||||
}
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR IRKelvinatorAC::on() {
|
||||
//state = ON;
|
||||
remote_state[0] |= KELVINATOR_POWER;
|
||||
remote_state[8] = remote_state[0]; // Duplicate to the 2nd command chunk.
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR IRKelvinatorAC::off() {
|
||||
//state = OFF;
|
||||
remote_state[0] &= ~KELVINATOR_POWER;
|
||||
remote_state[8] = remote_state[0]; // Duplicate to the 2nd command chunk.
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR IRKelvinatorAC::setPower(bool state) {
|
||||
if (state)
|
||||
on();
|
||||
else
|
||||
off();
|
||||
}
|
||||
|
||||
bool ICACHE_FLASH_ATTR IRKelvinatorAC::getPower() {
|
||||
return ((remote_state[0] & KELVINATOR_POWER) != 0);
|
||||
}
|
||||
|
||||
// Set the temp. in deg C
|
||||
void ICACHE_FLASH_ATTR IRKelvinatorAC::setTemp(uint8_t temp) {
|
||||
temp = max(static_cast<uint8_t>(KELVINATOR_MIN_TEMP), temp);
|
||||
temp = min(static_cast<uint8_t>(KELVINATOR_MAX_TEMP), temp);
|
||||
remote_state[1] = (remote_state[1] & 0xF0U) | (temp - KELVINATOR_MIN_TEMP);
|
||||
remote_state[9] = remote_state[1]; // Duplicate to the 2nd command chunk.
|
||||
}
|
||||
|
||||
// Return the set temp. in deg C
|
||||
uint8_t ICACHE_FLASH_ATTR IRKelvinatorAC::getTemp() {
|
||||
return ((remote_state[1] & 0xFU) + KELVINATOR_MIN_TEMP);
|
||||
}
|
||||
|
||||
// Set the speed of the fan, 0-5, 0 is auto, 1-5 is the speed
|
||||
void ICACHE_FLASH_ATTR IRKelvinatorAC::setFan(uint8_t fan) {
|
||||
fan = min(static_cast<uint8_t>(KELVINATOR_FAN_MAX), fan); // Bounds check
|
||||
|
||||
// Only change things if we need to.
|
||||
if (fan != getFan()) {
|
||||
// Set the basic fan values.
|
||||
uint8_t fan_basic = min(static_cast<uint8_t>(KELVINATOR_BASIC_FAN_MAX), fan);
|
||||
remote_state[0] = (remote_state[0] & KELVINATOR_BASIC_FAN_MASK) |
|
||||
(fan_basic << KELVINATOR_FAN_OFFSET);
|
||||
remote_state[8] = remote_state[0]; // Duplicate to the 2nd command chunk.
|
||||
// Set the advanced(?) fan value.
|
||||
remote_state[14] = (remote_state[14] & KELVINATOR_FAN_MASK) |
|
||||
(fan << KELVINATOR_FAN_OFFSET);
|
||||
setTurbo(false); // Turbo mode is turned off if we change the fan settings.
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t ICACHE_FLASH_ATTR IRKelvinatorAC::getFan() {
|
||||
return ((remote_state[14] & ~KELVINATOR_FAN_MASK) >> KELVINATOR_FAN_OFFSET);
|
||||
}
|
||||
|
||||
uint8_t ICACHE_FLASH_ATTR IRKelvinatorAC::getMode() {
|
||||
/*
|
||||
KELVINATOR_AUTO
|
||||
KELVINATOR_COOL
|
||||
KELVINATOR_DRY
|
||||
KELVINATOR_FAN
|
||||
KELVINATOR_HEAT
|
||||
*/
|
||||
return (remote_state[0] & ~KELVINATOR_MODE_MASK);
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR IRKelvinatorAC::setMode(uint8_t mode) {
|
||||
// If we get an unexpected mode, default to AUTO.
|
||||
if (mode > KELVINATOR_HEAT) mode = KELVINATOR_AUTO;
|
||||
remote_state[0] = (remote_state[0] & KELVINATOR_MODE_MASK) | mode;
|
||||
remote_state[8] = remote_state[0]; // Duplicate to the 2nd command chunk.
|
||||
if (mode == KELVINATOR_AUTO)
|
||||
// When the remote is set to Auto, it defaults to 25C and doesn't show it.
|
||||
setTemp(KELVINATOR_AUTO_TEMP);
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR IRKelvinatorAC::setSwingVertical(bool state) {
|
||||
if (state) {
|
||||
remote_state[0] |= KELVINATOR_VENT_SWING;
|
||||
remote_state[4] |= KELVINATOR_VENT_SWING_V;
|
||||
}
|
||||
else {
|
||||
remote_state[4] &= ~KELVINATOR_VENT_SWING_V;
|
||||
if (! getSwingHorizontal())
|
||||
remote_state[0] &= ~KELVINATOR_VENT_SWING;
|
||||
}
|
||||
remote_state[8] = remote_state[0]; // Duplicate to the 2nd command chunk.
|
||||
}
|
||||
|
||||
bool ICACHE_FLASH_ATTR IRKelvinatorAC::getSwingVertical() {
|
||||
return ((remote_state[4] & KELVINATOR_VENT_SWING_V) != 0);
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR IRKelvinatorAC::setSwingHorizontal(bool state) {
|
||||
if (state) {
|
||||
remote_state[0] |= KELVINATOR_VENT_SWING;
|
||||
remote_state[4] |= KELVINATOR_VENT_SWING_H;
|
||||
}
|
||||
else {
|
||||
remote_state[4] &= ~KELVINATOR_VENT_SWING_H;
|
||||
if (! getSwingVertical())
|
||||
remote_state[0] &= ~KELVINATOR_VENT_SWING;
|
||||
}
|
||||
remote_state[8] = remote_state[0]; // Duplicate to the 2nd command chunk.
|
||||
}
|
||||
|
||||
bool ICACHE_FLASH_ATTR IRKelvinatorAC::getSwingHorizontal() {
|
||||
return ((remote_state[4] & KELVINATOR_VENT_SWING_H) != 0);
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR IRKelvinatorAC::setQuiet(bool state) {
|
||||
remote_state[12] &= ~KELVINATOR_QUIET;
|
||||
remote_state[12] |= (state << KELVINATOR_QUIET_OFFSET);
|
||||
}
|
||||
|
||||
bool ICACHE_FLASH_ATTR IRKelvinatorAC::getQuiet() {
|
||||
return ((remote_state[12] & KELVINATOR_QUIET) != 0);
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR IRKelvinatorAC::setIonFilter(bool state) {
|
||||
remote_state[2] &= ~KELVINATOR_ION_FILTER;
|
||||
remote_state[2] |= (state << KELVINATOR_ION_FILTER_OFFSET);
|
||||
remote_state[10] = remote_state[2]; // Duplicate to the 2nd command chunk.
|
||||
}
|
||||
|
||||
bool ICACHE_FLASH_ATTR IRKelvinatorAC::getIonFilter() {
|
||||
return ((remote_state[2] & KELVINATOR_ION_FILTER) != 0);
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR IRKelvinatorAC::setLight(bool state) {
|
||||
remote_state[2] &= ~KELVINATOR_LIGHT;
|
||||
remote_state[2] |= (state << KELVINATOR_LIGHT_OFFSET);
|
||||
remote_state[10] = remote_state[2]; // Duplicate to the 2nd command chunk.
|
||||
}
|
||||
|
||||
bool ICACHE_FLASH_ATTR IRKelvinatorAC::getLight() {
|
||||
return ((remote_state[2] & KELVINATOR_LIGHT) != 0);
|
||||
}
|
||||
|
||||
// Note: XFan mode is only valid in Cool or Dry mode.
|
||||
void ICACHE_FLASH_ATTR IRKelvinatorAC::setXFan(bool state) {
|
||||
remote_state[2] &= ~KELVINATOR_XFAN;
|
||||
remote_state[2] |= (state << KELVINATOR_XFAN_OFFSET);
|
||||
remote_state[10] = remote_state[2]; // Duplicate to the 2nd command chunk.
|
||||
}
|
||||
|
||||
bool ICACHE_FLASH_ATTR IRKelvinatorAC::getXFan() {
|
||||
return ((remote_state[2] & KELVINATOR_XFAN) != 0);
|
||||
}
|
||||
|
||||
// Note: Turbo mode is turned off if the fan speed is changed.
|
||||
void ICACHE_FLASH_ATTR IRKelvinatorAC::setTurbo(bool state) {
|
||||
remote_state[2] &= ~KELVINATOR_TURBO;
|
||||
remote_state[2] |= (state << KELVINATOR_TURBO_OFFSET);
|
||||
remote_state[10] = remote_state[2]; // Duplicate to the 2nd command chunk.
|
||||
}
|
||||
|
||||
bool ICACHE_FLASH_ATTR IRKelvinatorAC::getTurbo() {
|
||||
return ((remote_state[2] & KELVINATOR_TURBO) != 0);
|
||||
}
|
||||
@@ -1,160 +0,0 @@
|
||||
|
||||
#include <IRremoteESP8266.h>
|
||||
#include <Arduino.h>
|
||||
|
||||
#define KELVINATOR_AUTO 0U
|
||||
#define KELVINATOR_COOL 1U
|
||||
#define KELVINATOR_DRY 2U
|
||||
#define KELVINATOR_FAN 3U
|
||||
#define KELVINATOR_HEAT 4U
|
||||
#define KELVINATOR_MODE_MASK 0xF8U
|
||||
#define KELVINATOR_POWER 8U
|
||||
#define KELVINATOR_FAN_OFFSET 4U
|
||||
#define KELVINATOR_BASIC_FAN_MAX 3U
|
||||
#define KELVINATOR_BASIC_FAN_MASK uint8_t(0xFFU ^ (3U << KELVINATOR_FAN_OFFSET))
|
||||
#define KELVINATOR_FAN_MASK uint8_t(0xFFU ^ (7U << KELVINATOR_FAN_OFFSET))
|
||||
#define KELVINATOR_FAN_MAX 5U
|
||||
#define KELVINATOR_VENT_SWING_OFFSET 6U
|
||||
#define KELVINATOR_VENT_SWING uint8_t(1U << KELVINATOR_VENT_SWING_OFFSET)
|
||||
#define KELVINATOR_VENT_SWING_V uint8_t(1U)
|
||||
#define KELVINATOR_VENT_SWING_H uint8_t(1U << 4)
|
||||
#define KELVINATOR_SLEEP_1_AND_3 uint8_t(1U << 7)
|
||||
#define KELVINATOR_MIN_TEMP 16U // 16C
|
||||
#define KELVINATOR_MAX_TEMP 30U // 30C
|
||||
#define KELVINATOR_AUTO_TEMP 25U // 25C
|
||||
#define KELVINATOR_CHECKSUM_START 10U
|
||||
#define KELVINATOR_QUIET_OFFSET 7U
|
||||
#define KELVINATOR_QUIET uint8_t(1U << KELVINATOR_QUIET_OFFSET)
|
||||
#define KELVINATOR_ION_FILTER_OFFSET 6U
|
||||
#define KELVINATOR_ION_FILTER uint8_t(1U << KELVINATOR_ION_FILTER_OFFSET)
|
||||
#define KELVINATOR_LIGHT_OFFSET 5U
|
||||
#define KELVINATOR_LIGHT uint8_t(1U << KELVINATOR_LIGHT_OFFSET)
|
||||
#define KELVINATOR_XFAN_OFFSET 7U
|
||||
#define KELVINATOR_XFAN uint8_t(1U << KELVINATOR_XFAN_OFFSET)
|
||||
#define KELVINATOR_TURBO_OFFSET 4U
|
||||
#define KELVINATOR_TURBO uint8_t(1U << KELVINATOR_TURBO_OFFSET)
|
||||
|
||||
|
||||
/*
|
||||
Kelvinator AC map
|
||||
|
||||
(header mark and space)
|
||||
byte 0 = Basic Modes
|
||||
b2-0 = Modes
|
||||
Modes:
|
||||
000 = Auto (temp = 25C)
|
||||
001 = Cool
|
||||
010 = Dry (temp = 25C, but not shown)
|
||||
011 = Fan
|
||||
100 = Heat
|
||||
b3 = Power Status (1 = On, 0 = Off)
|
||||
b5-4 = Fan (Basic modes)
|
||||
Fan:
|
||||
00 = Auto
|
||||
01 = Fan 1
|
||||
10 = Fan 2
|
||||
11 = Fan 3 or higher (See byte 14)
|
||||
b6 = Vent swing (1 = On, 0 = Off) (See byte 4)
|
||||
b7 = Sleep Modes 1 & 3 (1 = On, 0 = Off)
|
||||
byte 1 = Temperature
|
||||
b3-0: Degrees C.
|
||||
0000 (0) = 16C
|
||||
0001 (1) = 17C
|
||||
0010 (2) = 18C
|
||||
...
|
||||
1101 (13) = 29C
|
||||
1110 (14) = 30C
|
||||
byte 2 = Extras
|
||||
b3-0 = UNKNOWN, typically 0.
|
||||
b4 = Turbo Fan (1 = On, 0 = Off)
|
||||
b5 = Light (Display) (1 = On, 0 = Off)
|
||||
b6 = Ion Filter (1 = On, 0 = Off)
|
||||
b7 = X-Fan (Fan runs for a while after power off) (1 = On, 0 = Off)
|
||||
byte 3 = Section Indicator
|
||||
b3-0 = Unused (Typically 0)
|
||||
b5-4 = Unknown (possibly timer related) (Typically B01)
|
||||
b7-6 = End of command block (B01)
|
||||
(B010 marker and a gap of 20ms)
|
||||
byte 4 = Extended options
|
||||
b0 = Swing Vent Vertical (1 = On, 0 = Off)
|
||||
b4 = Swing Vent Horizontal (1 = On, 0 = Off)
|
||||
byte 5-6 = Timer related. Typically 0 except when timer in use.
|
||||
byte 7 = checksum
|
||||
b3-0 = Unknown (Used in Timer mode)
|
||||
b7-4 = checksum of the previous bytes (0-6)
|
||||
(gap of 40ms)
|
||||
(header mark and space)
|
||||
byte 8 = Repeat of byte 0
|
||||
byte 9 = Repeat of byte 1
|
||||
byte 10 = Repeat of byte 2
|
||||
byte 11 = Section Indicator
|
||||
b3-0 = Unused (Typically 0)
|
||||
b5-4 = Unknown (possibly timer related) (Typically B11)
|
||||
b7-6 = End of command block (B01)
|
||||
(B010 marker and a gap of 20ms)
|
||||
byte 12 = Extended options
|
||||
b0 = Sleep mode 2 (1 = On, 0=Off)
|
||||
b6-1 = Unknown (Used in Sleep Mode 3, Typically B000000)
|
||||
b7 = Quiet Mode (1 = On, 0=Off)
|
||||
byte 13 = Unknown (Sleep Mode 3 related, Typically 0x00)
|
||||
byte 14 = Fan control
|
||||
b3-0 = Unknown (Sleep Mode 3 related, Typically B0000)
|
||||
b6-4 = Fan speed
|
||||
B000 (0) = Automatic
|
||||
B001 (1) = Fan 1
|
||||
B010 (2) = Fan 2
|
||||
B011 (3) = Fan 3
|
||||
B100 (4) = Fan 4
|
||||
B101 (5) = Fan 5
|
||||
byte 15 = checksum
|
||||
b3-0 = Unknown (Typically B0000)
|
||||
b7-4 = checksum of the previous bytes (8-14)
|
||||
*/
|
||||
|
||||
#define KELVINATOR_STATE_LENGTH 16
|
||||
|
||||
class IRKelvinatorAC
|
||||
{
|
||||
public:
|
||||
IRKelvinatorAC(int pin);
|
||||
//: IRsend(pin){};
|
||||
|
||||
void stateReset();
|
||||
void send();
|
||||
|
||||
void begin();
|
||||
void on();
|
||||
void off();
|
||||
void setPower(bool state);
|
||||
bool getPower();
|
||||
void setTemp(uint8_t temp);
|
||||
uint8_t getTemp();
|
||||
void setFan(uint8_t fan);
|
||||
uint8_t getFan();
|
||||
void setMode(uint8_t mode);
|
||||
uint8_t getMode();
|
||||
void setSwingVertical(bool state);
|
||||
bool getSwingVertical();
|
||||
void setSwingHorizontal(bool state);
|
||||
bool getSwingHorizontal();
|
||||
void setQuiet(bool state);
|
||||
bool getQuiet();
|
||||
void setIonFilter(bool state);
|
||||
bool getIonFilter();
|
||||
void setLight(bool state);
|
||||
bool getLight();
|
||||
void setXFan(bool state);
|
||||
bool getXFan();
|
||||
void setTurbo(bool state);
|
||||
bool getTurbo();
|
||||
uint8_t* getRaw();
|
||||
|
||||
|
||||
private:
|
||||
// The state of the IR remote in IR code form.
|
||||
uint8_t remote_state[KELVINATOR_STATE_LENGTH];
|
||||
|
||||
void checksum();
|
||||
void fixup();
|
||||
IRsend _irsend;
|
||||
};
|
||||
@@ -1,148 +0,0 @@
|
||||
/*
|
||||
Code to emulate Mitsubishi A/C IR remote control unit.
|
||||
Inspired and derived from the work done at:
|
||||
https://github.com/r45635/HVAC-IR-Control
|
||||
|
||||
Warning: Consider this very alpha code. Seems to work, but not validated.
|
||||
|
||||
Equipment it seems compatible with:
|
||||
* <Add models (A/C & remotes) you've gotten it working with here>
|
||||
*/
|
||||
|
||||
#include <IRMitsubishiAC.h>
|
||||
|
||||
// Initialise the object.
|
||||
IRMitsubishiAC::IRMitsubishiAC(int pin) : _irsend(pin) {
|
||||
stateReset();
|
||||
}
|
||||
|
||||
// Reset the state of the remote to a known good state/sequence.
|
||||
void ICACHE_FLASH_ATTR IRMitsubishiAC::stateReset() {
|
||||
for (uint8_t i = 0; i < MITSUBISHI_AC_STATE_LENGTH; i++)
|
||||
remote_state[i] = known_good_state[i];
|
||||
checksum(); // Calculate the checksum
|
||||
}
|
||||
|
||||
// Configure the pin for output.
|
||||
void ICACHE_FLASH_ATTR IRMitsubishiAC::begin() {
|
||||
_irsend.begin();
|
||||
}
|
||||
|
||||
// Send the current desired state to the IR LED.
|
||||
void ICACHE_FLASH_ATTR IRMitsubishiAC::send() {
|
||||
checksum(); // Ensure correct checksum before sending.
|
||||
_irsend.sendMitsubishiAC(remote_state);
|
||||
}
|
||||
|
||||
// Return a pointer to the internal state date of the remote.
|
||||
uint8_t* ICACHE_FLASH_ATTR IRMitsubishiAC::getRaw() {
|
||||
checksum();
|
||||
return remote_state;
|
||||
}
|
||||
|
||||
// Calculate the checksum for the current internal state of the remote.
|
||||
void ICACHE_FLASH_ATTR IRMitsubishiAC::checksum() {
|
||||
uint8_t sum = 0;
|
||||
// Checksum is simple addition of all previous bytes stored
|
||||
// as a 8 bit value.
|
||||
for (uint8_t i = 0; i < 17; i++)
|
||||
sum += remote_state[i];
|
||||
remote_state[17] = sum & 0xFFU;
|
||||
}
|
||||
|
||||
// Set the requested power state of the A/C to off.
|
||||
void ICACHE_FLASH_ATTR IRMitsubishiAC::on() {
|
||||
//state = ON;
|
||||
remote_state[5] |= MITSUBISHI_AC_POWER;
|
||||
}
|
||||
|
||||
// Set the requested power state of the A/C to off.
|
||||
void ICACHE_FLASH_ATTR IRMitsubishiAC::off() {
|
||||
//state = OFF;
|
||||
remote_state[5] &= ~MITSUBISHI_AC_POWER;
|
||||
}
|
||||
|
||||
// Set the requested power state of the A/C.
|
||||
void ICACHE_FLASH_ATTR IRMitsubishiAC::setPower(bool state) {
|
||||
if (state)
|
||||
on();
|
||||
else
|
||||
off();
|
||||
}
|
||||
|
||||
// Return the requested power state of the A/C.
|
||||
bool ICACHE_FLASH_ATTR IRMitsubishiAC::getPower() {
|
||||
return((remote_state[5] & MITSUBISHI_AC_POWER) != 0);
|
||||
}
|
||||
|
||||
// Set the temp. in deg C
|
||||
void ICACHE_FLASH_ATTR IRMitsubishiAC::setTemp(uint8_t temp) {
|
||||
temp = max(static_cast<uint8_t>(MITSUBISHI_AC_MIN_TEMP), temp);
|
||||
temp = min(static_cast<uint8_t>(MITSUBISHI_AC_MAX_TEMP), temp);
|
||||
remote_state[7] = temp - MITSUBISHI_AC_MIN_TEMP;
|
||||
}
|
||||
|
||||
// Return the set temp. in deg C
|
||||
uint8_t ICACHE_FLASH_ATTR IRMitsubishiAC::getTemp() {
|
||||
return(remote_state[7] + MITSUBISHI_AC_MIN_TEMP);
|
||||
}
|
||||
|
||||
// Set the speed of the fan, 0-6.
|
||||
// 0 is auto, 1-5 is the speed, 6 is silent.
|
||||
void ICACHE_FLASH_ATTR IRMitsubishiAC::setFan(uint8_t fan) {
|
||||
// Bounds check
|
||||
if (fan > MITSUBISHI_AC_FAN_SILENT)
|
||||
fan = MITSUBISHI_AC_FAN_MAX; // Set the fan to maximum if out of range.
|
||||
if (fan == MITSUBISHI_AC_FAN_AUTO) { // Automatic is a special case.
|
||||
remote_state[9] = B10000000 | (remote_state[9] & B01111000);
|
||||
return;
|
||||
} else if (fan >= MITSUBISHI_AC_FAN_MAX) {
|
||||
fan--; // There is no spoon^H^H^Heed 5 (max), pretend it doesn't exist.
|
||||
}
|
||||
remote_state[9] |= fan;
|
||||
}
|
||||
|
||||
// Return the requested state of the unit's fan.
|
||||
uint8_t ICACHE_FLASH_ATTR IRMitsubishiAC::getFan() {
|
||||
uint8_t fan = remote_state[9] & B111;
|
||||
if (fan == MITSUBISHI_AC_FAN_MAX)
|
||||
return MITSUBISHI_AC_FAN_SILENT;
|
||||
return fan;
|
||||
}
|
||||
|
||||
// Return the requested climate operation mode of the a/c unit.
|
||||
uint8_t ICACHE_FLASH_ATTR IRMitsubishiAC::getMode() {
|
||||
/*
|
||||
MITSUBISHI_AC_AUTO
|
||||
MITSUBISHI_AC_COOL
|
||||
MITSUBISHI_AC_DRY
|
||||
MITSUBISHI_AC_HEAT
|
||||
*/
|
||||
return(remote_state[6]);
|
||||
}
|
||||
|
||||
// Set the requested climate operation mode of the a/c unit.
|
||||
void ICACHE_FLASH_ATTR IRMitsubishiAC::setMode(uint8_t mode) {
|
||||
// If we get an unexpected mode, default to AUTO.
|
||||
switch (mode) {
|
||||
case MITSUBISHI_AC_AUTO: break;
|
||||
case MITSUBISHI_AC_COOL: break;
|
||||
case MITSUBISHI_AC_DRY: break;
|
||||
case MITSUBISHI_AC_HEAT: break;
|
||||
default: mode = MITSUBISHI_AC_AUTO;
|
||||
}
|
||||
remote_state[6] = mode;
|
||||
}
|
||||
|
||||
// Set the requested vane operation mode of the a/c unit.
|
||||
void ICACHE_FLASH_ATTR IRMitsubishiAC::setVane(uint8_t mode) {
|
||||
mode = max(mode, static_cast<uint8_t>(B111)); // bounds check
|
||||
mode |= B1000;
|
||||
mode <<= 3;
|
||||
remote_state[9] |= mode;
|
||||
}
|
||||
|
||||
// Return the requested vane operation mode of the a/c unit.
|
||||
uint8_t ICACHE_FLASH_ATTR IRMitsubishiAC::getVane() {
|
||||
return ((remote_state[9] & B00111000) >> 3);
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
|
||||
#include <IRremoteESP8266.h>
|
||||
#include <Arduino.h>
|
||||
|
||||
#define MITSUBISHI_AC_AUTO 0x20U
|
||||
#define MITSUBISHI_AC_COOL 0x18U
|
||||
#define MITSUBISHI_AC_DRY 0x10U
|
||||
#define MITSUBISHI_AC_HEAT 0x08U
|
||||
#define MITSUBISHI_AC_POWER 0x20U
|
||||
#define MITSUBISHI_AC_FAN_AUTO 0U
|
||||
#define MITSUBISHI_AC_FAN_MAX 5U
|
||||
#define MITSUBISHI_AC_FAN_SILENT 6U
|
||||
#define MITSUBISHI_AC_MIN_TEMP 16U // 16C
|
||||
#define MITSUBISHI_AC_MAX_TEMP 31U // 31C
|
||||
#define MITSUBISHI_AC_VANE_AUTO 0U
|
||||
#define MITSUBISHI_AC_VANE_AUTO_MOVE 7U
|
||||
#define MITSUBISHI_AC_STATE_LENGTH 18
|
||||
|
||||
class IRMitsubishiAC
|
||||
{
|
||||
public:
|
||||
IRMitsubishiAC(int pin);
|
||||
|
||||
void stateReset();
|
||||
void send();
|
||||
|
||||
void begin();
|
||||
void on();
|
||||
void off();
|
||||
void setPower(bool state);
|
||||
bool getPower();
|
||||
void setTemp(uint8_t temp);
|
||||
uint8_t getTemp();
|
||||
void setFan(uint8_t fan);
|
||||
uint8_t getFan();
|
||||
void setMode(uint8_t mode);
|
||||
uint8_t getMode();
|
||||
void setVane(uint8_t mode);
|
||||
uint8_t getVane();
|
||||
uint8_t* getRaw();
|
||||
|
||||
|
||||
private:
|
||||
// The state of the IR remote in IR code form.
|
||||
// Known good state obtained from:
|
||||
// https://github.com/r45635/HVAC-IR-Control/blob/master/HVAC_ESP8266/HVAC_ESP8266.ino#L108
|
||||
uint8_t known_good_state[MITSUBISHI_AC_STATE_LENGTH] = { 0x23, 0xCB, 0x26, 0x01, 0x00, 0x20, 0x08, 0x06, 0x30, 0x45, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F };
|
||||
uint8_t remote_state[MITSUBISHI_AC_STATE_LENGTH];
|
||||
|
||||
void checksum();
|
||||
IRsend _irsend;
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,237 +0,0 @@
|
||||
/***************************************************
|
||||
* IRremote for ESP8266
|
||||
*
|
||||
* Based on the IRremote library for Arduino by Ken Shirriff
|
||||
* Version 0.11 August, 2009
|
||||
* Copyright 2009 Ken Shirriff
|
||||
* For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.html
|
||||
*
|
||||
* Edited by Mitra to add new controller SANYO
|
||||
*
|
||||
* Interrupt code based on NECIRrcv by Joe Knapp
|
||||
* http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1210243556
|
||||
* Also influenced by http://zovirl.com/2008/11/12/building-a-universal-remote-with-an-arduino/
|
||||
*
|
||||
* JVC and Panasonic protocol added by Kristian Lauszus (Thanks to zenwheel and other people at the original blog post)
|
||||
* LG added by Darryl Smith (based on the JVC protocol)
|
||||
* Whynter A/C ARC-110WD added by Francesco Meschia
|
||||
* Coolix A/C / heatpump added by bakrus
|
||||
* Denon: sendDenon, decodeDenon added by Massimiliano Pinto
|
||||
(from https://github.com/z3t0/Arduino-IRremote/blob/master/ir_Denon.cpp)
|
||||
* Kelvinator A/C and Sherwood added by crankyoldgit
|
||||
* Updated by markszabo (https://github.com/markszabo/IRremoteESP8266) for sending IR code on ESP8266
|
||||
* Updated by Sebastien Warin (http://sebastien.warin.fr) for receiving IR code on ESP8266
|
||||
*
|
||||
* Updated by sillyfrog for Daikin, adopted from
|
||||
* (https://github.com/mharizanov/Daikin-AC-remote-control-over-the-Internet/)
|
||||
*
|
||||
* GPL license, all text above must be included in any redistribution
|
||||
****************************************************/
|
||||
|
||||
#ifndef IRremote_h
|
||||
#define IRremote_h
|
||||
|
||||
#include <stdint.h>
|
||||
#include "IRremoteInt.h"
|
||||
|
||||
// The following are compile-time library options.
|
||||
// If you change them, recompile the library.
|
||||
// If DEBUG is defined, a lot of debugging output will be printed during decoding.
|
||||
// TEST must be defined for the IRtest unittests to work. It will make some
|
||||
// methods virtual, which will be slightly slower, which is why it is optional.
|
||||
//#define DEBUG
|
||||
//#define TEST
|
||||
|
||||
/*
|
||||
* Always add to the end of the list and should never remove entries
|
||||
* or change order. Projects may save the type number for later usage
|
||||
* so numbering should always stay the same.
|
||||
*/
|
||||
enum decode_type_t {
|
||||
UNKNOWN = -1,
|
||||
UNUSED = 0,
|
||||
RC5,
|
||||
RC6,
|
||||
NEC,
|
||||
PIONEER,
|
||||
SONY,
|
||||
PANASONIC,
|
||||
JVC,
|
||||
SAMSUNG,
|
||||
WHYNTER,
|
||||
AIWA_RC_T501,
|
||||
LG,
|
||||
SANYO,
|
||||
MITSUBISHI,
|
||||
DISH,
|
||||
SHARP,
|
||||
COOLIX,
|
||||
DAIKIN,
|
||||
DENON,
|
||||
KELVINATOR,
|
||||
SHERWOOD,
|
||||
MITSUBISHI_AC,
|
||||
RCMM
|
||||
};
|
||||
|
||||
// Results returned from the decoder
|
||||
class decode_results {
|
||||
public:
|
||||
int decode_type; // NEC, SONY, RC5, UNKNOWN
|
||||
union { // This is used for decoding Panasonic and Sharp data
|
||||
unsigned int panasonicAddress;
|
||||
unsigned int sharpAddress;
|
||||
};
|
||||
unsigned long value; // Decoded value
|
||||
int bits; // Number of bits in decoded value
|
||||
volatile unsigned int *rawbuf; // Raw intervals in .5 us ticks
|
||||
int rawlen; // Number of records in rawbuf.
|
||||
bool overflow;
|
||||
};
|
||||
|
||||
// Decoded value for NEC when a repeat code is received
|
||||
#define REPEAT 0xffffffff
|
||||
|
||||
#define SEND_PROTOCOL_NEC case NEC: sendNEC(data, nbits); break;
|
||||
#define SEND_PROTOCOL_PIONEER case PIONEER: sendPioneer(data, nbits, 1, 0ul); break;
|
||||
#define SEND_PROTOCOL_SONY case SONY: sendSony(data, nbits); break;
|
||||
#define SEND_PROTOCOL_RC5 case RC5: sendRC5(data, nbits); break;
|
||||
#define SEND_PROTOCOL_RC6 case RC6: sendRC6(data, nbits); break;
|
||||
#define SEND_PROTOCOL_DISH case DISH: sendDISH(data, nbits); break;
|
||||
#define SEND_PROTOCOL_JVC case JVC: sendJVC(data, nbits, 0); break;
|
||||
#define SEND_PROTOCOL_SAMSUNG case SAMSUNG: sendSAMSUNG(data, nbits); break;
|
||||
#define SEND_PROTOCOL_LG case LG: sendLG(data, nbits); break;
|
||||
#define SEND_PROTOCOL_WHYNTER case WHYNTER: sendWhynter(data, nbits); break;
|
||||
#define SEND_PROTOCOL_COOLIX case COOLIX: sendCOOLIX(data, nbits); break;
|
||||
#define SEND_PROTOCOL_DENON case DENON: sendDenon(data, nbits); break;
|
||||
#define SEND_PROTOCOL_SHERWOOD case SHERWOOD: sendSherwood(data, nbits); break;
|
||||
#define SEND_PROTOCOL_RCMM case RCMM: sendRCMM(data, nbits); break;
|
||||
|
||||
|
||||
// main class for receiving IR
|
||||
class IRrecv
|
||||
{
|
||||
public:
|
||||
IRrecv(int recvpin);
|
||||
bool decode(decode_results *results, irparams_t *save=NULL);
|
||||
void enableIRIn();
|
||||
void disableIRIn();
|
||||
void resume();
|
||||
private:
|
||||
// These are called by decode
|
||||
void copyIrParams(irparams_t *dest);
|
||||
int getRClevel(decode_results *results, int *offset, int *used, int t1);
|
||||
bool decodeNEC(decode_results *results);
|
||||
bool decodeSony(decode_results *results);
|
||||
bool decodeSanyo(decode_results *results);
|
||||
bool decodeMitsubishi(decode_results *results);
|
||||
bool decodeRC5(decode_results *results);
|
||||
bool decodeRC6(decode_results *results);
|
||||
bool decodeRCMM(decode_results *results);
|
||||
bool decodePanasonic(decode_results *results);
|
||||
bool decodeLG(decode_results *results);
|
||||
bool decodeJVC(decode_results *results);
|
||||
bool decodeSAMSUNG(decode_results *results);
|
||||
bool decodeWhynter(decode_results *results);
|
||||
bool decodeHash(decode_results *results);
|
||||
// COOLIX decode is not implemented yet
|
||||
// bool decodeCOOLIX(decode_results *results);
|
||||
bool decodeDaikin(decode_results *results);
|
||||
bool decodeDenon(decode_results *results);
|
||||
int compare(unsigned int oldval, unsigned int newval);
|
||||
uint32_t ticksLow(uint32_t usecs, uint8_t tolerance=TOLERANCE);
|
||||
uint32_t ticksHigh(uint32_t usecs, uint8_t tolerance=TOLERANCE);
|
||||
bool match(uint32_t measured_ticks, uint32_t desired_us,
|
||||
uint8_t tolerance=TOLERANCE);
|
||||
bool matchMark(uint32_t measured_ticks, uint32_t desired_us,
|
||||
uint8_t tolerance=TOLERANCE, int excess=MARK_EXCESS);
|
||||
bool matchSpace(uint32_t measured_ticks, uint32_t desired_us,
|
||||
uint8_t tolerance=TOLERANCE, int excess=MARK_EXCESS);
|
||||
};
|
||||
|
||||
// Only used for testing; can remove virtual for shorter code
|
||||
#ifdef TEST
|
||||
#define VIRTUAL virtual
|
||||
#else
|
||||
#define VIRTUAL
|
||||
#endif
|
||||
|
||||
class IRsend
|
||||
{
|
||||
public:
|
||||
IRsend(int IRsendPin);
|
||||
void begin();
|
||||
void send(int type, unsigned long data, int nbits) {
|
||||
switch (type) {
|
||||
SEND_PROTOCOL_NEC
|
||||
SEND_PROTOCOL_PIONEER
|
||||
SEND_PROTOCOL_SONY
|
||||
SEND_PROTOCOL_RC5
|
||||
SEND_PROTOCOL_RC6
|
||||
SEND_PROTOCOL_DISH
|
||||
SEND_PROTOCOL_JVC
|
||||
SEND_PROTOCOL_SAMSUNG
|
||||
SEND_PROTOCOL_LG
|
||||
SEND_PROTOCOL_WHYNTER
|
||||
SEND_PROTOCOL_COOLIX
|
||||
SEND_PROTOCOL_DENON
|
||||
SEND_PROTOCOL_SHERWOOD
|
||||
SEND_PROTOCOL_RCMM
|
||||
}
|
||||
};
|
||||
void sendCOOLIX(unsigned long data, int nbits);
|
||||
void sendWhynter(unsigned long data, int nbits);
|
||||
void sendNEC(unsigned long data, int nbits=32, unsigned int repeat=0);
|
||||
void sendPioneer(unsigned long data, int nbits=32, unsigned int repeat=0, unsigned long secondData=0ul);
|
||||
void sendLG(unsigned long data, int nbits=28, unsigned int repeat=0);
|
||||
// sendSony() should typically be called with repeat=2 as Sony devices
|
||||
// expect the code to be sent at least 3 times. (code + 2 repeats = 3 codes)
|
||||
// As the legacy use of this procedure was only to send a single code
|
||||
// it defaults to repeat=0 for backward compatiblity.
|
||||
void sendSony(unsigned long data, int nbits, unsigned int repeat=0);
|
||||
// Neither Sanyo nor Mitsubishi send is implemented yet
|
||||
// void sendSanyo(unsigned long data, int nbits);
|
||||
// void sendMitsubishi(unsigned long data, int nbits);
|
||||
void sendRaw(unsigned int buf[], int len, int hz);
|
||||
void sendGC(unsigned int buf[], int len);
|
||||
void sendRC5(unsigned long data, int nbits);
|
||||
void sendRC6(unsigned long data, int nbits);
|
||||
void sendRCMM(uint32_t data, uint8_t nbits=24);
|
||||
// sendDISH() should typically be called with repeat=3 as DISH devices
|
||||
// expect the code to be sent at least 4 times. (code + 3 repeats = 4 codes)
|
||||
// As the legacy use of this procedure was only to send a single code
|
||||
// it defaults to repeat=0 for backward compatiblity.
|
||||
void sendDISH(unsigned long data, int nbits, unsigned int repeat=0);
|
||||
void sendSharp(unsigned int address, unsigned int command);
|
||||
void sendSharpRaw(unsigned long data, int nbits);
|
||||
void sendPanasonic(unsigned int address, unsigned long data);
|
||||
void sendJVC(unsigned long data, int nbits, unsigned int repeat=0);
|
||||
void sendSAMSUNG(unsigned long data, int nbits=32);
|
||||
void sendDaikin(unsigned char data[]);
|
||||
void sendDenon(unsigned long data, int nbits=14);
|
||||
void sendKelvinator(unsigned char data[]);
|
||||
void sendSherwood(unsigned long data, int nbits=32, unsigned int repeat=1);
|
||||
void sendMitsubishiAC(unsigned char data[]);
|
||||
void enableIROut(int khz);
|
||||
VIRTUAL void mark(unsigned int usec);
|
||||
VIRTUAL void space(unsigned long usec);
|
||||
private:
|
||||
int halfPeriodicTime;
|
||||
int IRpin;
|
||||
void sendMitsubishiACChunk(unsigned char data);
|
||||
void sendData(uint16_t onemark, uint32_t onespace,
|
||||
uint16_t zeromark, uint32_t zerospace,
|
||||
uint32_t data, uint8_t nbits, bool MSBfirst=true);
|
||||
void ledOff();
|
||||
} ;
|
||||
|
||||
class IRtimer {
|
||||
public:
|
||||
IRtimer();
|
||||
void reset();
|
||||
uint32_t elapsed();
|
||||
private:
|
||||
uint32_t start;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,267 +0,0 @@
|
||||
/***************************************************
|
||||
* IRremote for ESP8266
|
||||
*
|
||||
* Based on the IRremote library for Arduino by Ken Shirriff
|
||||
* Version 0.11 August, 2009
|
||||
* Copyright 2009 Ken Shirriff
|
||||
* For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.html
|
||||
*
|
||||
* Modified by Paul Stoffregen <paul@pjrc.com> to support other boards and timers
|
||||
*
|
||||
* Interrupt code based on NECIRrcv by Joe Knapp
|
||||
* http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1210243556
|
||||
* Also influenced by http://zovirl.com/2008/11/12/building-a-universal-remote-with-an-arduino/
|
||||
*
|
||||
* JVC and Panasonic protocol added by Kristian Lauszus (Thanks to zenwheel and other people at the original blog post)
|
||||
* Whynter A/C ARC-110WD added by Francesco Meschia
|
||||
* Coolix A/C / heatpump added by bakrus
|
||||
* Denon: sendDenon, decodeDenon added by Massimiliano Pinto
|
||||
(from https://github.com/z3t0/Arduino-IRremote/blob/master/ir_Denon.cpp)
|
||||
* Kelvinator A/C added by crankyoldgit
|
||||
* Mitsubishi A/C added by crankyoldgit
|
||||
* (based on https://github.com/r45635/HVAC-IR-Control)
|
||||
*
|
||||
* 09/23/2015 : Samsung pulse parameters updated by Sebastien Warin to be compatible with EUxxD6200
|
||||
*
|
||||
* GPL license, all text above must be included in any redistribution
|
||||
****************************************************/
|
||||
|
||||
#ifndef IRremoteint_h
|
||||
#define IRremoteint_h
|
||||
|
||||
#if defined(ARDUINO) && ARDUINO >= 100
|
||||
#include <Arduino.h>
|
||||
#else
|
||||
#include <WProgram.h>
|
||||
#endif
|
||||
|
||||
// Pulse parms are *50-100 for the Mark and *50+100 for the space
|
||||
// First MARK is the one after the long gap
|
||||
// pulse parameters in usec
|
||||
#define COOLIX_BIT_MARK 560 // Approximately 21 cycles at 38kHz
|
||||
#define COOLIX_ONE_SPACE COOLIX_BIT_MARK * 3
|
||||
#define COOLIX_ZERO_SPACE COOLIX_BIT_MARK * 1
|
||||
#define COOLIX_HDR_MARK COOLIX_BIT_MARK * 8
|
||||
#define COOLIX_HDR_SPACE COOLIX_BIT_MARK * 8
|
||||
|
||||
#define WHYNTER_HDR_MARK 2850
|
||||
#define WHYNTER_HDR_SPACE 2850
|
||||
#define WHYNTER_BIT_MARK 750
|
||||
#define WHYNTER_ONE_MARK 750
|
||||
#define WHYNTER_ONE_SPACE 2150
|
||||
#define WHYNTER_ZERO_MARK 750
|
||||
#define WHYNTER_ZERO_SPACE 750
|
||||
|
||||
#define NEC_HDR_MARK 9000
|
||||
#define NEC_HDR_SPACE 4500
|
||||
#define NEC_BIT_MARK 560
|
||||
#define NEC_ONE_SPACE 1690
|
||||
#define NEC_ZERO_SPACE 560
|
||||
#define NEC_RPT_SPACE 2250
|
||||
#define NEC_MIN_COMMAND_LENGTH 108000UL
|
||||
|
||||
#define PIONEER_HDR_MARK 8000
|
||||
#define PIONEER_HDR_SPACE 4000
|
||||
#define PIONEER_BIT_MARK 500
|
||||
#define PIONEER_ONE_SPACE 1500
|
||||
#define PIONEER_ZERO_SPACE 500
|
||||
#define PIONEER_RPT_SPACE 2250
|
||||
#define PIONEER_MIN_COMMAND_LENGTH 90000UL
|
||||
|
||||
// Timings based on http://www.sbprojects.com/knowledge/ir/sirc.php
|
||||
#define SONY_HDR_MARK 2400
|
||||
#define SONY_HDR_SPACE 600
|
||||
#define SONY_ONE_MARK 1250 // Experiments suggest +50 to spec is better.
|
||||
#define SONY_ZERO_MARK 650 // Experiments suggest +50 to spec is better.
|
||||
#define SONY_RPT_LENGTH 45000
|
||||
#define SONY_DOUBLE_SPACE_USECS 500 // usually see 713 - not using ticks as get number wrapround
|
||||
|
||||
// SA 8650B
|
||||
#define SANYO_HDR_MARK 3500 // seen range 3500
|
||||
#define SANYO_HDR_SPACE 950 // seen 950
|
||||
#define SANYO_ONE_MARK 2400 // seen 2400
|
||||
#define SANYO_ZERO_MARK 700 // seen 700
|
||||
#define SANYO_DOUBLE_SPACE_USECS 800 // usually see 713 - not using ticks as get number wrapround
|
||||
#define SANYO_RPT_LENGTH 45000
|
||||
|
||||
// Mitsubishi RM 75501
|
||||
// 14200 7 41 7 42 7 42 7 17 7 17 7 18 7 41 7 18 7 17 7 17 7 18 7 41 8 17 7 17 7 18 7 17 7
|
||||
|
||||
// #define MITSUBISHI_HDR_MARK 250 // seen range 3500
|
||||
#define MITSUBISHI_HDR_SPACE 350 // 7*50+100
|
||||
#define MITSUBISHI_ONE_MARK 1950 // 41*50-100
|
||||
#define MITSUBISHI_ZERO_MARK 750 // 17*50-100
|
||||
// #define MITSUBISHI_DOUBLE_SPACE_USECS 800 // usually ssee 713 - not using ticks as get number wrapround
|
||||
// #define MITSUBISHI_RPT_LENGTH 45000
|
||||
|
||||
// Mitsubishi A/C
|
||||
// Values were initially obtained from:
|
||||
// https://github.com/r45635/HVAC-IR-Control/blob/master/HVAC_ESP8266/HVAC_ESP8266.ino#L84
|
||||
#define MITSUBISHI_AC_HDR_MARK 3400
|
||||
#define MITSUBISHI_AC_HDR_SPACE 1750
|
||||
#define MITSUBISHI_AC_BIT_MARK 450
|
||||
#define MITSUBISHI_AC_ONE_SPACE 1300
|
||||
#define MITSUBISHI_AC_ZERO_SPACE 420
|
||||
#define MITSUBISHI_AC_RPT_MARK 440
|
||||
#define MITSUBISHI_AC_RPT_SPACE 17100L
|
||||
|
||||
|
||||
#define RC5_T1 889
|
||||
#define RC5_RPT_LENGTH 46000
|
||||
|
||||
#define RC6_HDR_MARK 2666
|
||||
#define RC6_HDR_SPACE 889
|
||||
#define RC6_T1 444
|
||||
#define RC6_RPT_LENGTH 46000
|
||||
|
||||
// http://www.sbprojects.com/knowledge/ir/rcmm.php
|
||||
#define RCMM_HDR_MARK 416
|
||||
#define RCMM_HDR_SPACE 277
|
||||
#define RCMM_BIT_MARK 166
|
||||
#define RCMM_BIT_SPACE_0 277
|
||||
#define RCMM_BIT_SPACE_1 444
|
||||
#define RCMM_BIT_SPACE_2 611
|
||||
#define RCMM_BIT_SPACE_3 777
|
||||
#define RCMM_RPT_LENGTH 27778
|
||||
#define RCMM_MIN_GAP 3360
|
||||
// Use a tolerance of +/-10% when matching some data spaces.
|
||||
#define RCMM_TOLERANCE 10
|
||||
#define RCMM_EXCESS 50
|
||||
|
||||
#define SHARP_BIT_MARK 245
|
||||
#define SHARP_ONE_SPACE 1805
|
||||
#define SHARP_ZERO_SPACE 795
|
||||
#define SHARP_GAP 600000
|
||||
#define SHARP_TOGGLE_MASK 0x3FF
|
||||
#define SHARP_RPT_SPACE 3000
|
||||
|
||||
#define DISH_HDR_MARK 400
|
||||
#define DISH_HDR_SPACE 6100
|
||||
#define DISH_BIT_MARK 400
|
||||
#define DISH_ONE_SPACE 1700
|
||||
#define DISH_ZERO_SPACE 2800
|
||||
#define DISH_RPT_SPACE 6200
|
||||
|
||||
// Ref: http://www.remotecentral.com/cgi-bin/mboard/rc-pronto/thread.cgi?26152
|
||||
#define PANASONIC_HDR_MARK 3456
|
||||
#define PANASONIC_HDR_SPACE 1728
|
||||
#define PANASONIC_BIT_MARK 432
|
||||
#define PANASONIC_ONE_SPACE 1296
|
||||
#define PANASONIC_ZERO_SPACE 432
|
||||
|
||||
#define JVC_HDR_MARK 8000
|
||||
#define JVC_HDR_SPACE 4000
|
||||
#define JVC_BIT_MARK 600
|
||||
#define JVC_ONE_SPACE 1600
|
||||
#define JVC_ZERO_SPACE 550
|
||||
#define JVC_RPT_LENGTH 60000
|
||||
|
||||
#define LG_HDR_MARK 8000
|
||||
#define LG_HDR_SPACE 4000
|
||||
#define LG_BIT_MARK 600
|
||||
#define LG_ONE_SPACE 1600
|
||||
#define LG_ZERO_SPACE 550
|
||||
#define LG_RPT_LENGTH 60000
|
||||
|
||||
/*
|
||||
#define SAMSUNG_HDR_MARK 5000
|
||||
#define SAMSUNG_HDR_SPACE 5000
|
||||
#define SAMSUNG_BIT_MARK 560
|
||||
#define SAMSUNG_ONE_SPACE 1600
|
||||
#define SAMSUNG_ZERO_SPACE 560
|
||||
#define SAMSUNG_RPT_SPACE 2250
|
||||
*/
|
||||
|
||||
// Update by Sebastien Warin for my EU46D6200
|
||||
#define SAMSUNG_HDR_MARK 4500
|
||||
#define SAMSUNG_HDR_SPACE 4500
|
||||
#define SAMSUNG_BIT_MARK 590
|
||||
#define SAMSUNG_ONE_SPACE 1690
|
||||
#define SAMSUNG_ZERO_SPACE 590
|
||||
#define SAMSUNG_RPT_SPACE 2250
|
||||
|
||||
#define SHARP_BITS 15
|
||||
#define DISH_BITS 16
|
||||
|
||||
// Daikin, from https://github.com/mharizanov/Daikin-AC-remote-control-over-the-Internet/tree/master/IRremote
|
||||
#define DAIKIN_HDR_MARK 3650 //DAIKIN_ZERO_MARK*8
|
||||
#define DAIKIN_HDR_SPACE 1623 //DAIKIN_ZERO_MARK*4
|
||||
#define DAIKIN_ONE_SPACE 1280
|
||||
#define DAIKIN_ONE_MARK 428
|
||||
#define DAIKIN_ZERO_MARK 428
|
||||
#define DAIKIN_ZERO_SPACE 428
|
||||
|
||||
//Denon, from https://github.com/z3t0/Arduino-IRremote/blob/master/ir_Denon.cpp
|
||||
#define DENON_BITS 14 // The number of bits in the command
|
||||
#define DENON_HDR_MARK 300 // The length of the Header:Mark
|
||||
#define DENON_HDR_SPACE 750 // The lenght of the Header:Space
|
||||
#define DENON_BIT_MARK 300 // The length of a Bit:Mark
|
||||
#define DENON_ONE_SPACE 1800 // The length of a Bit:Space for 1's
|
||||
#define DENON_ZERO_SPACE 750 // The length of a Bit:Space for 0's
|
||||
|
||||
#define KELVINATOR_HDR_MARK 8990U
|
||||
#define KELVINATOR_HDR_SPACE 4490U
|
||||
#define KELVINATOR_BIT_MARK 675U
|
||||
#define KELVINATOR_ONE_SPACE 1560U
|
||||
#define KELVINATOR_ZERO_SPACE 520U
|
||||
#define KELVINATOR_GAP_SPACE 19950U
|
||||
#define KELVINATOR_CMD_FOOTER 2U
|
||||
|
||||
// Some useful constants
|
||||
#define USECPERTICK 50 // microseconds per clock interrupt tick
|
||||
#define RAWBUF 100 // Length of raw duration buffer
|
||||
|
||||
// Marks tend to be 100us too long, and spaces 100us too short
|
||||
// when received due to sensor lag.
|
||||
#define MARK_EXCESS 100
|
||||
|
||||
#define _GAP 5000 // Minimum map between transmissions
|
||||
#define GAP_TICKS (_GAP/USECPERTICK)
|
||||
|
||||
#define TOLERANCE 25 // default percent tolerance in measurements
|
||||
|
||||
// receiver states
|
||||
#define STATE_IDLE 2
|
||||
#define STATE_MARK 3
|
||||
#define STATE_SPACE 4
|
||||
#define STATE_STOP 5
|
||||
|
||||
#define RAWBUF 100 // Length of raw duration buffer
|
||||
|
||||
// information for the interrupt handler
|
||||
typedef struct {
|
||||
uint8_t recvpin; // pin for IR data from detector
|
||||
uint8_t rcvstate; // state machine
|
||||
unsigned int timer; // state timer, counts 50uS ticks.
|
||||
unsigned int rawbuf[RAWBUF]; // raw data
|
||||
// uint16_t is used for rawlen as it saves 3 bytes of iram in the interrupt
|
||||
// handler. Don't ask why, I don't know. It just does.
|
||||
uint16_t rawlen; // counter of entries in rawbuf.
|
||||
uint8_t overflow; // Buffer overflow indicator.
|
||||
}
|
||||
irparams_t;
|
||||
|
||||
// Defined in IRremote.cpp
|
||||
extern volatile irparams_t irparams;
|
||||
|
||||
// IR detector output is active low
|
||||
#define MARK 0
|
||||
#define SPACE 1
|
||||
|
||||
#define TOPBIT 0x80000000
|
||||
|
||||
#define NEC_BITS 32
|
||||
#define SONY_BITS 12
|
||||
#define SANYO_BITS 12
|
||||
#define MITSUBISHI_BITS 16
|
||||
#define MIN_RC5_SAMPLES 11
|
||||
#define MIN_RC6_SAMPLES 1
|
||||
#define PANASONIC_BITS 48
|
||||
#define JVC_BITS 16
|
||||
#define LG_BITS 28
|
||||
#define SAMSUNG_BITS 32
|
||||
#define WHYNTER_BITS 32
|
||||
#define COOLIX_NBYTES 3
|
||||
#define DAIKIN_BITS 99
|
||||
|
||||
#endif
|
||||
@@ -7,11 +7,26 @@
|
||||
|
||||
This library enables you to **send _and_ receive** infra-red signals on an [ESP8266 using the Arduino framework](https://github.com/esp8266/Arduino) using common 940nm IR LEDs and common IR receiver modules. e.g. TSOP{17,22,24,36,38,44,48}* etc.
|
||||
|
||||
## v2.4.3 Now Available
|
||||
Version 2.4.3 of the library is now [available](https://github.com/markszabo/IRremoteESP8266/releases/latest). You can view the [Release Notes](ReleaseNotes.md) for all the significant changes.
|
||||
## v2.5.2 Now Available
|
||||
Version 2.5.2 of the library is now [available](https://github.com/markszabo/IRremoteESP8266/releases/latest). You can view the [Release Notes](ReleaseNotes.md) for all the significant changes.
|
||||
|
||||
#### Upgrading from pre-v2.0
|
||||
Usage of the library slight changed at v2.0. You will need to change your usage to work with v2.0 and beyond. You can read more about the changes required on our [Upgrade to v2.0](https://github.com/markszabo/IRremoteESP8266/wiki/Upgrading-to-v2.0) page.
|
||||
Usage of the library has been slightly changed in v2.0. You will need to change your usage to work with v2.0 and beyond. You can read more about the changes required on our [Upgrade to v2.0](https://github.com/markszabo/IRremoteESP8266/wiki/Upgrading-to-v2.0) page.
|
||||
|
||||
#### Upgrading from pre-v2.5
|
||||
The library has changed from using constants declared as `#define` to
|
||||
[const](https://google.github.io/styleguide/cppguide.html#Constant_Names) with
|
||||
the appropriate naming per the
|
||||
[C++ style guide](https://google.github.io/styleguide/cppguide.html).
|
||||
This may potentially cause old programs to not compile.
|
||||
The most likely externally used `#define`s have been _aliased_ for limited
|
||||
backward compatibility for projects using the old style. Going forward, only the
|
||||
new `kConstantName` style will be supported for new protocol additions.
|
||||
|
||||
In the unlikely case it does break your code, then you may have been referencing
|
||||
something you likely should not have. You should be able to quickly determine
|
||||
the new name from the old. e.g. `CONSTANT_NAME` to `kConstantName`.
|
||||
Use common sense or examining the library's code if this does affect code.
|
||||
|
||||
## Troubleshooting
|
||||
Before reporting an issue or asking for help, please try to follow our [Troubleshooting Guide](https://github.com/markszabo/IRremoteESP8266/wiki/Troubleshooting-Guide) first.
|
||||
|
||||
@@ -1,5 +1,69 @@
|
||||
# Release Notes
|
||||
|
||||
## _v2.5.2 (20181021)_
|
||||
|
||||
**[Bug Fixes]**
|
||||
- Add missing send() method to IRPanasonicAC class. (#545)
|
||||
- Add missing sendWhirlpoolAC() to IRMQTTServer.ino (#558)
|
||||
|
||||
**[Features]**
|
||||
- Add IR receiving support to IRMQTTServer. (#543)
|
||||
- Pioneer support (#547)
|
||||
- Add support for a second LG protocol variant. (#552)
|
||||
- Support for short Panasonic A/C messages. (#553)
|
||||
- Add support for Panasonic CKP series A/Cs. (#554)
|
||||
- Experimental timer/clock support for Panasonic A/Cs. (#546)
|
||||
- Add Made With Magic (MWM) support (#557)
|
||||
|
||||
**[Misc]**
|
||||
- Grammar and typo fixes (#541, #549)
|
||||
- Increase Panasonic A/C message tolerances. (#542)
|
||||
- Added command mode2_decode in tools/ (#557)
|
||||
- General code style cleanup (#560)
|
||||
|
||||
|
||||
## _v2.5.1 (20181002)_
|
||||
|
||||
**[Bug Fixes]**
|
||||
- Correct the byte used for Samsung AC Swing. (#529)
|
||||
- Fix not sending Samsung A/C messages in IRMQTTServer. (#529)
|
||||
|
||||
**[Features]**
|
||||
- Experimental support for Electra A/C messages. (#528)
|
||||
- Experimental support for Panasonic A/C messages. (#535)
|
||||
- Samsung A/C fixes & improvements (#529)
|
||||
- IRMQTTServer v0.6.0 (#530)
|
||||
|
||||
**[Misc]**
|
||||
- Change required WifiManager lib version to v0.14
|
||||
- Add alias for RAWTICK to kRawTick. (#535)
|
||||
- Update sendLutron() status. (#515)
|
||||
- Remove leftover debug message in IRrecvDumpV2 (#526)
|
||||
|
||||
|
||||
## _v2.5.0 (20180919)_
|
||||
|
||||
**[Bug Fixes]**
|
||||
- Fix HTML menu error for GICABLE in IRMQTTServer. (#516)
|
||||
- Fix Mitsubishi A/C mode setting. (#514)
|
||||
- Add missing ',' in auto analyse tool generated code. (#513)
|
||||
- Fix Fujitsu checksum validation. (#501)
|
||||
- Remove errant Repeat debug statement in IRMQTTServer. (#507)
|
||||
|
||||
**[Features]**
|
||||
- Mitsubishi A/C decode improvements. (#514)
|
||||
- Basic support for Whirlpool A/C messages. (#511)
|
||||
- Basic support for Samsung A/C messages. (#512)
|
||||
- Experimental support for detailed Samsung A/C messages. (#521)
|
||||
- Experimental support for detailed Coolix A/C messages. (#518)
|
||||
- Experimental support for Lutron protocol. (#516)
|
||||
- Calculate and use average values for timings in analysing tool. (#513)
|
||||
|
||||
**[Misc]**
|
||||
- Style change from using #define's for constants to `const kConstantName`.
|
||||
- Improve the JVC example code.
|
||||
|
||||
|
||||
## _v2.4.3 (20180727)_
|
||||
|
||||
**[Bug Fixes]**
|
||||
|
||||
@@ -24,12 +24,13 @@
|
||||
* have enough current to drive the IR LED effectively.
|
||||
* * Make sure you have the IR LED polarity correct.
|
||||
* See: https://learn.sparkfun.com/tutorials/polarity/diode-and-led-polarity
|
||||
* * Typical digital camera/phones can be used to see if the IR LED is flashed.
|
||||
* Replace the IR LED with a normal LED if you don't have a digital camera
|
||||
* when debugging.
|
||||
* * Typical digital camera/phones can be used to see if the IR LED is
|
||||
* flashed. Replace the IR LED with a normal LED if you don't have a digital
|
||||
* camera when debugging.
|
||||
* * Avoid using the following pins unless you really know what you are doing:
|
||||
* * Pin 0/D3: Can interfere with the boot/program mode & support circuits.
|
||||
* * Pin 1/TX/TXD0: Any serial transmissions from the ESP8266 will interfere.
|
||||
* * Pin 1/TX/TXD0: Any serial transmissions from the ESP8266 will
|
||||
* interfere.
|
||||
* * Pin 3/RX/RXD0: Any serial transmissions to the ESP8266 will interfere.
|
||||
* * ESP-01 modules are tricky. We suggest you use a module with more GPIOs
|
||||
* for your first time. e.g. ESP-12 etc.
|
||||
@@ -45,11 +46,11 @@
|
||||
// These codes can be found in GC's Control Tower database.
|
||||
|
||||
uint16_t Samsung_power_toggle[71] = {
|
||||
38000, 1, 1, 170, 170, 20, 63, 20, 63, 20, 63, 20, 20, 20, 20, 20, 20, 20,
|
||||
20, 20, 20, 20, 63, 20, 63, 20, 63, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
|
||||
20, 20, 20, 63, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 63, 20,
|
||||
20, 20, 63, 20, 63, 20, 63, 20, 63, 20, 63, 20, 63, 20, 1798};
|
||||
|
||||
38000, 1, 1, 170, 170, 20, 63, 20, 63, 20, 63, 20, 20, 20, 20,
|
||||
20, 20, 20, 20, 20, 20, 20, 63, 20, 63, 20, 63, 20, 20, 20,
|
||||
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 63, 20, 20, 20, 20,
|
||||
20, 20, 20, 20, 20, 20, 20, 20, 20, 63, 20, 20, 20, 63, 20,
|
||||
63, 20, 63, 20, 63, 20, 63, 20, 63, 20, 1798};
|
||||
|
||||
#define IR_LED 4 // ESP8266 GPIO pin to use. Recommended: 4 (D2).
|
||||
|
||||
@@ -64,7 +65,7 @@ void loop() {
|
||||
Serial.println("Toggling power");
|
||||
#if SEND_GLOBALCACHE
|
||||
irsend.sendGC(Samsung_power_toggle, 71);
|
||||
#else // SEND_GLOBALCACHE
|
||||
#else // SEND_GLOBALCACHE
|
||||
Serial.println("Can't send because SEND_GLOBALCACHE has been disabled.");
|
||||
#endif // SEND_GLOBALCACHE
|
||||
delay(10000);
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
* For more codes, visit: https://irdb.globalcache.com/
|
||||
*
|
||||
* How to use this program:
|
||||
* 1) Update "ssid" and "password" below for your WIFI network.
|
||||
* 1) Update "kSsid" and "kPassword" below for your WIFI network.
|
||||
* 2) Compile and upload the sketch to your ESP8266 module.
|
||||
* 3) (Optional) Use the serial connection to confirm it started and get the
|
||||
* IP address.
|
||||
@@ -46,8 +46,8 @@
|
||||
#include <WiFiClient.h>
|
||||
#include <WiFiServer.h>
|
||||
|
||||
const char* ssid = "..."; // Put your WIFI SSID here.
|
||||
const char* password = "..."; // Put your WIFI password here.
|
||||
const char* kSsid = "..."; // Put your WIFI SSID here.
|
||||
const char* kPassword = "..."; // Put your WIFI Password here.
|
||||
|
||||
WiFiServer server(4998); // Uses port 4998.
|
||||
WiFiClient client;
|
||||
@@ -103,7 +103,7 @@ void setup() {
|
||||
delay(100);
|
||||
Serial.println(" ");
|
||||
Serial.println("IR TCP Server");
|
||||
WiFi.begin(ssid, password);
|
||||
WiFi.begin(kSsid, kPassword);
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(900);
|
||||
Serial.print(".");
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
/*
|
||||
* Send arbitrary IR codes via a web server or MQTT.
|
||||
* Send & receive arbitrary IR codes via a web server or MQTT.
|
||||
* Copyright David Conran 2016, 2017, 2018
|
||||
*
|
||||
* NOTE: An IR LED circuit *MUST* be connected to ESP8266 GPIO4 (D2). See IR_LED
|
||||
* NOTE: An IR LED circuit *MUST* be connected to ESP8266 GPIO4 (D2) if
|
||||
* you want to send IR messages. See IR_LED below.
|
||||
* A compatible IR RX modules *MUST* be connected to ESP8266 GPIO14 (D5)
|
||||
* if you want to capture & decode IR nessages. See IR_RX below.
|
||||
*
|
||||
* WARN: This is very advanced & complicated example code. Not for beginners.
|
||||
* You are strongly suggested to try & look at other example code first.
|
||||
@@ -10,10 +13,14 @@
|
||||
* # Instructions
|
||||
*
|
||||
* ## Before First Boot (i.e. Compile time)
|
||||
* - Set the MQTT_SERVER define below to the address of your MQTT server.
|
||||
* - Either:
|
||||
* o Set the MQTT_SERVER define below to the address of your MQTT server.
|
||||
* or
|
||||
* o Disable MQTT by commenting out the line "#define MQTT_ENABLE" down below.
|
||||
*
|
||||
* - Arduino IDE:
|
||||
* o Install the following libraries via Library Manager
|
||||
* - WiFiManager (https://github.com/tzapu/WiFiManager)
|
||||
* - WiFiManager (https://github.com/tzapu/WiFiManager) (Version >= 0.14)
|
||||
* - PubSubClient (https://pubsubclient.knolleary.net/)
|
||||
* o You MUST change <PubSubClient.h> to have the following (or larger) value:
|
||||
* #define MQTT_MAX_PACKET_SIZE 512
|
||||
@@ -90,6 +97,19 @@
|
||||
* # Listen to MQTT acknowledgements.
|
||||
* $ mosquitto_sub -h 10.20.0.253 -t ir_server/sent
|
||||
*
|
||||
* Incoming IR messages (from an IR remote control) will be transmitted to
|
||||
* the MQTT topic 'ir_server/received'. The MQTT message will be formatted
|
||||
* similar to what is required to for the 'sent' topic.
|
||||
* e.g. "3,C1A2F00F,32" (Protocol,Value,Bits) for simple codes
|
||||
* or "18,110B805000000060110B807000001070" (Protocol,Value) for complex codes
|
||||
* Note: If the protocol is listed as -1, then that is an UNKNOWN IR protocol.
|
||||
* You can't use that to recreate/resend an IR message. It's only for
|
||||
* matching purposes and shouldn't be trusted.
|
||||
*
|
||||
* Unix command line usage example:
|
||||
* # Listen via MQTT for IR messages captured by this server.
|
||||
* $ mosquitto_sub -h 10.20.0.253 -t ir_server/received
|
||||
*
|
||||
* If DEBUG is turned on, there is additional information printed on the Serial
|
||||
* Port.
|
||||
*
|
||||
@@ -132,7 +152,11 @@
|
||||
// GPIO the IR LED is connected to/controlled by. GPIO 4 = D2.
|
||||
#define IR_LED 4
|
||||
// define IR_LED 3 // For an ESP-01 we suggest you use RX/GPIO3/Pin 7.
|
||||
#define HTTP_PORT 80 // The port the HTTP server is listening on.
|
||||
//
|
||||
// GPIO the IR RX module is connected to/controlled by. GPIO 14 = D5.
|
||||
// Comment this out to disable receiving/decoding IR messages entirely.
|
||||
#define IR_RX 14
|
||||
const uint16_t kHttpPort = 80; // The TCP port the HTTP server is listening on.
|
||||
// Name of the device you want in mDNS.
|
||||
// NOTE: Changing this will change the MQTT path too unless you override it
|
||||
// via MQTTprefix below.
|
||||
@@ -150,16 +174,17 @@ const IPAddress kSubnetMask = IPAddress(255, 255, 255, 0);
|
||||
#ifdef MQTT_ENABLE
|
||||
// Address of your MQTT server.
|
||||
#define MQTT_SERVER "10.20.0.253" // <=- CHANGE ME
|
||||
#define MQTT_PORT 1883 // Default port used by MQTT servers.
|
||||
const uint16_t kMqttPort = 1883; // Default port used by MQTT servers.
|
||||
// Set if your MQTT server requires a Username & Password to connect.
|
||||
const char* mqtt_user = "";
|
||||
const char* mqtt_password = "";
|
||||
#define MQTT_RECONNECT_TIME 5000 // Delay(ms) between reconnect tries.
|
||||
const uint32_t kMqttReconnectTime = 5000; // Delay(ms) between reconnect tries.
|
||||
|
||||
#define MQTTprefix HOSTNAME // Change this if you want the MQTT topic to be
|
||||
// independent of the hostname.
|
||||
#define MQTTack MQTTprefix "/sent" // Topic we send back acknowledgements on
|
||||
#define MQTTcommand MQTTprefix "/send" // Topic we get new commands from.
|
||||
#define MQTTrecv MQTTprefix "/received" // Topic we send received IRs to.
|
||||
#endif // MQTT_ENABLE
|
||||
|
||||
// HTML arguments we will parse for IR code information.
|
||||
@@ -167,10 +192,23 @@ const char* mqtt_password = "";
|
||||
#define argData "code"
|
||||
#define argBits "bits"
|
||||
#define argRepeat "repeats"
|
||||
// Let's use a larger than normal buffer so we can handle AirCon remote codes.
|
||||
const uint16_t kCaptureBufferSize = 1024;
|
||||
#if DECODE_AC
|
||||
// Some A/C units have gaps in their protocols of ~40ms. e.g. Kelvinator
|
||||
// A value this large may swallow repeats of some protocols
|
||||
const uint8_t kCaptureTimeout = 50;
|
||||
#else // DECODE_AC
|
||||
// Suits most messages, while not swallowing many repeats.
|
||||
const uint8_t kCaptureTimeout = 15;
|
||||
#endif // DECODE_AC
|
||||
// Ignore unknown messages with <10 pulses
|
||||
const uint16_t kMinUnknownSize = 20;
|
||||
|
||||
#define _MY_VERSION_ "v0.5.1"
|
||||
#define _MY_VERSION_ "v0.7.0"
|
||||
|
||||
#if IR_LED != 1 // Disable debug output if the LED is on the TX (D1) pin.
|
||||
// Disable debug output if any of the IR pins are on the TX (D1) pin.
|
||||
#if (IR_LED != 1 && IR_RX != 1)
|
||||
#undef DEBUG
|
||||
#define DEBUG true // Change to 'false' to disable all serial output.
|
||||
#else
|
||||
@@ -181,8 +219,12 @@ const char* mqtt_password = "";
|
||||
#define BAUD_RATE 115200 // Serial port Baud rate.
|
||||
|
||||
// Globals
|
||||
ESP8266WebServer server(HTTP_PORT);
|
||||
ESP8266WebServer server(kHttpPort);
|
||||
IRsend irsend = IRsend(IR_LED);
|
||||
#ifdef IR_RX
|
||||
IRrecv irrecv(IR_RX, kCaptureBufferSize, kCaptureTimeout, true);
|
||||
decode_results capture; // Somewhere to store inbound IR messages.
|
||||
#endif // IR_RX
|
||||
MDNSResponder mdns;
|
||||
WiFiClient espClient;
|
||||
WiFiManager wifiManager;
|
||||
@@ -192,16 +234,27 @@ uint32_t lastReconnectAttempt = 0; // MQTT last attempt reconnection number
|
||||
bool boot = true;
|
||||
bool ir_lock = false; // Primitive locking for gating the IR LED.
|
||||
uint32_t sendReqCounter = 0;
|
||||
bool lastSendSucceeded = false; // Store the success status of the last send.
|
||||
uint32_t lastSendTime = 0;
|
||||
int8_t offset; // The calculated period offset for this chip and library.
|
||||
|
||||
#ifdef MQTT_ENABLE
|
||||
String lastMqttCmd = "None";
|
||||
uint32_t lastMqttCmdTime = 0;
|
||||
uint32_t lastConnectedTime = 0;
|
||||
uint32_t lastDisconnectedTime = 0;
|
||||
uint32_t mqttDisconnectCounter = 0;
|
||||
bool wasConnected = true;
|
||||
#ifdef IR_RX
|
||||
String lastIrReceived = "None";
|
||||
uint32_t lastIrReceivedTime = 0;
|
||||
uint32_t irRecvCounter = 0;
|
||||
#endif // IR_RX
|
||||
|
||||
|
||||
// MQTT client parameters
|
||||
void callback(char* topic, byte* payload, unsigned int length);
|
||||
PubSubClient mqtt_client(MQTT_SERVER, MQTT_PORT, callback, espClient);
|
||||
PubSubClient mqtt_client(MQTT_SERVER, kMqttPort, callback, espClient);
|
||||
// Create a unique MQTT client id.
|
||||
String mqtt_clientid = MQTTprefix + String(ESP.getChipId(), HEX);
|
||||
#endif // MQTT_ENABLE
|
||||
@@ -237,13 +290,13 @@ String timeSince(uint32_t const start) {
|
||||
result += String(days) + " day";
|
||||
if (days > 1) result += "s";
|
||||
if (hours)
|
||||
result += " " + String(hours) + " hour";
|
||||
result += ' ' + String(hours) + " hour";
|
||||
if (hours > 1) result += "s";
|
||||
if (minutes)
|
||||
result += " " + String(minutes) + " minute";
|
||||
result += ' ' + String(minutes) + " minute";
|
||||
if (minutes > 1) result += "s";
|
||||
if (seconds)
|
||||
result += " " + String(seconds) + " second";
|
||||
result += ' ' + String(seconds) + " second";
|
||||
if (seconds > 1) result += "s";
|
||||
result.trim();
|
||||
return result + " ago";
|
||||
@@ -272,15 +325,31 @@ void handleRoot() {
|
||||
"Period Offset: " + String(offset) + "us<br>"
|
||||
"IR Lib Version: " _IRREMOTEESP8266_VERSION_ "<br>"
|
||||
"ESP8266 Core Version: " + ESP.getCoreVersion() + "<br>"
|
||||
"Total send requests: " + String(sendReqCounter) + "</p>"
|
||||
"IR Send GPIO: " + String(IR_LED) + "<br>"
|
||||
"Total send requests: " + String(sendReqCounter) + "<br>"
|
||||
"Last message sent: " + String(lastSendSucceeded ? "Ok" : "FAILED") +
|
||||
" <i>(" + timeSince(lastSendTime) + ")</i><br>"
|
||||
#ifdef IR_RX
|
||||
"IR Recv GPIO: " + String(IR_RX) + "<br>"
|
||||
"Total IR Received: " + String(irRecvCounter) + "<br>"
|
||||
"Last IR Received: " + lastIrReceived +
|
||||
" <i>(" + timeSince(lastIrReceivedTime) + ")</i><br>"
|
||||
#endif // IR_RX
|
||||
"</p>"
|
||||
#ifdef MQTT_ENABLE
|
||||
"<h4>MQTT Information</h4>"
|
||||
"<p>Server: " MQTT_SERVER ":" + String(MQTT_PORT) + " <i>(" +
|
||||
(mqtt_client.connected() ? "Connected" : "Disconnected") + ")</i><br>"
|
||||
"<p>Server: " MQTT_SERVER ":" + String(kMqttPort) + " <i>(" +
|
||||
(mqtt_client.connected() ? "Connected " + timeSince(lastDisconnectedTime)
|
||||
: "Disconnected " + timeSince(lastConnectedTime)) +
|
||||
")</i><br>"
|
||||
"Disconnections: " + String(mqttDisconnectCounter - 1) + "<br>"
|
||||
"Client id: " + mqtt_clientid + "<br>"
|
||||
"Command topic: " MQTTcommand "<br>"
|
||||
"Acknowledgements topic: " MQTTack "<br>"
|
||||
"Last command seen: " +
|
||||
#ifdef IR_RX
|
||||
"IR Received topic: " MQTTrecv "<br>"
|
||||
#endif // IR_RX
|
||||
"Last MQTT command seen: " +
|
||||
// lastMqttCmd is unescaped untrusted input.
|
||||
// Avoid any possible HTML/XSS when displaying it.
|
||||
(hasUnsafeHTMLChars(lastMqttCmd) ?
|
||||
@@ -320,10 +389,12 @@ void handleRoot() {
|
||||
"<option value='15'>Coolix</option>"
|
||||
"<option value='17'>Denon</option>"
|
||||
"<option value='13'>Dish</option>"
|
||||
"<option value='41'>GICable</option>"
|
||||
"<option value='43'>GICable</option>"
|
||||
"<option value='6'>JVC</option>"
|
||||
"<option value='10'>LG</option>"
|
||||
"<option value='36'>Lasertag</option>"
|
||||
"<option value='10'>LG</option>"
|
||||
"<option value='51'>LG2</option>"
|
||||
"<option value='47'>Lutron</option>"
|
||||
"<option value='35'>MagiQuest</option>"
|
||||
"<option value='34'>Midea</option>"
|
||||
"<option value='12'>Mitsubishi</option>"
|
||||
@@ -331,6 +402,7 @@ void handleRoot() {
|
||||
"<option selected='selected' value='3'>NEC</option>" // Default
|
||||
"<option value='29'>Nikai</option>"
|
||||
"<option value='5'>Panasonic</option>"
|
||||
"<option value='50'>Pioneer</option>"
|
||||
"<option value='1'>RC-5</option>"
|
||||
"<option value='23'>RC-5X</option>"
|
||||
"<option value='2'>RC-6</option>"
|
||||
@@ -359,6 +431,7 @@ void handleRoot() {
|
||||
"<option value='24'>24</option>"
|
||||
"<option value='28'>28</option>"
|
||||
"<option value='32'>32</option>"
|
||||
"<option value='35'>35</option>"
|
||||
"<option value='36'>36</option>"
|
||||
"<option value='48'>48</option>"
|
||||
"<option value='56'>56</option>"
|
||||
@@ -412,6 +485,7 @@ void handleRoot() {
|
||||
"<select name='type'>"
|
||||
"<option value='27'>Argo</option>"
|
||||
"<option value='16'>Daikin</option>"
|
||||
"<option value='48'>Electra</option>"
|
||||
"<option value='33'>Fujitsu</option>"
|
||||
"<option value='24'>Gree</option>"
|
||||
"<option value='38'>Haier (9 bytes)</option>"
|
||||
@@ -421,12 +495,15 @@ void handleRoot() {
|
||||
"<option value='42'>Hitachi2 (53 bytes)</option>"
|
||||
"<option selected='selected' value='18'>Kelvinator</option>" // Default
|
||||
"<option value='20'>Mitsubishi</option>"
|
||||
"<option value='52'>MWM</option>"
|
||||
"<option value='46'>Samsung</option>"
|
||||
"<option value='32'>Toshiba</option>"
|
||||
"<option value='28'>Trotec</option>"
|
||||
"<option value='45'>Whirlpool</option>"
|
||||
"</select>"
|
||||
" State code: 0x"
|
||||
"<input type='text' name='code' size='" + String(STATE_SIZE_MAX * 2) +
|
||||
"' maxlength='" + String(STATE_SIZE_MAX * 2) + "'"
|
||||
"<input type='text' name='code' size='" + String(kStateSizeMax * 2) +
|
||||
"' maxlength='" + String(kStateSizeMax * 2) + "'"
|
||||
" value='190B8050000000E0190B8070000010F0'>"
|
||||
" <input type='submit' value='Send A/C State'>"
|
||||
"</form>"
|
||||
@@ -462,9 +539,11 @@ void handleReset() {
|
||||
// Args:
|
||||
// irType: Nr. of the protocol we need to send.
|
||||
// str: A hexadecimal string containing the state to be sent.
|
||||
void parseStringAndSendAirCon(const uint16_t irType, const String str) {
|
||||
// Returns:
|
||||
// bool: Successfully sent or not.
|
||||
bool parseStringAndSendAirCon(const uint16_t irType, const String str) {
|
||||
uint8_t strOffset = 0;
|
||||
uint8_t state[STATE_SIZE_MAX] = {0}; // All array elements are set to 0.
|
||||
uint8_t state[kStateSizeMax] = {0}; // All array elements are set to 0.
|
||||
uint16_t stateSize = 0;
|
||||
|
||||
if (str.startsWith("0x") || str.startsWith("0X"))
|
||||
@@ -473,30 +552,36 @@ void parseStringAndSendAirCon(const uint16_t irType, const String str) {
|
||||
uint16_t inputLength = str.length() - strOffset;
|
||||
if (inputLength == 0) {
|
||||
debug("Zero length AirCon code encountered. Ignored.");
|
||||
return; // No input. Abort.
|
||||
return false; // No input. Abort.
|
||||
}
|
||||
|
||||
switch (irType) { // Get the correct state size for the protocol.
|
||||
case KELVINATOR:
|
||||
stateSize = KELVINATOR_STATE_LENGTH;
|
||||
stateSize = kKelvinatorStateLength;
|
||||
break;
|
||||
case TOSHIBA_AC:
|
||||
stateSize = TOSHIBA_AC_STATE_LENGTH;
|
||||
stateSize = kToshibaACStateLength;
|
||||
break;
|
||||
case DAIKIN:
|
||||
stateSize = DAIKIN_COMMAND_LENGTH;
|
||||
stateSize = kDaikinStateLength;
|
||||
break;
|
||||
case ELECTRA_AC:
|
||||
stateSize = kElectraAcStateLength;
|
||||
break;
|
||||
case MITSUBISHI_AC:
|
||||
stateSize = MITSUBISHI_AC_STATE_LENGTH;
|
||||
stateSize = kMitsubishiACStateLength;
|
||||
break;
|
||||
case PANASONIC_AC:
|
||||
stateSize = kPanasonicAcStateLength;
|
||||
break;
|
||||
case TROTEC:
|
||||
stateSize = TROTEC_COMMAND_LENGTH;
|
||||
stateSize = kTrotecStateLength;
|
||||
break;
|
||||
case ARGO:
|
||||
stateSize = ARGO_COMMAND_LENGTH;
|
||||
stateSize = kArgoStateLength;
|
||||
break;
|
||||
case GREE:
|
||||
stateSize = GREE_STATE_LENGTH;
|
||||
stateSize = kGreeStateLength;
|
||||
break;
|
||||
case FUJITSU_AC:
|
||||
// Fujitsu has four distinct & different size states, so make a best guess
|
||||
@@ -506,37 +591,66 @@ void parseStringAndSendAirCon(const uint16_t irType, const String str) {
|
||||
stateSize = inputLength / 2; // Every two hex chars is a byte.
|
||||
// Use at least the minimum size.
|
||||
stateSize = std::max(stateSize,
|
||||
(uint16_t) (FUJITSU_AC_STATE_LENGTH_SHORT - 1));
|
||||
(uint16_t) (kFujitsuAcStateLengthShort - 1));
|
||||
// If we think it isn't a "short" message.
|
||||
if (stateSize > FUJITSU_AC_STATE_LENGTH_SHORT)
|
||||
if (stateSize > kFujitsuAcStateLengthShort)
|
||||
// Then it has to be at least the smaller version of the "normal" size.
|
||||
stateSize = std::max(stateSize,
|
||||
(uint16_t) (FUJITSU_AC_STATE_LENGTH - 1));
|
||||
stateSize = std::max(stateSize, (uint16_t) (kFujitsuAcStateLength - 1));
|
||||
// Lastly, it should never exceed the maximum "normal" size.
|
||||
stateSize = std::min(stateSize, (uint16_t) FUJITSU_AC_STATE_LENGTH);
|
||||
stateSize = std::min(stateSize, kFujitsuAcStateLength);
|
||||
break;
|
||||
case HAIER_AC:
|
||||
stateSize = HAIER_AC_STATE_LENGTH;
|
||||
stateSize = kHaierACStateLength;
|
||||
break;
|
||||
case HAIER_AC_YRW02:
|
||||
stateSize = HAIER_AC_YRW02_STATE_LENGTH;
|
||||
stateSize = kHaierACYRW02StateLength;
|
||||
break;
|
||||
case HITACHI_AC:
|
||||
stateSize = HITACHI_AC_STATE_LENGTH;
|
||||
stateSize = kHitachiAcStateLength;
|
||||
break;
|
||||
case HITACHI_AC1:
|
||||
stateSize = HITACHI_AC1_STATE_LENGTH;
|
||||
stateSize = kHitachiAc1StateLength;
|
||||
break;
|
||||
case HITACHI_AC2:
|
||||
stateSize = HITACHI_AC2_STATE_LENGTH;
|
||||
stateSize = kHitachiAc2StateLength;
|
||||
break;
|
||||
case WHIRLPOOL_AC:
|
||||
stateSize = kWhirlpoolAcStateLength;
|
||||
break;
|
||||
case SAMSUNG_AC:
|
||||
// Samsung has two distinct & different size states, so make a best guess
|
||||
// which one we are being presented with based on the number of
|
||||
// hexadecimal digits provided. i.e. Zero-pad if you need to to get
|
||||
// the correct length/byte size.
|
||||
stateSize = inputLength / 2; // Every two hex chars is a byte.
|
||||
// Use at least the minimum size.
|
||||
stateSize = std::max(stateSize, (uint16_t) (kSamsungAcStateLength));
|
||||
// If we think it isn't a "normal" message.
|
||||
if (stateSize > kSamsungAcStateLength)
|
||||
// Then it probably the extended size.
|
||||
stateSize = std::max(stateSize,
|
||||
(uint16_t) (kSamsungAcExtendedStateLength));
|
||||
// Lastly, it should never exceed the maximum "extended" size.
|
||||
stateSize = std::min(stateSize, kSamsungAcExtendedStateLength);
|
||||
break;
|
||||
case MWM:
|
||||
// MWM has variable size states, so make a best guess
|
||||
// which one we are being presented with based on the number of
|
||||
// hexadecimal digits provided. i.e. Zero-pad if you need to to get
|
||||
// the correct length/byte size.
|
||||
stateSize = inputLength / 2; // Every two hex chars is a byte.
|
||||
// Use at least the minimum size.
|
||||
stateSize = std::max(stateSize, (uint16_t) 3);
|
||||
// Cap the maximum size.
|
||||
stateSize = std::min(stateSize, kStateSizeMax);
|
||||
break;
|
||||
default: // Not a protocol we expected. Abort.
|
||||
debug("Unexpected AirCon protocol detected. Ignoring.");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
if (inputLength > stateSize * 2) {
|
||||
debug("AirCon code to large for the given protocol.");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ptr to the least significant byte of the resulting state for this protocol.
|
||||
@@ -553,7 +667,7 @@ void parseStringAndSendAirCon(const uint16_t irType, const String str) {
|
||||
c = c - 'a' + 10;
|
||||
} else {
|
||||
debug("Aborting! Non-hexadecimal char found in AirCon state: " + str);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
if (i % 2 == 1) { // Odd: Upper half of the byte.
|
||||
*statePtr += (c << 4);
|
||||
@@ -630,7 +744,36 @@ void parseStringAndSendAirCon(const uint16_t irType, const String str) {
|
||||
irsend.sendHitachiAC2(reinterpret_cast<uint8_t *>(state));
|
||||
break;
|
||||
#endif
|
||||
#if SEND_WHIRLPOOL_AC
|
||||
case WHIRLPOOL_AC:
|
||||
irsend.sendWhirlpoolAC(reinterpret_cast<uint8_t *>(state));
|
||||
break;
|
||||
#endif
|
||||
#if SEND_SAMSUNG_AC
|
||||
case SAMSUNG_AC:
|
||||
irsend.sendSamsungAC(reinterpret_cast<uint8_t *>(state), stateSize);
|
||||
break;
|
||||
#endif
|
||||
#if SEND_ELECTRA_AC
|
||||
case ELECTRA_AC:
|
||||
irsend.sendElectraAC(reinterpret_cast<uint8_t *>(state));
|
||||
break;
|
||||
#endif
|
||||
#if SEND_PANASONIC_AC
|
||||
case PANASONIC_AC:
|
||||
irsend.sendPanasonicAC(reinterpret_cast<uint8_t *>(state));
|
||||
break;
|
||||
#endif
|
||||
#if SEND_MWM_
|
||||
case MWM:
|
||||
irsend.sendMWM(reinterpret_cast<uint8_t *>(state), stateSize);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
debug("Unexpected AirCon type in send request. Not sent.");
|
||||
return false;
|
||||
}
|
||||
return true; // We were successful as far as we can tell.
|
||||
}
|
||||
|
||||
// Count how many values are in the String.
|
||||
@@ -679,7 +822,9 @@ uint16_t * newCodeArray(const uint16_t size) {
|
||||
// 20,20,20,20,20,20,20,20,20,20,20,20,20,63,20,20,20,63,20,63,20,
|
||||
// 63,20,63,20,63,20,63,20,1798"
|
||||
// Note: The leading "1:1,1," of normal GC codes should be removed.
|
||||
void parseStringAndSendGC(const String str) {
|
||||
// Returns:
|
||||
// bool: Successfully sent or not.
|
||||
bool parseStringAndSendGC(const String str) {
|
||||
uint16_t count;
|
||||
uint16_t *code_array;
|
||||
String tmp_str;
|
||||
@@ -709,6 +854,9 @@ void parseStringAndSendGC(const String str) {
|
||||
|
||||
irsend.sendGC(code_array, count); // All done. Send it.
|
||||
free(code_array); // Free up the memory allocated.
|
||||
if (count > 0)
|
||||
return true; // We sent something.
|
||||
return false; // We probably didn't.
|
||||
}
|
||||
#endif // SEND_GLOBALCACHE
|
||||
|
||||
@@ -722,11 +870,13 @@ void parseStringAndSendGC(const String str) {
|
||||
// 0030,0018,0018,0018,0018,0018,0030,0018,0018,03f6"
|
||||
// or
|
||||
// "0000,0067,0000,0015,0060,0018". i.e. without the Repeat value
|
||||
// Requires at least PRONTO_MIN_LENGTH comma-separated values.
|
||||
// Requires at least kProntoMinLength comma-separated values.
|
||||
// sendPronto() only supports raw pronto code types, thus so does this.
|
||||
// repeats: Nr. of times the message is to be repeated.
|
||||
// This value is ignored if an embeddd repeat is found in str.
|
||||
void parseStringAndSendPronto(const String str, uint16_t repeats) {
|
||||
// Returns:
|
||||
// bool: Successfully sent or not.
|
||||
bool parseStringAndSendPronto(const String str, uint16_t repeats) {
|
||||
uint16_t count;
|
||||
uint16_t *code_array;
|
||||
int16_t index = -1;
|
||||
@@ -744,8 +894,8 @@ void parseStringAndSendPronto(const String str, uint16_t repeats) {
|
||||
count--; // We don't count the repeats value as part of the code array.
|
||||
}
|
||||
|
||||
// We need at least PRONTO_MIN_LENGTH values for the code part.
|
||||
if (count < PRONTO_MIN_LENGTH) return;
|
||||
// We need at least kProntoMinLength values for the code part.
|
||||
if (count < kProntoMinLength) return false;
|
||||
|
||||
// Now we know how many there are, allocate the memory to store them all.
|
||||
code_array = newCodeArray(count);
|
||||
@@ -764,6 +914,9 @@ void parseStringAndSendPronto(const String str, uint16_t repeats) {
|
||||
|
||||
irsend.sendPronto(code_array, count, repeats); // All done. Send it.
|
||||
free(code_array); // Free up the memory allocated.
|
||||
if (count > 0)
|
||||
return true; // We sent something.
|
||||
return false; // We probably didn't.
|
||||
}
|
||||
#endif // SEND_PRONTO
|
||||
|
||||
@@ -774,7 +927,9 @@ void parseStringAndSendPronto(const String str, uint16_t repeats) {
|
||||
// e.g. "38000,9000,4500,600,1450,600,900,650,1500,..."
|
||||
// Requires at least two comma-separated values.
|
||||
// First value is the transmission frequency in Hz or kHz.
|
||||
void parseStringAndSendRaw(const String str) {
|
||||
// Returns:
|
||||
// bool: Successfully sent or not.
|
||||
bool parseStringAndSendRaw(const String str) {
|
||||
uint16_t count;
|
||||
uint16_t freq = 38000; // Default to 38kHz.
|
||||
uint16_t *raw_array;
|
||||
@@ -784,7 +939,7 @@ void parseStringAndSendRaw(const String str) {
|
||||
|
||||
// We expect the frequency as the first comma separated value, so we need at
|
||||
// least two values. If not, bail out.
|
||||
if (count < 2) return;
|
||||
if (count < 2) return false;
|
||||
count--; // We don't count the frequency value as part of the raw array.
|
||||
|
||||
// Now we know how many there are, allocate the memory to store them all.
|
||||
@@ -806,6 +961,9 @@ void parseStringAndSendRaw(const String str) {
|
||||
|
||||
irsend.sendRaw(raw_array, count, freq); // All done. Send it.
|
||||
free(raw_array); // Free up the memory allocated.
|
||||
if (count > 0)
|
||||
return true; // We sent something.
|
||||
return false; // We probably didn't.
|
||||
}
|
||||
#endif // SEND_RAW
|
||||
|
||||
@@ -830,7 +988,8 @@ void handleIr() {
|
||||
repeat = atoi(server.arg(i).c_str());
|
||||
}
|
||||
debug("New code received via HTTP");
|
||||
sendIRCode(ir_type, data, data_str.c_str(), nbits, repeat);
|
||||
lastSendSucceeded = sendIRCode(ir_type, data, data_str.c_str(), nbits,
|
||||
repeat);
|
||||
handleRoot();
|
||||
}
|
||||
|
||||
@@ -844,7 +1003,7 @@ void handleNotFound() {
|
||||
message += server.args();
|
||||
message += "\n";
|
||||
for (uint8_t i=0; i < server.args(); i++)
|
||||
message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
|
||||
message += ' ' + server.argName(i) + ": " + server.arg(i) + "\n";
|
||||
server.send(404, "text/plain", message);
|
||||
}
|
||||
|
||||
@@ -871,6 +1030,13 @@ void setup_wifi() {
|
||||
void setup(void) {
|
||||
irsend.begin();
|
||||
offset = irsend.calibrate();
|
||||
#if IR_RX
|
||||
#if DECODE_HASH
|
||||
// Ignore messages with less than minimum on or off pulses.
|
||||
irrecv.setUnknownThreshold(kMinUnknownSize);
|
||||
#endif // DECODE_HASH
|
||||
irrecv.enableIRIn(); // Start the receiver
|
||||
#endif // IR_RX
|
||||
|
||||
#ifdef DEBUG
|
||||
// Use SERIAL_TX_ONLY so that the RX pin can be freed up for GPIO/IR use.
|
||||
@@ -954,7 +1120,7 @@ bool reconnect() {
|
||||
while (!mqtt_client.connected() && tries <= 3) {
|
||||
int connected = false;
|
||||
// Attempt to connect
|
||||
debug("Attempting MQTT connection to " MQTT_SERVER ":" + String(MQTT_PORT) +
|
||||
debug("Attempting MQTT connection to " MQTT_SERVER ":" + String(kMqttPort) +
|
||||
"... ");
|
||||
if (mqtt_user && mqtt_password)
|
||||
connected = mqtt_client.connect(mqtt_clientid.c_str(), mqtt_user,
|
||||
@@ -980,32 +1146,57 @@ bool reconnect() {
|
||||
#endif // MQTT_ENABLE
|
||||
|
||||
void loop(void) {
|
||||
server.handleClient();
|
||||
server.handleClient(); // Handle any web activity
|
||||
|
||||
#ifdef MQTT_ENABLE
|
||||
uint32_t now = millis();
|
||||
// MQTT client connection management
|
||||
if (!mqtt_client.connected()) {
|
||||
uint32_t now = millis();
|
||||
// Reconnect if it's longer than MQTT_RECONNECT_TIME since we last tried.
|
||||
if (now - lastReconnectAttempt > MQTT_RECONNECT_TIME) {
|
||||
if (wasConnected) {
|
||||
lastDisconnectedTime = now;
|
||||
wasConnected = false;
|
||||
mqttDisconnectCounter++;
|
||||
}
|
||||
// Reconnect if it's longer than kMqttReconnectTime since we last tried.
|
||||
if (now - lastReconnectAttempt > kMqttReconnectTime) {
|
||||
lastReconnectAttempt = now;
|
||||
debug("client mqtt not connected, trying to connect");
|
||||
// Attempt to reconnect
|
||||
if (reconnect()) {
|
||||
lastReconnectAttempt = 0;
|
||||
wasConnected = true;
|
||||
if (boot) {
|
||||
mqtt_client.publish(MQTTack, "IR Server just booted");
|
||||
boot = false;
|
||||
} else {
|
||||
mqtt_client.publish(MQTTack, "IR Server just (re)connected to MQTT");
|
||||
String text = "IR Server just (re)connected to MQTT. "
|
||||
"Lost connection about " + timeSince(lastConnectedTime);
|
||||
mqtt_client.publish(MQTTack, text.c_str());
|
||||
}
|
||||
lastConnectedTime = now;
|
||||
debug("successful client mqtt connection");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
lastConnectedTime = now;
|
||||
// MQTT loop
|
||||
mqtt_client.loop();
|
||||
}
|
||||
#endif // MQTT_ENABLE
|
||||
#ifdef IR_RX
|
||||
// Check if an IR code has been received via the IR RX module.
|
||||
if (irrecv.decode(&capture)) {
|
||||
lastIrReceivedTime = millis();
|
||||
lastIrReceived = String(capture.decode_type) + "," +
|
||||
resultToHexidecimal(&capture);
|
||||
// If it isn't an AC code, add the bits.
|
||||
if (!hasACState(capture.decode_type))
|
||||
lastIrReceived += "," + String(capture.bits);
|
||||
mqtt_client.publish(MQTTrecv, lastIrReceived.c_str());
|
||||
irRecvCounter++;
|
||||
debug("Incoming IR message sent to MQTT: " + lastIrReceived);
|
||||
}
|
||||
#endif // IR_RX
|
||||
delay(100);
|
||||
}
|
||||
|
||||
@@ -1037,114 +1228,118 @@ uint64_t getUInt64fromHex(char const *str) {
|
||||
// code_str: The unparsed code to be sent. Used by complex protocol encodings.
|
||||
// bits: Nr. of bits in the protocol. 0 means use the protocol's default.
|
||||
// repeat: Nr. of times the message is to be repeated. (Not all protcols.)
|
||||
void sendIRCode(int const ir_type, uint64_t const code, char const * code_str,
|
||||
// Returns:
|
||||
// bool: Successfully sent or not.
|
||||
bool sendIRCode(int const ir_type, uint64_t const code, char const * code_str,
|
||||
uint16_t bits, uint16_t repeat) {
|
||||
// Create a pseudo-lock so we don't try to send two codes at the same time.
|
||||
while (ir_lock)
|
||||
delay(20);
|
||||
ir_lock = true;
|
||||
|
||||
bool success = true; // Assume success.
|
||||
|
||||
// send the IR message.
|
||||
switch (ir_type) {
|
||||
#if SEND_RC5
|
||||
case RC5: // 1
|
||||
if (bits == 0)
|
||||
bits = RC5_BITS;
|
||||
bits = kRC5Bits;
|
||||
irsend.sendRC5(code, bits, repeat);
|
||||
break;
|
||||
#endif
|
||||
#if SEND_RC6
|
||||
case RC6: // 2
|
||||
if (bits == 0)
|
||||
bits = RC6_MODE0_BITS;
|
||||
bits = kRC6Mode0Bits;
|
||||
irsend.sendRC6(code, bits, repeat);
|
||||
break;
|
||||
#endif
|
||||
#if SEND_NEC
|
||||
case NEC: // 3
|
||||
if (bits == 0)
|
||||
bits = NEC_BITS;
|
||||
bits = kNECBits;
|
||||
irsend.sendNEC(code, bits, repeat);
|
||||
break;
|
||||
#endif
|
||||
#if SEND_SONY
|
||||
case SONY: // 4
|
||||
if (bits == 0)
|
||||
bits = SONY_12_BITS;
|
||||
repeat = std::max(repeat, (uint16_t) SONY_MIN_REPEAT);
|
||||
bits = kSony12Bits;
|
||||
repeat = std::max(repeat, kSonyMinRepeat);
|
||||
irsend.sendSony(code, bits, repeat);
|
||||
break;
|
||||
#endif
|
||||
#if SEND_PANASONIC
|
||||
case PANASONIC: // 5
|
||||
if (bits == 0)
|
||||
bits = PANASONIC_BITS;
|
||||
bits = kPanasonicBits;
|
||||
irsend.sendPanasonic64(code, bits, repeat);
|
||||
break;
|
||||
#endif
|
||||
#if SEND_JVC
|
||||
case JVC: // 6
|
||||
if (bits == 0)
|
||||
bits = JVC_BITS;
|
||||
bits = kJvcBits;
|
||||
irsend.sendJVC(code, bits, repeat);
|
||||
break;
|
||||
#endif
|
||||
#if SEND_SAMSUNG
|
||||
case SAMSUNG: // 7
|
||||
if (bits == 0)
|
||||
bits = SAMSUNG_BITS;
|
||||
bits = kSamsungBits;
|
||||
irsend.sendSAMSUNG(code, bits, repeat);
|
||||
break;
|
||||
#endif
|
||||
#if SEND_WHYNTER
|
||||
case WHYNTER: // 8
|
||||
if (bits == 0)
|
||||
bits = WHYNTER_BITS;
|
||||
bits = kWhynterBits;
|
||||
irsend.sendWhynter(code, bits, repeat);
|
||||
break;
|
||||
#endif
|
||||
#if SEND_AIWA_RC_T501
|
||||
case AIWA_RC_T501: // 9
|
||||
if (bits == 0)
|
||||
bits = AIWA_RC_T501_BITS;
|
||||
repeat = std::max(repeat, (uint16_t) AIWA_RC_T501_MIN_REPEAT);
|
||||
bits = kAiwaRcT501Bits;
|
||||
repeat = std::max(repeat, kAiwaRcT501MinRepeats);
|
||||
irsend.sendAiwaRCT501(code, bits, repeat);
|
||||
break;
|
||||
#endif
|
||||
#if SEND_LG
|
||||
case LG: // 10
|
||||
if (bits == 0)
|
||||
bits = LG_BITS;
|
||||
bits = kLgBits;
|
||||
irsend.sendLG(code, bits, repeat);
|
||||
break;
|
||||
#endif
|
||||
#if SEND_MITSUBISHI
|
||||
case MITSUBISHI: // 12
|
||||
if (bits == 0)
|
||||
bits = MITSUBISHI_BITS;
|
||||
repeat = std::max(repeat, (uint16_t) MITSUBISHI_MIN_REPEAT);
|
||||
bits = kMitsubishiBits;
|
||||
repeat = std::max(repeat, kMitsubishiMinRepeat);
|
||||
irsend.sendMitsubishi(code, bits, repeat);
|
||||
break;
|
||||
#endif
|
||||
#if SEND_DISH
|
||||
case DISH: // 13
|
||||
if (bits == 0)
|
||||
bits = DISH_BITS;
|
||||
repeat = std::max(repeat, (uint16_t) DISH_MIN_REPEAT);
|
||||
bits = kDishBits;
|
||||
repeat = std::max(repeat, kDishMinRepeat);
|
||||
irsend.sendDISH(code, bits, repeat);
|
||||
break;
|
||||
#endif
|
||||
#if SEND_SHARP
|
||||
case SHARP: // 14
|
||||
if (bits == 0)
|
||||
bits = SHARP_BITS;
|
||||
bits = kSharpBits;
|
||||
irsend.sendSharpRaw(code, bits, repeat);
|
||||
break;
|
||||
#endif
|
||||
#if SEND_COOLIX
|
||||
case COOLIX: // 15
|
||||
if (bits == 0)
|
||||
bits = COOLIX_BITS;
|
||||
bits = kCoolixBits;
|
||||
irsend.sendCOOLIX(code, bits, repeat);
|
||||
break;
|
||||
#endif
|
||||
@@ -1161,7 +1356,12 @@ void sendIRCode(int const ir_type, uint64_t const code, char const * code_str,
|
||||
case HITACHI_AC: // 40
|
||||
case HITACHI_AC1: // 41
|
||||
case HITACHI_AC2: // 42
|
||||
parseStringAndSendAirCon(ir_type, code_str);
|
||||
case WHIRLPOOL_AC: // 45
|
||||
case SAMSUNG_AC: // 46
|
||||
case ELECTRA_AC: // 48
|
||||
case PANASONIC_AC: // 49
|
||||
case MWM: // 52
|
||||
success = parseStringAndSendAirCon(ir_type, code_str);
|
||||
break;
|
||||
#if SEND_DENON
|
||||
case DENON: // 17
|
||||
@@ -1173,105 +1373,135 @@ void sendIRCode(int const ir_type, uint64_t const code, char const * code_str,
|
||||
#if SEND_SHERWOOD
|
||||
case SHERWOOD: // 19
|
||||
if (bits == 0)
|
||||
bits = SHERWOOD_BITS;
|
||||
repeat = std::max(repeat, (uint16_t) SHERWOOD_MIN_REPEAT);
|
||||
bits = kSherwoodBits;
|
||||
repeat = std::max(repeat, kSherwoodMinRepeat);
|
||||
irsend.sendSherwood(code, bits, repeat);
|
||||
break;
|
||||
#endif
|
||||
#if SEND_RCMM
|
||||
case RCMM: // 21
|
||||
if (bits == 0)
|
||||
bits = RCMM_BITS;
|
||||
bits = kRCMMBits;
|
||||
irsend.sendRCMM(code, bits, repeat);
|
||||
break;
|
||||
#endif
|
||||
#if SEND_SANYO
|
||||
case SANYO_LC7461: // 22
|
||||
if (bits == 0)
|
||||
bits = SANYO_LC7461_BITS;
|
||||
bits = kSanyoLC7461Bits;
|
||||
irsend.sendSanyoLC7461(code, bits, repeat);
|
||||
break;
|
||||
#endif
|
||||
#if SEND_RC5
|
||||
case RC5X: // 23
|
||||
if (bits == 0)
|
||||
bits = RC5X_BITS;
|
||||
bits = kRC5XBits;
|
||||
irsend.sendRC5(code, bits, repeat);
|
||||
break;
|
||||
#endif
|
||||
#if SEND_PRONTO
|
||||
case PRONTO: // 25
|
||||
parseStringAndSendPronto(code_str, repeat);
|
||||
success = parseStringAndSendPronto(code_str, repeat);
|
||||
break;
|
||||
#endif
|
||||
#if SEND_NIKAI
|
||||
case NIKAI: // 29
|
||||
if (bits == 0)
|
||||
bits = NIKAI_BITS;
|
||||
bits = kNikaiBits;
|
||||
irsend.sendNikai(code, bits, repeat);
|
||||
break;
|
||||
#endif
|
||||
#if SEND_RAW
|
||||
case RAW: // 30
|
||||
parseStringAndSendRaw(code_str);
|
||||
success = parseStringAndSendRaw(code_str);
|
||||
break;
|
||||
#endif
|
||||
#if SEND_GLOBALCACHE
|
||||
case GLOBALCACHE: // 31
|
||||
parseStringAndSendGC(code_str);
|
||||
success = parseStringAndSendGC(code_str);
|
||||
break;
|
||||
#endif
|
||||
#if SEND_MIDEA
|
||||
case MIDEA: // 34
|
||||
if (bits == 0)
|
||||
bits = MIDEA_BITS;
|
||||
bits = kMideaBits;
|
||||
irsend.sendMidea(code, bits, repeat);
|
||||
break;
|
||||
#endif
|
||||
#if SEND_MAGIQUEST
|
||||
case MAGIQUEST: // 35
|
||||
if (bits == 0)
|
||||
bits = MAGIQUEST_BITS;
|
||||
bits = kMagiquestBits;
|
||||
irsend.sendMagiQuest(code, bits, repeat);
|
||||
break;
|
||||
#endif
|
||||
#if SEND_LASERTAG
|
||||
case LASERTAG: // 36
|
||||
if (bits == 0)
|
||||
bits = LASERTAG_BITS;
|
||||
bits = kLasertagBits;
|
||||
irsend.sendLasertag(code, bits, repeat);
|
||||
break;
|
||||
#endif
|
||||
#if SEND_CARRIER_AC
|
||||
case CARRIER_AC: // 37
|
||||
if (bits == 0)
|
||||
bits = CARRIER_AC_BITS;
|
||||
bits = kCarrierAcBits;
|
||||
irsend.sendCarrierAC(code, bits, repeat);
|
||||
break;
|
||||
#endif
|
||||
#if SEND_MITSUBISHI2
|
||||
case MITSUBISHI2: // 39
|
||||
if (bits == 0)
|
||||
bits = MITSUBISHI_BITS;
|
||||
repeat = std::max(repeat, (uint16_t) MITSUBISHI_MIN_REPEAT);
|
||||
bits = kMitsubishiBits;
|
||||
repeat = std::max(repeat, kMitsubishiMinRepeat);
|
||||
irsend.sendMitsubishi2(code, bits, repeat);
|
||||
break;
|
||||
#endif
|
||||
#if SEND_GICABLE
|
||||
case GICABLE: // 43
|
||||
if (bits == 0)
|
||||
bits = GICABLE_BITS;
|
||||
repeat = std::max(repeat, (uint16_t) GICABLE_MIN_REPEAT);
|
||||
bits = kGicableBits;
|
||||
repeat = std::max(repeat, kGicableMinRepeat);
|
||||
irsend.sendGICable(code, bits, repeat);
|
||||
break;
|
||||
#endif
|
||||
#if SEND_LUTRON
|
||||
case LUTRON: // 47
|
||||
if (bits == 0)
|
||||
bits = kLutronBits;
|
||||
irsend.sendLutron(code, bits, repeat);
|
||||
break;
|
||||
#endif
|
||||
#if SEND_PIONEER
|
||||
case PIONEER: // 50
|
||||
if (bits == 0)
|
||||
bits = kPioneerBits;
|
||||
irsend.sendPioneer(code, bits, repeat);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if SEND_LG
|
||||
case LG2: // 51
|
||||
if (bits == 0)
|
||||
bits = kLgBits;
|
||||
irsend.sendLG2(code, bits, repeat);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
// If we got here, we didn't know how to send it.
|
||||
success = false;
|
||||
}
|
||||
sendReqCounter++;
|
||||
lastSendTime = millis();
|
||||
// Release the lock.
|
||||
ir_lock = false;
|
||||
|
||||
// Indicate that we sent the message.
|
||||
debug("Sent the IR message.");
|
||||
// Indicate that we sent the message or not.
|
||||
if (success) {
|
||||
sendReqCounter++;
|
||||
debug("Sent the IR message:");
|
||||
} else {
|
||||
debug("Failed to send IR Message:");
|
||||
}
|
||||
debug("Type: " + String(ir_type));
|
||||
// For "long" codes we basically repeat what we got.
|
||||
if (hasACState((decode_type_t) ir_type) ||
|
||||
@@ -1280,28 +1510,31 @@ void sendIRCode(int const ir_type, uint64_t const code, char const * code_str,
|
||||
ir_type == GLOBALCACHE) {
|
||||
debug("Code: ");
|
||||
debug(code_str);
|
||||
debug("Repeats: " + String(repeat));
|
||||
// Confirm what we were asked to send was sent.
|
||||
#ifdef MQTT_ENABLE
|
||||
if (ir_type == PRONTO && repeat > 0)
|
||||
mqtt_client.publish(MQTTack, (String(ir_type) + ",R" +
|
||||
String(repeat) + "," +
|
||||
String(code_str)).c_str());
|
||||
else
|
||||
mqtt_client.publish(MQTTack, (String(ir_type) + "," +
|
||||
String(code_str)).c_str());
|
||||
if (success) {
|
||||
if (ir_type == PRONTO && repeat > 0)
|
||||
mqtt_client.publish(MQTTack, (String(ir_type) + ",R" +
|
||||
String(repeat) + "," +
|
||||
String(code_str)).c_str());
|
||||
else
|
||||
mqtt_client.publish(MQTTack, (String(ir_type) + "," +
|
||||
String(code_str)).c_str());
|
||||
}
|
||||
#endif // MQTT_ENABLE
|
||||
} else { // For "short" codes, we break it down a bit more before we report.
|
||||
debug("Code: 0x" + uint64ToString(code, 16));
|
||||
debug("Bits: " + String(bits));
|
||||
debug("Repeats: " + String(repeat));
|
||||
#ifdef MQTT_ENABLE
|
||||
mqtt_client.publish(MQTTack, (String(ir_type) + "," +
|
||||
uint64ToString(code, 16)
|
||||
+ "," + String(bits) + "," +
|
||||
String(repeat)).c_str());
|
||||
if (success)
|
||||
mqtt_client.publish(MQTTack, (String(ir_type) + "," +
|
||||
uint64ToString(code, 16)
|
||||
+ "," + String(bits) + "," +
|
||||
String(repeat)).c_str());
|
||||
#endif // MQTT_ENABLE
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
#ifdef MQTT_ENABLE
|
||||
@@ -1344,9 +1577,10 @@ void receivingMQTT(String const topic_name, String const callback_str) {
|
||||
|
||||
|
||||
// send received MQTT value by IR signal
|
||||
sendIRCode(ir_type, code,
|
||||
callback_str.substring(callback_str.indexOf(",") + 1).c_str(),
|
||||
nbits, repeat);
|
||||
lastSendSucceeded = sendIRCode(
|
||||
ir_type, code,
|
||||
callback_str.substring(callback_str.indexOf(",") + 1).c_str(),
|
||||
nbits, repeat);
|
||||
}
|
||||
|
||||
// Callback function, when the gateway receive an MQTT value on the topics
|
||||
|
||||
@@ -7,7 +7,7 @@ build_flags = -DMQTT_MAX_PACKET_SIZE=512
|
||||
lib_deps_builtin =
|
||||
lib_deps_external =
|
||||
PubSubClient
|
||||
WifiManager@0.12
|
||||
WifiManager@0.14
|
||||
|
||||
[env:nodemcuv2]
|
||||
platform = espressif8266
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* Copyright 2015 Mark Szabo
|
||||
*
|
||||
* An IR LED circuit *MUST* be connected to the ESP8266 on a pin
|
||||
* as specified by IR_LED below.
|
||||
* as specified by kIrLed below.
|
||||
*
|
||||
* TL;DR: The IR LED needs to be driven by a transistor for a good result.
|
||||
*
|
||||
@@ -36,15 +36,15 @@
|
||||
#include <IRsend.h>
|
||||
#include <WiFiClient.h>
|
||||
|
||||
const char* ssid = ".....";
|
||||
const char* password = ".....";
|
||||
const char* kSsid = ".....";
|
||||
const char* kPassword = ".....";
|
||||
MDNSResponder mdns;
|
||||
|
||||
ESP8266WebServer server(80);
|
||||
|
||||
#define IR_LED 4 // ESP8266 GPIO pin to use. Recommended: 4 (D2).
|
||||
const uint16_t kIrLed = 4; // ESP8266 GPIO pin to use. Recommended: 4 (D2).
|
||||
|
||||
IRsend irsend(IR_LED); // Set the GPIO to be used to sending the message.
|
||||
IRsend irsend(kIrLed); // Set the GPIO to be used to sending the message.
|
||||
|
||||
void handleRoot() {
|
||||
server.send(200, "text/html",
|
||||
@@ -82,7 +82,7 @@ void handleNotFound() {
|
||||
message += server.args();
|
||||
message += "\n";
|
||||
for (uint8_t i = 0; i < server.args(); i++)
|
||||
message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
|
||||
message += ' ' + server.argName(i) + ": " + server.arg(i) + "\n";
|
||||
server.send(404, "text/plain", message);
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ void setup(void) {
|
||||
irsend.begin();
|
||||
|
||||
Serial.begin(115200);
|
||||
WiFi.begin(ssid, password);
|
||||
WiFi.begin(kSsid, kPassword);
|
||||
Serial.println("");
|
||||
|
||||
// Wait for connection
|
||||
@@ -100,7 +100,7 @@ void setup(void) {
|
||||
}
|
||||
Serial.println("");
|
||||
Serial.print("Connected to ");
|
||||
Serial.println(ssid);
|
||||
Serial.println(kSsid);
|
||||
Serial.print("IP address: ");
|
||||
Serial.println(WiFi.localIP().toString());
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* This is very simple teaching code to show you how to use the library.
|
||||
* If you are trying to decode your Infra-Red remote(s) for later replay,
|
||||
* use the IRrecvDumpV2.ino example code instead of this.
|
||||
* An IR detector/demodulator must be connected to the input RECV_PIN.
|
||||
* An IR detector/demodulator must be connected to the input kRecvPin.
|
||||
* Copyright 2009 Ken Shirriff, http://arcfn.com
|
||||
* Example circuit diagram:
|
||||
* https://github.com/markszabo/IRremoteESP8266/wiki#ir-receiving
|
||||
@@ -25,9 +25,9 @@
|
||||
|
||||
// An IR detector/demodulator is connected to GPIO pin 14(D5 on a NodeMCU
|
||||
// board).
|
||||
uint16_t RECV_PIN = 14;
|
||||
const uint16_t kRecvPin = 14;
|
||||
|
||||
IRrecv irrecv(RECV_PIN);
|
||||
IRrecv irrecv(kRecvPin);
|
||||
|
||||
decode_results results;
|
||||
|
||||
@@ -38,7 +38,7 @@ void setup() {
|
||||
delay(50);
|
||||
Serial.println();
|
||||
Serial.print("IRrecvDemo is now running and waiting for IR message on Pin ");
|
||||
Serial.println(RECV_PIN);
|
||||
Serial.println(kRecvPin);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
||||
@@ -86,10 +86,10 @@ void dump(decode_results *results) {
|
||||
if (i % 100 == 0)
|
||||
yield(); // Preemptive yield every 100th entry to feed the WDT.
|
||||
if (i & 1) {
|
||||
Serial.print(results->rawbuf[i] * RAWTICK, DEC);
|
||||
Serial.print(results->rawbuf[i] * kRawTick, DEC);
|
||||
} else {
|
||||
Serial.print(", ");
|
||||
Serial.print((uint32_t) results->rawbuf[i] * RAWTICK, DEC);
|
||||
Serial.print((uint32_t) results->rawbuf[i] * kRawTick, DEC);
|
||||
}
|
||||
}
|
||||
Serial.println("};");
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* IRremoteESP8266: IRrecvDumpV2 - dump details of IR codes with IRrecv
|
||||
* An IR detector/demodulator must be connected to the input RECV_PIN.
|
||||
* An IR detector/demodulator must be connected to the input kRecvPin.
|
||||
*
|
||||
* Copyright 2009 Ken Shirriff, http://arcfn.com
|
||||
* Copyright 2017 David Conran
|
||||
@@ -22,36 +22,39 @@
|
||||
#ifndef UNIT_TEST
|
||||
#include <Arduino.h>
|
||||
#endif
|
||||
#include <IRremoteESP8266.h>
|
||||
#include <IRrecv.h>
|
||||
#include <IRremoteESP8266.h>
|
||||
#include <IRutils.h>
|
||||
#if DECODE_AC
|
||||
// The following are only needed for extended decoding of A/C Messages
|
||||
#include <ir_Coolix.h>
|
||||
#include <ir_Daikin.h>
|
||||
#include <ir_Fujitsu.h>
|
||||
#include <ir_Gree.h>
|
||||
#include <ir_Haier.h>
|
||||
#include <ir_Kelvinator.h>
|
||||
#include <ir_Midea.h>
|
||||
#include <ir_Mitsubishi.h>
|
||||
#include <ir_Panasonic.h>
|
||||
#include <ir_Samsung.h>
|
||||
#include <ir_Toshiba.h>
|
||||
#endif // DECODE_AC
|
||||
|
||||
// ==================== start of TUNEABLE PARAMETERS ====================
|
||||
// An IR detector/demodulator is connected to GPIO pin 14
|
||||
// e.g. D5 on a NodeMCU board.
|
||||
#define RECV_PIN 14
|
||||
const uint16_t kRecvPin = 14;
|
||||
|
||||
// The Serial connection baud rate.
|
||||
// i.e. Status message will be sent to the PC at this baud rate.
|
||||
// Try to avoid slow speeds like 9600, as you will miss messages and
|
||||
// cause other problems. 115200 (or faster) is recommended.
|
||||
// NOTE: Make sure you set your Serial Monitor to the same speed.
|
||||
#define BAUD_RATE 115200
|
||||
const uint32_t kBaudRate = 115200;
|
||||
|
||||
// As this program is a special purpose capture/decoder, let us use a larger
|
||||
// than normal buffer so we can handle Air Conditioner remote codes.
|
||||
#define CAPTURE_BUFFER_SIZE 1024
|
||||
const uint16_t kCaptureBufferSize = 1024;
|
||||
|
||||
// TIMEOUT is the Nr. of milli-Seconds of no-more-data before we consider a
|
||||
// kTimeout is the Nr. of milli-Seconds of no-more-data before we consider a
|
||||
// message ended.
|
||||
// This parameter is an interesting trade-off. The longer the timeout, the more
|
||||
// complex a message it can capture. e.g. Some device protocols will send
|
||||
@@ -63,33 +66,34 @@
|
||||
// them is often also around 20+ms. This can result in the raw data be 2-3+
|
||||
// times larger than needed as it has captured 2-3+ messages in a single
|
||||
// capture. Setting a low timeout value can resolve this.
|
||||
// So, choosing the best TIMEOUT value for your use particular case is
|
||||
// So, choosing the best kTimeout value for your use particular case is
|
||||
// quite nuanced. Good luck and happy hunting.
|
||||
// NOTE: Don't exceed MAX_TIMEOUT_MS. Typically 130ms.
|
||||
// NOTE: Don't exceed kMaxTimeoutMs. Typically 130ms.
|
||||
#if DECODE_AC
|
||||
#define TIMEOUT 50U // Some A/C units have gaps in their protocols of ~40ms.
|
||||
// e.g. Kelvinator
|
||||
// A value this large may swallow repeats of some protocols
|
||||
#else // DECODE_AC
|
||||
#define TIMEOUT 15U // Suits most messages, while not swallowing many repeats.
|
||||
// Some A/C units have gaps in their protocols of ~40ms. e.g. Kelvinator
|
||||
// A value this large may swallow repeats of some protocols
|
||||
const uint8_t kTimeout = 50;
|
||||
#else // DECODE_AC
|
||||
// Suits most messages, while not swallowing many repeats.
|
||||
const uint8_t kTimeout = 15;
|
||||
#endif // DECODE_AC
|
||||
// Alternatives:
|
||||
// #define TIMEOUT 90U // Suits messages with big gaps like XMP-1 & some aircon
|
||||
// units, but can accidentally swallow repeated messages
|
||||
// in the rawData[] output.
|
||||
// #define TIMEOUT MAX_TIMEOUT_MS // This will set it to our currently allowed
|
||||
// maximum. Values this high are problematic
|
||||
// because it is roughly the typical boundary
|
||||
// where most messages repeat.
|
||||
// e.g. It will stop decoding a message and
|
||||
// start sending it to serial at precisely
|
||||
// the time when the next message is likely
|
||||
// to be transmitted, and may miss it.
|
||||
// const uint8_t kTimeout = 90;
|
||||
// Suits messages with big gaps like XMP-1 & some aircon units, but can
|
||||
// accidentally swallow repeated messages in the rawData[] output.
|
||||
//
|
||||
// const uint8_t kTimeout = kMaxTimeoutMs;
|
||||
// This will set it to our currently allowed maximum.
|
||||
// Values this high are problematic because it is roughly the typical boundary
|
||||
// where most messages repeat.
|
||||
// e.g. It will stop decoding a message and start sending it to serial at
|
||||
// precisely the time when the next message is likely to be transmitted,
|
||||
// and may miss it.
|
||||
|
||||
// Set the smallest sized "UNKNOWN" message packets we actually care about.
|
||||
// This value helps reduce the false-positive detection rate of IR background
|
||||
// noise as real messages. The chances of background IR noise getting detected
|
||||
// as a message increases with the length of the TIMEOUT value. (See above)
|
||||
// as a message increases with the length of the kTimeout value. (See above)
|
||||
// The downside of setting this message too large is you can miss some valid
|
||||
// short messages for protocols that this library doesn't yet decode.
|
||||
//
|
||||
@@ -98,12 +102,11 @@
|
||||
// Set lower if you are sure your setup is working, but it doesn't see messages
|
||||
// from your device. (e.g. Other IR remotes work.)
|
||||
// NOTE: Set this value very high to effectively turn off UNKNOWN detection.
|
||||
#define MIN_UNKNOWN_SIZE 12
|
||||
const uint16_t kMinUnknownSize = 12;
|
||||
// ==================== end of TUNEABLE PARAMETERS ====================
|
||||
|
||||
|
||||
// Use turn on the save buffer feature for more complete capture coverage.
|
||||
IRrecv irrecv(RECV_PIN, CAPTURE_BUFFER_SIZE, TIMEOUT, true);
|
||||
IRrecv irrecv(kRecvPin, kCaptureBufferSize, kTimeout, true);
|
||||
|
||||
decode_results results; // Somewhere to store the results
|
||||
|
||||
@@ -131,6 +134,13 @@ void dumpACInfo(decode_results *results) {
|
||||
description = ac.toString();
|
||||
}
|
||||
#endif // DECODE_KELVINATOR
|
||||
#if DECODE_MITSUBISHI_AC
|
||||
if (results->decode_type == MITSUBISHI_AC) {
|
||||
IRMitsubishiAC ac(0);
|
||||
ac.setRaw(results->state);
|
||||
description = ac.toString();
|
||||
}
|
||||
#endif // DECODE_MITSUBISHI_AC
|
||||
#if DECODE_TOSHIBA_AC
|
||||
if (results->decode_type == TOSHIBA_AC) {
|
||||
IRToshibaAC ac(0);
|
||||
@@ -166,23 +176,45 @@ void dumpACInfo(decode_results *results) {
|
||||
description = ac.toString();
|
||||
}
|
||||
#endif // DECODE_HAIER_AC_YRW02
|
||||
#if DECODE_SAMSUNG_AC
|
||||
if (results->decode_type == SAMSUNG_AC) {
|
||||
IRSamsungAc ac(0);
|
||||
ac.setRaw(results->state);
|
||||
description = ac.toString();
|
||||
}
|
||||
#endif // DECODE_SAMSUNG_AC
|
||||
#if DECODE_COOLIX
|
||||
if (results->decode_type == COOLIX) {
|
||||
IRCoolixAC ac(0);
|
||||
ac.setRaw(results->value); // Coolix uses value instead of state.
|
||||
description = ac.toString();
|
||||
}
|
||||
#endif // DECODE_COOLIX
|
||||
#if DECODE_PANASONIC_AC
|
||||
if (results->decode_type == PANASONIC_AC &&
|
||||
results->bits > kPanasonicAcShortBits) {
|
||||
IRPanasonicAc ac(0);
|
||||
ac.setRaw(results->state);
|
||||
description = ac.toString();
|
||||
}
|
||||
#endif // DECODE_PANASONIC_AC
|
||||
// If we got a human-readable description of the message, display it.
|
||||
if (description != "") Serial.println("Mesg Desc.: " + description);
|
||||
if (description != "") Serial.println("Mesg Desc.: " + description);
|
||||
}
|
||||
|
||||
// The section of code run only once at start-up.
|
||||
void setup() {
|
||||
Serial.begin(BAUD_RATE, SERIAL_8N1, SERIAL_TX_ONLY);
|
||||
Serial.begin(kBaudRate, SERIAL_8N1, SERIAL_TX_ONLY);
|
||||
while (!Serial) // Wait for the serial connection to be establised.
|
||||
delay(50);
|
||||
Serial.println();
|
||||
Serial.print("IRrecvDumpV2 is now running and waiting for IR input on Pin ");
|
||||
Serial.println(RECV_PIN);
|
||||
Serial.println(kRecvPin);
|
||||
|
||||
#if DECODE_HASH
|
||||
// Ignore messages with less than minimum on or off pulses.
|
||||
irrecv.setUnknownThreshold(MIN_UNKNOWN_SIZE);
|
||||
#endif // DECODE_HASH
|
||||
irrecv.setUnknownThreshold(kMinUnknownSize);
|
||||
#endif // DECODE_HASH
|
||||
irrecv.enableIRIn(); // Start the receiver
|
||||
}
|
||||
|
||||
@@ -195,10 +227,11 @@ void loop() {
|
||||
uint32_t now = millis();
|
||||
Serial.printf("Timestamp : %06u.%03u\n", now / 1000, now % 1000);
|
||||
if (results.overflow)
|
||||
Serial.printf("WARNING: IR code is too big for buffer (>= %d). "
|
||||
"This result shouldn't be trusted until this is resolved. "
|
||||
"Edit & increase CAPTURE_BUFFER_SIZE.\n",
|
||||
CAPTURE_BUFFER_SIZE);
|
||||
Serial.printf(
|
||||
"WARNING: IR code is too big for buffer (>= %d). "
|
||||
"This result shouldn't be trusted until this is resolved. "
|
||||
"Edit & increase kCaptureBufferSize.\n",
|
||||
kCaptureBufferSize);
|
||||
// Display the basic output of what we found.
|
||||
Serial.print(resultToHumanReadableBasic(&results));
|
||||
dumpACInfo(&results); // Display any extra A/C info if we have it.
|
||||
@@ -216,6 +249,6 @@ void loop() {
|
||||
// Output the results as source code
|
||||
Serial.println(resultToSourceCode(&results));
|
||||
Serial.println(""); // Blank line between entries
|
||||
yield(); // Feed the WDT (again)
|
||||
yield(); // Feed the WDT (again)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* Copyright 2009 Ken Shirriff, http://arcfn.com
|
||||
*
|
||||
* An IR LED circuit *MUST* be connected to the ESP8266 on a pin
|
||||
* as specified by IR_LED below.
|
||||
* as specified by kIrLed below.
|
||||
*
|
||||
* TL;DR: The IR LED needs to be driven by a transistor for a good result.
|
||||
*
|
||||
@@ -34,9 +34,9 @@
|
||||
#include <IRremoteESP8266.h>
|
||||
#include <IRsend.h>
|
||||
|
||||
#define IR_LED 4 // ESP8266 GPIO pin to use. Recommended: 4 (D2).
|
||||
const uint16_t kIrLed = 4; // ESP8266 GPIO pin to use. Recommended: 4 (D2).
|
||||
|
||||
IRsend irsend(IR_LED); // Set the GPIO to be used to sending the message.
|
||||
IRsend irsend(kIrLed); // Set the GPIO to be used to sending the message.
|
||||
|
||||
// Example of data captured by IRrecvDumpV2.ino
|
||||
uint16_t rawData[67] = {9000, 4500, 650, 550, 650, 1650, 600, 550, 650, 550,
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* Version 1.0 June, 2017
|
||||
*
|
||||
* An IR LED circuit *MUST* be connected to ESP8266 pin 4 (D2), unless you
|
||||
* change the IR_LED value below.
|
||||
* change the kIrLed value below.
|
||||
*
|
||||
* TL;DR: The IR LED needs to be driven by a transistor for a good result.
|
||||
*
|
||||
@@ -35,9 +35,9 @@
|
||||
#include <IRremoteESP8266.h>
|
||||
#include <IRsend.h>
|
||||
|
||||
#define IR_LED 4 // ESP8266 GPIO pin to use. Recommended: 4 (D2).
|
||||
const uint16_t kIrLed = 4; // ESP8266 GPIO pin to use. Recommended: 4 (D2).
|
||||
|
||||
IRsend irsend(IR_LED); // Set the GPIO to be used to sending the message.
|
||||
IRsend irsend(kIrLed); // Set the GPIO to be used to sending the message.
|
||||
|
||||
// Panasonic Plasma TV Descrete code (Power On).
|
||||
// Acquired from:
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* JVC and Panasonic protocol added by Kristian Lauszus (Thanks to zenwheel and other people at the original blog post)
|
||||
*
|
||||
* An IR LED circuit *MUST* be connected to the ESP8266 on a pin
|
||||
* as specified by IR_LED below.
|
||||
* as specified by kIrLed below.
|
||||
*
|
||||
* TL;DR: The IR LED needs to be driven by a transistor for a good result.
|
||||
*
|
||||
@@ -34,14 +34,13 @@
|
||||
#include <IRremoteESP8266.h>
|
||||
#include <IRsend.h>
|
||||
|
||||
#define PanasonicAddress 0x4004 // Panasonic address (Pre data)
|
||||
#define PanasonicPower 0x100BCBD // Panasonic Power button
|
||||
const uint16_t kPanasonicAddress = 0x4004; // Panasonic address (Pre data)
|
||||
const uint32_t kPanasonicPower = 0x100BCBD; // Panasonic Power button
|
||||
const uint16_t kJVCPower = 0xC5E8;
|
||||
|
||||
#define JVCPower 0xC5E8
|
||||
const uint16_t kIrLed = 4; // ESP8266 GPIO pin to use. Recommended: 4 (D2).
|
||||
|
||||
#define IR_LED 4 // ESP8266 GPIO pin to use. Recommended: 4 (D2).
|
||||
|
||||
IRsend irsend(IR_LED); // Set the GPIO to be used to sending the message.
|
||||
IRsend irsend(kIrLed); // Set the GPIO to be used to sending the message.
|
||||
|
||||
void setup() {
|
||||
irsend.begin();
|
||||
@@ -50,18 +49,15 @@ void setup() {
|
||||
void loop() {
|
||||
// This should turn your TV on and off
|
||||
#if SEND_PANASONIC
|
||||
irsend.sendPanasonic(PanasonicAddress, PanasonicPower);
|
||||
irsend.sendPanasonic(kPanasonicAddress, kPanasonicPower);
|
||||
#else // SEND_PANASONIC
|
||||
Serial.println("Can't send because SEND_PANASONIC has been disabled.");
|
||||
#endif // SEND_PANASONIC
|
||||
|
||||
#if SEND_JVC
|
||||
irsend.sendJVC(JVCPower, 16, 0); // hex value, 16 bits, no repeat
|
||||
// see http://www.sbprojects.com/knowledge/ir/jvc.php for information
|
||||
delayMicroseconds(50);
|
||||
irsend.sendJVC(JVCPower, 16, 1); // hex value, 16 bits, repeat
|
||||
delayMicroseconds(50);
|
||||
irsend.sendJVC(kJVCPower, 16, 1); // hex value, 16 bits, single repeat
|
||||
#else // SEND_JVC
|
||||
Serial.println("Can't send because SEND_JVC has been disabled.");
|
||||
#endif // SEND_JVC
|
||||
delay(10000); // Wait 10 seconds before we repeat everything.
|
||||
}
|
||||
|
||||
@@ -64,9 +64,9 @@ void Ac_Activate(unsigned int temperature, unsigned int air_flow,
|
||||
else
|
||||
ac_msbits4 = 0; // cooling
|
||||
unsigned int ac_msbits5 = (temperature < 15) ? 0 : temperature - 15;
|
||||
unsigned int ac_msbits6;
|
||||
unsigned int ac_msbits6 = 0;
|
||||
|
||||
if (0 <= air_flow && air_flow <= 2) {
|
||||
if (air_flow <= 2) {
|
||||
if (kAc_Type == 0)
|
||||
ac_msbits6 = kAc_Flow_Tower[air_flow];
|
||||
else
|
||||
@@ -132,7 +132,7 @@ void setup() {
|
||||
}
|
||||
|
||||
void loop() {
|
||||
char b;
|
||||
char b = ' ';
|
||||
Serial.println("# a : mode or temp b : air_flow, temp, swing, clean,"
|
||||
" cooling/heating");
|
||||
Serial.println("# 0 : off 0");
|
||||
@@ -162,7 +162,7 @@ void loop() {
|
||||
default:
|
||||
Serial.println("b="); // Prompt User for input
|
||||
while (Serial.available() == 0) {}
|
||||
char b = Serial.read();
|
||||
b = Serial.read();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -198,7 +198,7 @@ void loop() {
|
||||
Ac_Change_Air_Swing(1);
|
||||
break;
|
||||
case '3': // 1 : clean on, power on
|
||||
if (b == '0' | b == '1')
|
||||
if (b == '0' || b == '1')
|
||||
Ac_Air_Clean(b);
|
||||
break;
|
||||
case '4':
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
[platformio]
|
||||
lib_extra_dirs = ../../
|
||||
src_dir=.
|
||||
|
||||
[common]
|
||||
build_flags =
|
||||
lib_deps_builtin =
|
||||
lib_deps_external =
|
||||
|
||||
[env:nodemcuv2]
|
||||
platform = espressif8266
|
||||
framework = arduino
|
||||
board = nodemcuv2
|
||||
build_flags = ${common.build_flags}
|
||||
lib_deps =
|
||||
${common.lib_deps_builtin}
|
||||
${common.lib_deps_external}
|
||||
@@ -1,6 +1,6 @@
|
||||
/* Copyright 2017 crankyoldgit
|
||||
* An IR LED circuit *MUST* be connected to the ESP8266 on a pin
|
||||
* as specified by IR_LED below.
|
||||
* as specified by kIrLed below.
|
||||
*
|
||||
* TL;DR: The IR LED needs to be driven by a transistor for a good result.
|
||||
*
|
||||
@@ -30,8 +30,8 @@
|
||||
#include <IRsend.h>
|
||||
#include <ir_Argo.h>
|
||||
|
||||
#define IR_LED 4 // ESP8266 GPIO pin to use. Recommended: 4 (D2).
|
||||
IRArgoAC argoir(IR_LED); // Set the GPIO to be used to sending the message.
|
||||
const uint16_t kIrLed = 4; // ESP8266 GPIO pin to use. Recommended: 4 (D2).
|
||||
IRArgoAC argoir(kIrLed); // Set the GPIO to be used to sending the message.
|
||||
|
||||
void setup() {
|
||||
argoir.begin();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* Copyright 2017 sillyfrog
|
||||
*
|
||||
* An IR LED circuit *MUST* be connected to the ESP8266 on a pin
|
||||
* as specified by IR_LED below.
|
||||
* as specified by kIrLed below.
|
||||
*
|
||||
* TL;DR: The IR LED needs to be driven by a transistor for a good result.
|
||||
*
|
||||
@@ -31,8 +31,8 @@
|
||||
#include <IRsend.h>
|
||||
#include <ir_Daikin.h>
|
||||
|
||||
#define IR_LED 4 // ESP8266 GPIO pin to use. Recommended: 4 (D2).
|
||||
IRDaikinESP daikinir(IR_LED); // Set the GPIO to be used to sending the message
|
||||
const uint16_t kIrLed = 4; // ESP8266 GPIO pin to use. Recommended: 4 (D2).
|
||||
IRDaikinESP daikinir(kIrLed); // Set the GPIO to be used to sending the message
|
||||
|
||||
void setup() {
|
||||
daikinir.begin();
|
||||
@@ -46,7 +46,7 @@ void loop() {
|
||||
// Set up what we want to send. See ir_Daikin.cpp for all the options.
|
||||
daikinir.on();
|
||||
daikinir.setFan(1);
|
||||
daikinir.setMode(DAIKIN_COOL);
|
||||
daikinir.setMode(kDaikinCool);
|
||||
daikinir.setTemp(25);
|
||||
daikinir.setSwingVertical(false);
|
||||
daikinir.setSwingHorizontal(false);
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
#include <IRsend.h>
|
||||
#include <ir_Fujitsu.h>
|
||||
|
||||
IRFujitsuAC fujitsu(5); // IR led controlled by Pin D1.
|
||||
const uint16_t kIrLed = 4; // ESP8266 GPIO pin to use. Recommended: 4 (D2).
|
||||
IRFujitsuAC fujitsu(kIrLed);
|
||||
|
||||
void printState() {
|
||||
// Display the settings.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* Copyright 2016 David Conran
|
||||
*
|
||||
* An IR LED circuit *MUST* be connected to the ESP8266 on a pin
|
||||
* as specified by IR_LED below.
|
||||
* as specified by kIrLed below.
|
||||
*
|
||||
* TL;DR: The IR LED needs to be driven by a transistor for a good result.
|
||||
*
|
||||
@@ -30,8 +30,8 @@
|
||||
#include <IRsend.h>
|
||||
#include <ir_Kelvinator.h>
|
||||
|
||||
#define IR_LED 4 // ESP8266 GPIO pin to use. Recommended: 4 (D2).
|
||||
IRKelvinatorAC kelvir(IR_LED); // Set the GPIO to be used for sending messages.
|
||||
const uint16_t kIrLed = 4; // ESP8266 GPIO pin to use. Recommended: 4 (D2).
|
||||
IRKelvinatorAC kelvir(kIrLed); // Set the GPIO to be used for sending messages.
|
||||
|
||||
void printState() {
|
||||
// Display the settings.
|
||||
@@ -47,7 +47,7 @@ void printState() {
|
||||
// Display the encoded IR sequence.
|
||||
unsigned char* ir_code = kelvir.getRaw();
|
||||
Serial.print("IR Code: 0x");
|
||||
for (uint8_t i = 0; i < KELVINATOR_STATE_LENGTH; i++)
|
||||
for (uint8_t i = 0; i < kKelvinatorStateLength; i++)
|
||||
Serial.printf("%02X", ir_code[i]);
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* Copyright 2017 David Conran
|
||||
*
|
||||
* An IR LED circuit *MUST* be connected to the ESP8266 on a pin
|
||||
* as specified by IR_LED below.
|
||||
* as specified by kIrLed below.
|
||||
*
|
||||
* TL;DR: The IR LED needs to be driven by a transistor for a good result.
|
||||
*
|
||||
@@ -30,8 +30,8 @@
|
||||
#include <IRsend.h>
|
||||
#include <ir_Mitsubishi.h>
|
||||
|
||||
#define IR_LED 4 // ESP8266 GPIO pin to use. Recommended: 4 (D2).
|
||||
IRMitsubishiAC mitsubir(IR_LED); // Set the GPIO used for sending messages.
|
||||
const uint16_t kIrLed = 4; // ESP8266 GPIO pin to use. Recommended: 4 (D2).
|
||||
IRMitsubishiAC mitsubir(kIrLed); // Set the GPIO used for sending messages.
|
||||
|
||||
void printState() {
|
||||
// Display the settings.
|
||||
@@ -43,7 +43,7 @@ void printState() {
|
||||
// Display the encoded IR sequence.
|
||||
unsigned char* ir_code = mitsubir.getRaw();
|
||||
Serial.print("IR Code: 0x");
|
||||
for (uint8_t i = 0; i < MITSUBISHI_AC_STATE_LENGTH; i++)
|
||||
for (uint8_t i = 0; i < kMitsubishiACStateLength; i++)
|
||||
Serial.printf("%02X", ir_code[i]);
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* Copyright 2017 David Conran
|
||||
*
|
||||
* An IR LED circuit *MUST* be connected to the ESP8266 on a pin
|
||||
* as specified by IR_LED below.
|
||||
* as specified by kIrLed below.
|
||||
*
|
||||
* TL;DR: The IR LED needs to be driven by a transistor for a good result.
|
||||
*
|
||||
@@ -30,8 +30,8 @@
|
||||
#include <IRsend.h>
|
||||
#include <ir_Toshiba.h>
|
||||
|
||||
#define IR_LED 4 // ESP8266 GPIO pin to use. Recommended: 4 (D2).
|
||||
IRToshibaAC toshibair(IR_LED); // Set the GPIO to be used for sending messages.
|
||||
const uint16_t kIrLed = 4; // ESP8266 GPIO pin to use. Recommended: 4 (D2).
|
||||
IRToshibaAC toshibair(kIrLed); // Set the GPIO to be used for sending messages.
|
||||
|
||||
void printState() {
|
||||
// Display the settings.
|
||||
@@ -42,7 +42,7 @@ void printState() {
|
||||
// Display the encoded IR sequence.
|
||||
unsigned char* ir_code = toshibair.getRaw();
|
||||
Serial.print("IR Code: 0x");
|
||||
for (uint8_t i = 0; i < TOSHIBA_AC_STATE_LENGTH; i++)
|
||||
for (uint8_t i = 0; i < kToshibaACStateLength; i++)
|
||||
Serial.printf("%02X", ir_code[i]);
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* Copyright 2017 stufisher
|
||||
* An IR LED circuit *MUST* be connected to the ESP8266 on a pin
|
||||
* as specified by IR_LED below.
|
||||
* as specified by kIrLed below.
|
||||
*
|
||||
* TL;DR: The IR LED needs to be driven by a transistor for a good result.
|
||||
*
|
||||
@@ -30,8 +30,8 @@
|
||||
#include <IRsend.h>
|
||||
#include <ir_Trotec.h>
|
||||
|
||||
#define IR_LED 4 // ESP8266 GPIO pin to use. Recommended: 4 (D2).
|
||||
IRTrotecESP trotecir(IR_LED); // Set the GPIO to be used for sending messages.
|
||||
const uint16_t kIrLed = 4; // ESP8266 GPIO pin to use. Recommended: 4 (D2).
|
||||
IRTrotecESP trotecir(kIrLed); // Set the GPIO to be used for sending messages.
|
||||
|
||||
void setup() {
|
||||
trotecir.begin();
|
||||
|
||||
+976
-481
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "IRremoteESP8266",
|
||||
"version": "2.4.3",
|
||||
"version": "2.5.2",
|
||||
"keywords": "infrared, ir, remote, esp8266",
|
||||
"description": "Send and receive infrared signals with multiple protocols (ESP8266)",
|
||||
"repository":
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name=IRremoteESP8266
|
||||
version=2.4.3
|
||||
version=2.5.2
|
||||
author=Sebastien Warin, Mark Szabo, Ken Shirriff, David Conran
|
||||
maintainer=Mark Szabo, David Conran, Sebastien Warin, Roi Dayan, Massimiliano Pinto
|
||||
sentence=Send and receive infrared signals with multiple protocols (ESP8266)
|
||||
|
||||
+148
-146
@@ -7,13 +7,14 @@
|
||||
#include <stddef.h>
|
||||
#ifndef UNIT_TEST
|
||||
extern "C" {
|
||||
#include <gpio.h>
|
||||
#include <user_interface.h>
|
||||
#include <gpio.h>
|
||||
#include <user_interface.h>
|
||||
}
|
||||
#include <Arduino.h>
|
||||
#endif
|
||||
#include <algorithm>
|
||||
#include "IRremoteESP8266.h"
|
||||
#include "IRutils.h"
|
||||
|
||||
#ifdef UNIT_TEST
|
||||
#undef ICACHE_RAM_ATTR
|
||||
@@ -34,8 +35,7 @@ irparams_t *irparams_save; // A copy of the interrupt state while decoding.
|
||||
#ifndef UNIT_TEST
|
||||
static void ICACHE_RAM_ATTR read_timeout(void *arg __attribute__((unused))) {
|
||||
os_intr_lock();
|
||||
if (irparams.rawlen)
|
||||
irparams.rcvstate = STATE_STOP;
|
||||
if (irparams.rawlen) irparams.rcvstate = kStopState;
|
||||
os_intr_unlock();
|
||||
}
|
||||
|
||||
@@ -57,25 +57,24 @@ static void ICACHE_RAM_ATTR gpio_intr() {
|
||||
|
||||
if (rawlen >= irparams.bufsize) {
|
||||
irparams.overflow = true;
|
||||
irparams.rcvstate = STATE_STOP;
|
||||
irparams.rcvstate = kStopState;
|
||||
}
|
||||
|
||||
if (irparams.rcvstate == STATE_STOP)
|
||||
return;
|
||||
if (irparams.rcvstate == kStopState) return;
|
||||
|
||||
if (irparams.rcvstate == STATE_IDLE) {
|
||||
irparams.rcvstate = STATE_MARK;
|
||||
if (irparams.rcvstate == kIdleState) {
|
||||
irparams.rcvstate = kMarkState;
|
||||
irparams.rawbuf[rawlen] = 1;
|
||||
} else {
|
||||
if (now < start)
|
||||
irparams.rawbuf[rawlen] = (UINT32_MAX - start + now) / RAWTICK;
|
||||
irparams.rawbuf[rawlen] = (UINT32_MAX - start + now) / kRawTick;
|
||||
else
|
||||
irparams.rawbuf[rawlen] = (now - start) / RAWTICK;
|
||||
irparams.rawbuf[rawlen] = (now - start) / kRawTick;
|
||||
}
|
||||
irparams.rawlen++;
|
||||
|
||||
start = now;
|
||||
#define ONCE 0
|
||||
#define ONCE 0
|
||||
os_timer_arm(&timer, irparams.timeout, ONCE);
|
||||
}
|
||||
#endif // UNIT_TEST
|
||||
@@ -85,9 +84,9 @@ static void ICACHE_RAM_ATTR gpio_intr() {
|
||||
// Class constructor
|
||||
// Args:
|
||||
// recvpin: GPIO pin the IR receiver module's data pin is connected to.
|
||||
// bufsize: Nr. of entries to have in the capture buffer. (Default: RAWBUF)
|
||||
// bufsize: Nr. of entries to have in the capture buffer. (Default: kRawBuf)
|
||||
// timeout: Nr. of milli-Seconds of no signal before we stop capturing data.
|
||||
// (Default: TIMEOUT_MS)
|
||||
// (Default: kTimeoutMs)
|
||||
// save_buffer: Use a second (save) buffer to decode from. (Def: false)
|
||||
// Returns:
|
||||
// An IRrecv class object.
|
||||
@@ -97,11 +96,12 @@ IRrecv::IRrecv(uint16_t recvpin, uint16_t bufsize, uint8_t timeout,
|
||||
irparams.bufsize = bufsize;
|
||||
// Ensure we are going to be able to store all possible values in the
|
||||
// capture buffer.
|
||||
irparams.timeout = std::min(timeout, (uint8_t) MAX_TIMEOUT_MS);
|
||||
irparams.timeout = std::min(timeout, (uint8_t)kMaxTimeoutMs);
|
||||
irparams.rawbuf = new uint16_t[bufsize];
|
||||
if (irparams.rawbuf == NULL) {
|
||||
DPRINTLN("Could not allocate memory for the primary IR buffer.\n"
|
||||
"Try a smaller size for CAPTURE_BUFFER_SIZE.\nRebooting!");
|
||||
DPRINTLN(
|
||||
"Could not allocate memory for the primary IR buffer.\n"
|
||||
"Try a smaller size for CAPTURE_BUFFER_SIZE.\nRebooting!");
|
||||
#ifndef UNIT_TEST
|
||||
ESP.restart(); // Mem alloc failure. Reboot.
|
||||
#endif
|
||||
@@ -112,8 +112,9 @@ IRrecv::IRrecv(uint16_t recvpin, uint16_t bufsize, uint8_t timeout,
|
||||
irparams_save->rawbuf = new uint16_t[bufsize];
|
||||
// Check we allocated the memory successfully.
|
||||
if (irparams_save->rawbuf == NULL) {
|
||||
DPRINTLN("Could not allocate memory for the second IR buffer.\n"
|
||||
"Try a smaller size for CAPTURE_BUFFER_SIZE.\nRebooting!");
|
||||
DPRINTLN(
|
||||
"Could not allocate memory for the second IR buffer.\n"
|
||||
"Try a smaller size for CAPTURE_BUFFER_SIZE.\nRebooting!");
|
||||
#ifndef UNIT_TEST
|
||||
ESP.restart(); // Mem alloc failure. Reboot.
|
||||
#endif
|
||||
@@ -122,15 +123,15 @@ IRrecv::IRrecv(uint16_t recvpin, uint16_t bufsize, uint8_t timeout,
|
||||
irparams_save = NULL;
|
||||
}
|
||||
#if DECODE_HASH
|
||||
unknown_threshold = UNKNOWN_THRESHOLD;
|
||||
unknown_threshold = kUnknownThreshold;
|
||||
#endif // DECODE_HASH
|
||||
}
|
||||
|
||||
// Class destructor
|
||||
IRrecv::~IRrecv(void) {
|
||||
delete [] irparams.rawbuf;
|
||||
delete[] irparams.rawbuf;
|
||||
if (irparams_save != NULL) {
|
||||
delete [] irparams_save->rawbuf;
|
||||
delete[] irparams_save->rawbuf;
|
||||
delete irparams_save;
|
||||
}
|
||||
}
|
||||
@@ -159,7 +160,7 @@ void IRrecv::disableIRIn() {
|
||||
}
|
||||
|
||||
void IRrecv::resume() {
|
||||
irparams.rcvstate = STATE_IDLE;
|
||||
irparams.rcvstate = kIdleState;
|
||||
irparams.rawlen = 0;
|
||||
irparams.overflow = false;
|
||||
}
|
||||
@@ -167,15 +168,15 @@ void IRrecv::resume() {
|
||||
// Make a copy of the interrupt state & buffer data.
|
||||
// Needed because irparams is marked as volatile, thus memcpy() isn't allowed.
|
||||
// Only call this when you know the interrupt handlers won't modify anything.
|
||||
// i.e. In STATE_STOP.
|
||||
// i.e. In kStopState.
|
||||
//
|
||||
// Args:
|
||||
// src: Pointer to an irparams_t structure to copy from.
|
||||
// dst: Pointer to an irparams_t structure to copy to.
|
||||
void IRrecv::copyIrParams(volatile irparams_t *src, irparams_t *dst) {
|
||||
// Typecast src and dst addresses to (char *)
|
||||
char *csrc = (char *) src; // NOLINT(readability/casting)
|
||||
char *cdst = (char *) dst; // NOLINT(readability/casting)
|
||||
char *csrc = (char *)src; // NOLINT(readability/casting)
|
||||
char *cdst = (char *)dst; // NOLINT(readability/casting)
|
||||
|
||||
// Save the pointer to the destination's rawbuf so we don't lose it as
|
||||
// the for-loop/copy after this will overwrite it with src's rawbuf pointer.
|
||||
@@ -184,22 +185,18 @@ void IRrecv::copyIrParams(volatile irparams_t *src, irparams_t *dst) {
|
||||
dst_rawbuf_ptr = dst->rawbuf;
|
||||
|
||||
// Copy contents of src[] to dst[]
|
||||
for (uint16_t i = 0; i < sizeof(irparams_t); i++)
|
||||
cdst[i] = csrc[i];
|
||||
for (uint16_t i = 0; i < sizeof(irparams_t); i++) cdst[i] = csrc[i];
|
||||
|
||||
// Restore the buffer pointer
|
||||
dst->rawbuf = dst_rawbuf_ptr;
|
||||
|
||||
// Copy the rawbuf
|
||||
for (uint16_t i = 0; i < dst->bufsize; i++)
|
||||
dst->rawbuf[i] = src->rawbuf[i];
|
||||
for (uint16_t i = 0; i < dst->bufsize; i++) dst->rawbuf[i] = src->rawbuf[i];
|
||||
}
|
||||
|
||||
// Obtain the maximum number of entries possible in the capture buffer.
|
||||
// i.e. It's size.
|
||||
uint16_t IRrecv::getBufSize() {
|
||||
return irparams.bufsize;
|
||||
}
|
||||
uint16_t IRrecv::getBufSize() { return irparams.bufsize; }
|
||||
|
||||
#if DECODE_HASH
|
||||
// Set the minimum length we will consider for reporting UNKNOWN message types.
|
||||
@@ -223,8 +220,7 @@ void IRrecv::setUnknownThreshold(uint16_t length) {
|
||||
bool IRrecv::decode(decode_results *results, irparams_t *save) {
|
||||
// Proceed only if an IR message been received.
|
||||
#ifndef UNIT_TEST
|
||||
if (irparams.rcvstate != STATE_STOP)
|
||||
return false;
|
||||
if (irparams.rcvstate != kStopState) return false;
|
||||
#endif
|
||||
|
||||
// Clear the entry we are currently pointing to when we got the timeout.
|
||||
@@ -240,8 +236,7 @@ bool IRrecv::decode(decode_results *results, irparams_t *save) {
|
||||
bool resumed = false; // Flag indicating if we have resumed.
|
||||
|
||||
// If we were requested to use a save buffer previously, do so.
|
||||
if (save == NULL)
|
||||
save = irparams_save;
|
||||
if (save == NULL) save = irparams_save;
|
||||
|
||||
if (save == NULL) {
|
||||
// We haven't been asked to copy it so use the existing memory.
|
||||
@@ -273,8 +268,7 @@ bool IRrecv::decode(decode_results *results, irparams_t *save) {
|
||||
// Try decodeAiwaRCT501() before decodeSanyoLC7461() & decodeNEC()
|
||||
// because the protocols are similar. This protocol is more specific than
|
||||
// those ones, so should got before them.
|
||||
if (decodeAiwaRCT501(results))
|
||||
return true;
|
||||
if (decodeAiwaRCT501(results)) return true;
|
||||
#endif
|
||||
#if DECODE_SANYO
|
||||
DPRINTLN("Attempting Sanyo LC7461 decode");
|
||||
@@ -282,8 +276,7 @@ bool IRrecv::decode(decode_results *results, irparams_t *save) {
|
||||
// similar in timings & structure, but the Sanyo one is much longer than the
|
||||
// NEC protocol (42 vs 32 bits) so this one should be tried first to try to
|
||||
// reduce false detection as a NEC packet.
|
||||
if (decodeSanyoLC7461(results))
|
||||
return true;
|
||||
if (decodeSanyoLC7461(results)) return true;
|
||||
#endif
|
||||
#if DECODE_CARRIER_AC
|
||||
DPRINTLN("Attempting Carrier AC decode");
|
||||
@@ -291,141 +284,127 @@ bool IRrecv::decode(decode_results *results, irparams_t *save) {
|
||||
// similar in timings & structure, but the Carrier one is much longer than the
|
||||
// NEC protocol (3x32 bits vs 1x32 bits) so this one should be tried first to
|
||||
// try to reduce false detection as a NEC packet.
|
||||
if (decodeCarrierAC(results))
|
||||
return true;
|
||||
if (decodeCarrierAC(results)) return true;
|
||||
#endif
|
||||
#if DECODE_PIONEER
|
||||
DPRINTLN("Attempting Pioneer decode");
|
||||
// Try decodePioneer() before decodeNEC() because the protocols are
|
||||
// similar in timings & structure, but the Pioneer one is much longer than the
|
||||
// NEC protocol (2x32 bits vs 1x32 bits) so this one should be tried first to
|
||||
// try to reduce false detection as a NEC packet.
|
||||
if (decodePioneer(results)) return true;
|
||||
#endif
|
||||
#if DECODE_NEC
|
||||
DPRINTLN("Attempting NEC decode");
|
||||
if (decodeNEC(results))
|
||||
return true;
|
||||
if (decodeNEC(results)) return true;
|
||||
#endif
|
||||
#if DECODE_SONY
|
||||
DPRINTLN("Attempting Sony decode");
|
||||
if (decodeSony(results))
|
||||
return true;
|
||||
if (decodeSony(results)) return true;
|
||||
#endif
|
||||
#if DECODE_MITSUBISHI
|
||||
DPRINTLN("Attempting Mitsubishi decode");
|
||||
if (decodeMitsubishi(results))
|
||||
return true;
|
||||
if (decodeMitsubishi(results)) return true;
|
||||
#endif
|
||||
#if DECODE_MITSUBISHI_AC
|
||||
DPRINTLN("Attempting Mitsubishi AC decode");
|
||||
if (decodeMitsubishiAC(results)) return true;
|
||||
#endif
|
||||
#if DECODE_MITSUBISHI2
|
||||
DPRINTLN("Attempting Mitsubishi2 decode");
|
||||
if (decodeMitsubishi2(results))
|
||||
return true;
|
||||
if (decodeMitsubishi2(results)) return true;
|
||||
#endif
|
||||
#if DECODE_RC5
|
||||
DPRINTLN("Attempting RC5 decode");
|
||||
if (decodeRC5(results))
|
||||
return true;
|
||||
if (decodeRC5(results)) return true;
|
||||
#endif
|
||||
#if DECODE_RC6
|
||||
DPRINTLN("Attempting RC6 decode");
|
||||
if (decodeRC6(results))
|
||||
return true;
|
||||
if (decodeRC6(results)) return true;
|
||||
#endif
|
||||
#if DECODE_RCMM
|
||||
DPRINTLN("Attempting RC-MM decode");
|
||||
if (decodeRCMM(results))
|
||||
return true;
|
||||
if (decodeRCMM(results)) return true;
|
||||
#endif
|
||||
#if DECODE_FUJITSU_AC
|
||||
// Fujitsu A/C needs to precede Panasonic and Denon as it has a short
|
||||
// message which looks exactly the same as a Panasonic/Denon message.
|
||||
DPRINTLN("Attempting Fujitsu A/C decode");
|
||||
if (decodeFujitsuAC(results))
|
||||
return true;
|
||||
if (decodeFujitsuAC(results)) return true;
|
||||
#endif
|
||||
#if DECODE_DENON
|
||||
// Denon needs to precede Panasonic as it is a special case of Panasonic.
|
||||
DPRINTLN("Attempting Denon decode");
|
||||
if (decodeDenon(results, DENON_48_BITS) ||
|
||||
decodeDenon(results, DENON_BITS) ||
|
||||
decodeDenon(results, DENON_LEGACY_BITS))
|
||||
if (decodeDenon(results, DENON_48_BITS) || decodeDenon(results, DENON_BITS) ||
|
||||
decodeDenon(results, kDenonLegacyBits))
|
||||
return true;
|
||||
#endif
|
||||
#if DECODE_PANASONIC
|
||||
DPRINTLN("Attempting Panasonic decode");
|
||||
if (decodePanasonic(results))
|
||||
return true;
|
||||
if (decodePanasonic(results)) return true;
|
||||
#endif
|
||||
#if DECODE_LG
|
||||
DPRINTLN("Attempting LG (28-bit) decode");
|
||||
if (decodeLG(results, LG_BITS, true))
|
||||
return true;
|
||||
if (decodeLG(results, kLgBits, true)) return true;
|
||||
DPRINTLN("Attempting LG (32-bit) decode");
|
||||
// LG32 should be tried before Samsung
|
||||
if (decodeLG(results, LG32_BITS, true))
|
||||
return true;
|
||||
if (decodeLG(results, kLg32Bits, true)) return true;
|
||||
#endif
|
||||
#if DECODE_GICABLE
|
||||
// Note: Needs to happen before JVC decode, because it looks similar except
|
||||
// with a required NEC-like repeat code.
|
||||
DPRINTLN("Attempting GICable decode");
|
||||
if (decodeGICable(results))
|
||||
return true;
|
||||
if (decodeGICable(results)) return true;
|
||||
#endif
|
||||
#if DECODE_JVC
|
||||
DPRINTLN("Attempting JVC decode");
|
||||
if (decodeJVC(results))
|
||||
return true;
|
||||
if (decodeJVC(results)) return true;
|
||||
#endif
|
||||
#if DECODE_SAMSUNG
|
||||
DPRINTLN("Attempting SAMSUNG decode");
|
||||
if (decodeSAMSUNG(results))
|
||||
return true;
|
||||
if (decodeSAMSUNG(results)) return true;
|
||||
#endif
|
||||
#if DECODE_WHYNTER
|
||||
DPRINTLN("Attempting Whynter decode");
|
||||
if (decodeWhynter(results))
|
||||
return true;
|
||||
if (decodeWhynter(results)) return true;
|
||||
#endif
|
||||
#if DECODE_DISH
|
||||
DPRINTLN("Attempting DISH decode");
|
||||
if (decodeDISH(results))
|
||||
return true;
|
||||
if (decodeDISH(results)) return true;
|
||||
#endif
|
||||
#if DECODE_SHARP
|
||||
DPRINTLN("Attempting Sharp decode");
|
||||
if (decodeSharp(results))
|
||||
return true;
|
||||
if (decodeSharp(results)) return true;
|
||||
#endif
|
||||
#if DECODE_COOLIX
|
||||
DPRINTLN("Attempting Coolix decode");
|
||||
if (decodeCOOLIX(results))
|
||||
return true;
|
||||
if (decodeCOOLIX(results)) return true;
|
||||
#endif
|
||||
#if DECODE_NIKAI
|
||||
DPRINTLN("Attempting Nikai decode");
|
||||
if (decodeNikai(results))
|
||||
return true;
|
||||
if (decodeNikai(results)) return true;
|
||||
#endif
|
||||
#if DECODE_KELVINATOR
|
||||
// Kelvinator based-devices use a similar code to Gree ones, to avoid false
|
||||
// matches this needs to happen before decodeGree().
|
||||
// Kelvinator based-devices use a similar code to Gree ones, to avoid false
|
||||
// matches this needs to happen before decodeGree().
|
||||
DPRINTLN("Attempting Kelvinator decode");
|
||||
if (decodeKelvinator(results))
|
||||
return true;
|
||||
if (decodeKelvinator(results)) return true;
|
||||
#endif
|
||||
#if DECODE_DAIKIN
|
||||
DPRINTLN("Attempting Daikin decode");
|
||||
if (decodeDaikin(results))
|
||||
return true;
|
||||
if (decodeDaikin(results)) return true;
|
||||
#endif
|
||||
#if DECODE_TOSHIBA_AC
|
||||
DPRINTLN("Attempting Toshiba AC decode");
|
||||
if (decodeToshibaAC(results))
|
||||
return true;
|
||||
if (decodeToshibaAC(results)) return true;
|
||||
#endif
|
||||
#if DECODE_MIDEA
|
||||
DPRINTLN("Attempting Midea decode");
|
||||
if (decodeMidea(results))
|
||||
return true;
|
||||
if (decodeMidea(results)) return true;
|
||||
#endif
|
||||
#if DECODE_MAGIQUEST
|
||||
DPRINTLN("Attempting Magiquest decode");
|
||||
if (decodeMagiQuest(results))
|
||||
return true;
|
||||
if (decodeMagiQuest(results)) return true;
|
||||
#endif
|
||||
/* NOTE: Disabled due to poor quality.
|
||||
#if DECODE_SANYO
|
||||
@@ -444,48 +423,71 @@ bool IRrecv::decode(decode_results *results, irparams_t *save) {
|
||||
// other protocols that are NEC-like as well, as turning off strict may
|
||||
// cause this to match other valid protocols.
|
||||
DPRINTLN("Attempting NEC (non-strict) decode");
|
||||
if (decodeNEC(results, NEC_BITS, false)) {
|
||||
if (decodeNEC(results, kNECBits, false)) {
|
||||
results->decode_type = NEC_LIKE;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
#if DECODE_LASERTAG
|
||||
DPRINTLN("Attempting Lasertag decode");
|
||||
if (decodeLasertag(results))
|
||||
return true;
|
||||
if (decodeLasertag(results)) return true;
|
||||
#endif
|
||||
#if DECODE_GREE
|
||||
// Gree based-devices use a similar code to Kelvinator ones, to avoid false
|
||||
// matches this needs to happen after decodeKelvinator().
|
||||
DPRINTLN("Attempting Gree decode");
|
||||
if (decodeGree(results))
|
||||
return true;
|
||||
if (decodeGree(results)) return true;
|
||||
#endif
|
||||
#if DECODE_HAIER_AC
|
||||
DPRINTLN("Attempting Haier AC decode");
|
||||
if (decodeHaierAC(results))
|
||||
return true;
|
||||
if (decodeHaierAC(results)) return true;
|
||||
#endif
|
||||
#if DECODE_HAIER_AC_YRW02
|
||||
DPRINTLN("Attempting Haier AC YR-W02 decode");
|
||||
if (decodeHaierACYRW02(results))
|
||||
return true;
|
||||
if (decodeHaierACYRW02(results)) return true;
|
||||
#endif
|
||||
#if DECODE_HITACHI_AC2
|
||||
// HitachiAC2 should be checked before HitachiAC
|
||||
DPRINTLN("Attempting Hitachi AC2 decode");
|
||||
if (decodeHitachiAC(results, HITACHI_AC2_BITS))
|
||||
return true;
|
||||
if (decodeHitachiAC(results, kHitachiAc2Bits)) return true;
|
||||
#endif
|
||||
#if DECODE_HITACHI_AC
|
||||
DPRINTLN("Attempting Hitachi AC decode");
|
||||
if (decodeHitachiAC(results, HITACHI_AC_BITS))
|
||||
return true;
|
||||
if (decodeHitachiAC(results, kHitachiAcBits)) return true;
|
||||
#endif
|
||||
#if DECODE_HITACHI_AC1
|
||||
DPRINTLN("Attempting Hitachi AC1 decode");
|
||||
if (decodeHitachiAC(results, HITACHI_AC1_BITS))
|
||||
return true;
|
||||
if (decodeHitachiAC(results, kHitachiAc1Bits)) return true;
|
||||
#endif
|
||||
#if DECODE_WHIRLPOOL_AC
|
||||
DPRINTLN("Attempting Whirlpool AC decode");
|
||||
if (decodeWhirlpoolAC(results)) return true;
|
||||
#endif
|
||||
#if DECODE_SAMSUNG_AC
|
||||
DPRINTLN("Attempting Samsung AC (extended) decode");
|
||||
// Check the extended size first, as it should fail fast due to longer length.
|
||||
if (decodeSamsungAC(results, kSamsungAcExtendedBits, false)) return true;
|
||||
// Now check for the more common length.
|
||||
DPRINTLN("Attempting Samsung AC decode");
|
||||
if (decodeSamsungAC(results, kSamsungAcBits)) return true;
|
||||
#endif
|
||||
#if DECODE_ELECTRA_AC
|
||||
DPRINTLN("Attempting Electra AC decode");
|
||||
if (decodeElectraAC(results)) return true;
|
||||
#endif
|
||||
#if DECODE_PANASONIC_AC
|
||||
DPRINTLN("Attempting Panasonic AC decode");
|
||||
if (decodePanasonicAC(results)) return true;
|
||||
DPRINTLN("Attempting Panasonic AC short decode");
|
||||
if (decodePanasonicAC(results, kPanasonicAcShortBits)) return true;
|
||||
#endif
|
||||
#if DECODE_LUTRON
|
||||
DPRINTLN("Attempting Lutron decode");
|
||||
if (decodeLutron(results)) return true;
|
||||
#endif
|
||||
#if DECODE_MWM
|
||||
DPRINTLN("Attempting MWM decode");
|
||||
if (decodeMWM(results)) return true;
|
||||
#endif
|
||||
#if DECODE_HASH
|
||||
// decodeHash returns a hash on any input.
|
||||
@@ -511,8 +513,8 @@ bool IRrecv::decode(decode_results *results, irparams_t *save) {
|
||||
// Nr. of ticks.
|
||||
uint32_t IRrecv::ticksLow(uint32_t usecs, uint8_t tolerance, uint16_t delta) {
|
||||
// max() used to ensure the result can't drop below 0 before the cast.
|
||||
return((uint32_t) std::max(
|
||||
(int32_t) (usecs * (1.0 - tolerance / 100.0) - delta), 0));
|
||||
return ((uint32_t)std::max(
|
||||
(int32_t)(usecs * (1.0 - tolerance / 100.0) - delta), 0));
|
||||
}
|
||||
|
||||
// Calculate the upper bound of the nr. of ticks.
|
||||
@@ -524,7 +526,7 @@ uint32_t IRrecv::ticksLow(uint32_t usecs, uint8_t tolerance, uint16_t delta) {
|
||||
// Returns:
|
||||
// Nr. of ticks.
|
||||
uint32_t IRrecv::ticksHigh(uint32_t usecs, uint8_t tolerance, uint16_t delta) {
|
||||
return((uint32_t) (usecs * (1.0 + tolerance / 100.0)) + 1 + delta);
|
||||
return ((uint32_t)(usecs * (1.0 + tolerance / 100.0)) + 1 + delta);
|
||||
}
|
||||
|
||||
// Check if we match a pulse(measured) with the desired within
|
||||
@@ -538,9 +540,9 @@ uint32_t IRrecv::ticksHigh(uint32_t usecs, uint8_t tolerance, uint16_t delta) {
|
||||
//
|
||||
// Returns:
|
||||
// Boolean: true if it matches, false if it doesn't.
|
||||
bool IRrecv::match(uint32_t measured, uint32_t desired,
|
||||
uint8_t tolerance, uint16_t delta) {
|
||||
measured *= RAWTICK; // Convert to uSecs.
|
||||
bool IRrecv::match(uint32_t measured, uint32_t desired, uint8_t tolerance,
|
||||
uint16_t delta) {
|
||||
measured *= kRawTick; // Convert to uSecs.
|
||||
DPRINT("Matching: ");
|
||||
DPRINT(ticksLow(desired, tolerance, delta));
|
||||
DPRINT(" <= ");
|
||||
@@ -551,7 +553,6 @@ bool IRrecv::match(uint32_t measured, uint32_t desired,
|
||||
measured <= ticksHigh(desired, tolerance, delta));
|
||||
}
|
||||
|
||||
|
||||
// Check if we match a pulse(measured) of at least desired within
|
||||
// tolerance percent and/or a fixed delta margin.
|
||||
//
|
||||
@@ -566,7 +567,7 @@ bool IRrecv::match(uint32_t measured, uint32_t desired,
|
||||
// Boolean: true if it matches, false if it doesn't.
|
||||
bool IRrecv::matchAtLeast(uint32_t measured, uint32_t desired,
|
||||
uint8_t tolerance, uint16_t delta) {
|
||||
measured *= RAWTICK; // Convert to uSecs.
|
||||
measured *= kRawTick; // Convert to uSecs.
|
||||
DPRINT("Matching ATLEAST ");
|
||||
DPRINT(measured);
|
||||
DPRINT(" vs ");
|
||||
@@ -599,10 +600,10 @@ bool IRrecv::matchAtLeast(uint32_t measured, uint32_t desired,
|
||||
//
|
||||
// Returns:
|
||||
// Boolean: true if it matches, false if it doesn't.
|
||||
bool IRrecv::matchMark(uint32_t measured, uint32_t desired,
|
||||
uint8_t tolerance, int16_t excess) {
|
||||
bool IRrecv::matchMark(uint32_t measured, uint32_t desired, uint8_t tolerance,
|
||||
int16_t excess) {
|
||||
DPRINT("Matching MARK ");
|
||||
DPRINT(measured * RAWTICK);
|
||||
DPRINT(measured * kRawTick);
|
||||
DPRINT(" vs ");
|
||||
DPRINT(desired);
|
||||
DPRINT(" + ");
|
||||
@@ -622,10 +623,10 @@ bool IRrecv::matchMark(uint32_t measured, uint32_t desired,
|
||||
//
|
||||
// Returns:
|
||||
// Boolean: true if it matches, false if it doesn't.
|
||||
bool IRrecv::matchSpace(uint32_t measured, uint32_t desired,
|
||||
uint8_t tolerance, int16_t excess) {
|
||||
bool IRrecv::matchSpace(uint32_t measured, uint32_t desired, uint8_t tolerance,
|
||||
int16_t excess) {
|
||||
DPRINT("Matching SPACE ");
|
||||
DPRINT(measured * RAWTICK);
|
||||
DPRINT(measured * kRawTick);
|
||||
DPRINT(" vs ");
|
||||
DPRINT(desired);
|
||||
DPRINT(" - ");
|
||||
@@ -667,9 +668,8 @@ int16_t IRrecv::compare(uint16_t oldval, uint16_t newval) {
|
||||
*/
|
||||
bool IRrecv::decodeHash(decode_results *results) {
|
||||
// Require at least some samples to prevent triggering on noise
|
||||
if (results->rawlen < unknown_threshold)
|
||||
return false;
|
||||
int32_t hash = FNV_BASIS_32;
|
||||
if (results->rawlen < unknown_threshold) return false;
|
||||
int32_t hash = kFnvBasis32;
|
||||
// 'rawlen - 2' to avoid the look ahead from going out of bounds.
|
||||
// Should probably be -3 to avoid comparing the trailing space entry,
|
||||
// however it is left this way for compatibility with previously captured
|
||||
@@ -677,7 +677,7 @@ bool IRrecv::decodeHash(decode_results *results) {
|
||||
for (uint16_t i = 1; i < results->rawlen - 2; i++) {
|
||||
int16_t value = compare(results->rawbuf[i], results->rawbuf[i + 2]);
|
||||
// Add value into the hash
|
||||
hash = (hash * FNV_PRIME_32) ^ value;
|
||||
hash = (hash * kFnvPrime32) ^ value;
|
||||
}
|
||||
results->value = hash & 0xFFFFFFFF;
|
||||
results->bits = results->rawlen / 2;
|
||||
@@ -689,7 +689,8 @@ bool IRrecv::decodeHash(decode_results *results) {
|
||||
#endif // DECODE_HASH
|
||||
|
||||
// Match & decode the typical data section of an IR message.
|
||||
// The data value constructed as the Most Significant Bit first.
|
||||
// The data value is stored in the least significant bits reguardless of the
|
||||
// bit ordering requested.
|
||||
//
|
||||
// Args:
|
||||
// data_ptr: A pointer to where we are at in the capture buffer.
|
||||
@@ -698,34 +699,35 @@ bool IRrecv::decodeHash(decode_results *results) {
|
||||
// onespace: Nr. of uSeconds in an expected space signal for a '1' bit.
|
||||
// zeromark: Nr. of uSeconds in an expected mark signal for a '0' bit.
|
||||
// zerospace: Nr. of uSeconds in an expected space signal for a '0' bit.
|
||||
// tolerance: Percentage error margin to allow.
|
||||
// tolerance: Percentage error margin to allow. (Def: kTolerance)
|
||||
// excess: Nr. of useconds. (Def: kMarkExcess)
|
||||
// MSBfirst: Bit order to save the data in. (Def: true)
|
||||
// Returns:
|
||||
// A match_result_t structure containing the success (or not), the data value,
|
||||
// and how many buffer entries were used.
|
||||
match_result_t IRrecv::matchData(volatile uint16_t *data_ptr,
|
||||
const uint16_t nbits, const uint16_t onemark,
|
||||
const uint32_t onespace,
|
||||
const uint16_t zeromark,
|
||||
const uint32_t zerospace,
|
||||
const uint8_t tolerance) {
|
||||
match_result_t IRrecv::matchData(
|
||||
volatile uint16_t *data_ptr, const uint16_t nbits, const uint16_t onemark,
|
||||
const uint32_t onespace, const uint16_t zeromark, const uint32_t zerospace,
|
||||
const uint8_t tolerance, const int16_t excess, const bool MSBfirst) {
|
||||
match_result_t result;
|
||||
result.success = false; // Fail by default.
|
||||
result.data = 0;
|
||||
for (result.used = 0;
|
||||
result.used < nbits * 2;
|
||||
for (result.used = 0; result.used < nbits * 2;
|
||||
result.used += 2, data_ptr += 2) {
|
||||
// Is the bit a '1'?
|
||||
if (matchMark(*data_ptr, onemark, tolerance) &&
|
||||
matchSpace(*(data_ptr + 1), onespace, tolerance))
|
||||
if (matchMark(*data_ptr, onemark, tolerance, excess) &&
|
||||
matchSpace(*(data_ptr + 1), onespace, tolerance, excess)) {
|
||||
result.data = (result.data << 1) | 1;
|
||||
// or is the bit a '0'?
|
||||
else if (matchMark(*data_ptr, zeromark, tolerance) &&
|
||||
matchSpace(*(data_ptr + 1), zerospace, tolerance))
|
||||
result.data <<= 1;
|
||||
else
|
||||
} else if (matchMark(*data_ptr, zeromark, tolerance, excess) &&
|
||||
matchSpace(*(data_ptr + 1), zerospace, tolerance, excess)) {
|
||||
result.data <<= 1; // The bit is a '0'.
|
||||
} else {
|
||||
if (!MSBfirst) result.data = reverseBits(result.data, result.used / 2);
|
||||
return result; // It's neither, so fail.
|
||||
}
|
||||
}
|
||||
result.success = true;
|
||||
if (!MSBfirst) result.data = reverseBits(result.data, nbits);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,59 +15,68 @@
|
||||
#include "IRremoteESP8266.h"
|
||||
|
||||
// Constants
|
||||
#define HEADER 2U // Usual nr. of header entries.
|
||||
#define FOOTER 2U // Usual nr. of footer (stop bits) entries.
|
||||
#define OFFSET_START 1U // Usual rawbuf entry to start processing from.
|
||||
#define MS_TO_USEC(x) (x * 1000U) // Convert milli-Seconds to micro-Seconds.
|
||||
const uint16_t kHeader = 2; // Usual nr. of header entries.
|
||||
const uint16_t kFooter = 2; // Usual nr. of footer (stop bits) entries.
|
||||
const uint16_t kStartOffset = 1; // Usual rawbuf entry to start from.
|
||||
#define MS_TO_USEC(x) (x * 1000U) // Convert milli-Seconds to micro-Seconds.
|
||||
// Marks tend to be 100us too long, and spaces 100us too short
|
||||
// when received due to sensor lag.
|
||||
#define MARK_EXCESS 50U
|
||||
#define RAWBUF 100U // Default length of raw capture buffer
|
||||
#define REPEAT UINT64_MAX
|
||||
#define UNKNOWN_THRESHOLD 6U // Default min size of reported UNKNOWN messages.
|
||||
const uint16_t kMarkExcess = 50;
|
||||
const uint16_t kRawBuf = 100; // Default length of raw capture buffer
|
||||
const uint64_t kRepeat = UINT64_MAX;
|
||||
// Default min size of reported UNKNOWN messages.
|
||||
const uint16_t kUnknownThreshold = 6;
|
||||
|
||||
// receiver states
|
||||
#define STATE_IDLE 2U
|
||||
#define STATE_MARK 3U
|
||||
#define STATE_SPACE 4U
|
||||
#define STATE_STOP 5U
|
||||
#define TOLERANCE 25U // default percent tolerance in measurements
|
||||
#define RAWTICK 2U // Capture tick to uSec factor.
|
||||
const uint8_t kIdleState = 2;
|
||||
const uint8_t kMarkState = 3;
|
||||
const uint8_t kSpaceState = 4;
|
||||
const uint8_t kStopState = 5;
|
||||
const uint8_t kTolerance = 25; // default percent tolerance in measurements.
|
||||
const uint16_t kRawTick = 2; // Capture tick to uSec factor.
|
||||
#define RAWTICK kRawTick // Deprecated. For legacy user code support only.
|
||||
// How long (ms) before we give up wait for more data?
|
||||
// Don't exceed MAX_TIMEOUT_MS without a good reason.
|
||||
// That is the capture buffers maximum value size. (UINT16_MAX / RAWTICK)
|
||||
// Don't exceed kMaxTimeoutMs without a good reason.
|
||||
// That is the capture buffers maximum value size. (UINT16_MAX / kRawTick)
|
||||
// Typically messages/protocols tend to repeat around the 100ms timeframe,
|
||||
// thus we should timeout before that to give us some time to try to decode
|
||||
// before we need to start capturing a possible new message.
|
||||
// Typically 15ms suits most applications. However, some protocols demand a
|
||||
// higher value. e.g. 90ms for XMP-1 and some aircon units.
|
||||
#define TIMEOUT_MS 15U // In MilliSeconds.
|
||||
#define MAX_TIMEOUT_MS (RAWTICK * UINT16_MAX / MS_TO_USEC(1))
|
||||
const uint8_t kTimeoutMs = 15; // In MilliSeconds.
|
||||
#define TIMEOUT_MS kTimeoutMs // For legacy documentation.
|
||||
const uint16_t kMaxTimeoutMs = kRawTick * (UINT16_MAX / MS_TO_USEC(1));
|
||||
|
||||
// Use FNV hash algorithm: http://isthe.com/chongo/tech/comp/fnv/#FNV-param
|
||||
#define FNV_PRIME_32 16777619UL
|
||||
#define FNV_BASIS_32 2166136261UL
|
||||
const uint32_t kFnvPrime32 = 16777619UL;
|
||||
const uint32_t kFnvBasis32 = 2166136261UL;
|
||||
|
||||
#if DECODE_AC
|
||||
// Hitachi AC is the current largest state size.
|
||||
#define STATE_SIZE_MAX HITACHI_AC2_STATE_LENGTH
|
||||
const uint16_t kStateSizeMax = kHitachiAc2StateLength;
|
||||
#else
|
||||
// Just define something
|
||||
const uint16_t kStateSizeMax = 0;
|
||||
#endif
|
||||
|
||||
// Types
|
||||
// information for the interrupt handler
|
||||
typedef struct {
|
||||
uint8_t recvpin; // pin for IR data from detector
|
||||
uint8_t rcvstate; // state machine
|
||||
uint16_t timer; // state timer, counts 50uS ticks.
|
||||
uint16_t bufsize; // max. nr. of entries in the capture buffer.
|
||||
uint16_t *rawbuf; // raw data
|
||||
uint8_t recvpin; // pin for IR data from detector
|
||||
uint8_t rcvstate; // state machine
|
||||
uint16_t timer; // state timer, counts 50uS ticks.
|
||||
uint16_t bufsize; // max. nr. of entries in the capture buffer.
|
||||
uint16_t *rawbuf; // raw data
|
||||
// uint16_t is used for rawlen as it saves 3 bytes of iram in the interrupt
|
||||
// handler. Don't ask why, I don't know. It just does.
|
||||
uint16_t rawlen; // counter of entries in rawbuf.
|
||||
uint8_t overflow; // Buffer overflow indicator.
|
||||
uint8_t timeout; // Nr. of milliSeconds before we give up.
|
||||
uint16_t rawlen; // counter of entries in rawbuf.
|
||||
uint8_t overflow; // Buffer overflow indicator.
|
||||
uint8_t timeout; // Nr. of milliSeconds before we give up.
|
||||
} irparams_t;
|
||||
|
||||
// results from a data match
|
||||
typedef struct {
|
||||
bool success; // Was the match successful?
|
||||
bool success; // Was the match successful?
|
||||
uint64_t data; // The data found.
|
||||
uint16_t used; // How many buffer positions were used.
|
||||
} match_result_t;
|
||||
@@ -83,17 +92,15 @@ class decode_results {
|
||||
// structure to save us a handful of valuable bytes of memory.
|
||||
union {
|
||||
struct {
|
||||
uint64_t value; // Decoded value
|
||||
uint64_t value; // Decoded value
|
||||
uint32_t address; // Decoded device address.
|
||||
uint32_t command; // Decoded command.
|
||||
};
|
||||
#if DECODE_AC // Only include state if we must. It's big.
|
||||
uint8_t state[STATE_SIZE_MAX]; // Complex multi-byte A/C result.
|
||||
#endif
|
||||
uint8_t state[kStateSizeMax]; // Multi-byte results.
|
||||
};
|
||||
uint16_t bits; // Number of bits in decoded value
|
||||
uint16_t bits; // Number of bits in decoded value
|
||||
volatile uint16_t *rawbuf; // Raw intervals in .5 us ticks
|
||||
uint16_t rawlen; // Number of records in rawbuf.
|
||||
uint16_t rawlen; // Number of records in rawbuf.
|
||||
bool overflow;
|
||||
bool repeat; // Is the result a repeat code?
|
||||
};
|
||||
@@ -101,10 +108,10 @@ class decode_results {
|
||||
// main class for receiving IR
|
||||
class IRrecv {
|
||||
public:
|
||||
explicit IRrecv(uint16_t recvpin, uint16_t bufsize = RAWBUF,
|
||||
uint8_t timeout = TIMEOUT_MS,
|
||||
explicit IRrecv(uint16_t recvpin, uint16_t bufsize = kRawBuf,
|
||||
uint8_t timeout = kTimeoutMs,
|
||||
bool save_buffer = false); // Constructor
|
||||
~IRrecv(); // Destructor
|
||||
~IRrecv(); // Destructor
|
||||
bool decode(decode_results *results, irparams_t *save = NULL);
|
||||
void enableIRIn();
|
||||
void disableIRIn();
|
||||
@@ -114,13 +121,13 @@ class IRrecv {
|
||||
void setUnknownThreshold(uint16_t length);
|
||||
#endif
|
||||
static bool match(uint32_t measured, uint32_t desired,
|
||||
uint8_t tolerance = TOLERANCE, uint16_t delta = 0);
|
||||
uint8_t tolerance = kTolerance, uint16_t delta = 0);
|
||||
static bool matchMark(uint32_t measured, uint32_t desired,
|
||||
uint8_t tolerance = TOLERANCE,
|
||||
int16_t excess = MARK_EXCESS);
|
||||
uint8_t tolerance = kTolerance,
|
||||
int16_t excess = kMarkExcess);
|
||||
static bool matchSpace(uint32_t measured, uint32_t desired,
|
||||
uint8_t tolerance = TOLERANCE,
|
||||
int16_t excess = MARK_EXCESS);
|
||||
uint8_t tolerance = kTolerance,
|
||||
int16_t excess = kMarkExcess);
|
||||
#ifndef UNIT_TEST
|
||||
|
||||
private:
|
||||
@@ -132,84 +139,93 @@ class IRrecv {
|
||||
// These are called by decode
|
||||
void copyIrParams(volatile irparams_t *src, irparams_t *dst);
|
||||
int16_t compare(uint16_t oldval, uint16_t newval);
|
||||
static uint32_t ticksLow(uint32_t usecs, uint8_t tolerance = TOLERANCE,
|
||||
uint16_t delta = 0);
|
||||
static uint32_t ticksHigh(uint32_t usecs, uint8_t tolerance = TOLERANCE,
|
||||
static uint32_t ticksLow(uint32_t usecs, uint8_t tolerance = kTolerance,
|
||||
uint16_t delta = 0);
|
||||
static uint32_t ticksHigh(uint32_t usecs, uint8_t tolerance = kTolerance,
|
||||
uint16_t delta = 0);
|
||||
bool matchAtLeast(uint32_t measured, uint32_t desired,
|
||||
uint8_t tolerance = TOLERANCE, uint16_t delta = 0);
|
||||
uint8_t tolerance = kTolerance, uint16_t delta = 0);
|
||||
match_result_t matchData(volatile uint16_t *data_ptr, const uint16_t nbits,
|
||||
const uint16_t onemark, const uint32_t onespace,
|
||||
const uint16_t zeromark, const uint32_t zerospace,
|
||||
const uint8_t tolerance = TOLERANCE);
|
||||
const uint8_t tolerance = kTolerance,
|
||||
const int16_t excess = kMarkExcess,
|
||||
const bool MSBfirst = true);
|
||||
bool decodeHash(decode_results *results);
|
||||
#if (DECODE_NEC || DECODE_SHERWOOD || DECODE_AIWA_RC_T501 || SEND_SANYO)
|
||||
bool decodeNEC(decode_results *results, uint16_t nbits = NEC_BITS,
|
||||
bool decodeNEC(decode_results *results, uint16_t nbits = kNECBits,
|
||||
bool strict = true);
|
||||
#endif
|
||||
#if DECODE_SONY
|
||||
bool decodeSony(decode_results *results, uint16_t nbits = SONY_MIN_BITS,
|
||||
bool decodeSony(decode_results *results, uint16_t nbits = kSonyMinBits,
|
||||
bool strict = false);
|
||||
#endif
|
||||
#if DECODE_SANYO
|
||||
// DISABLED due to poor quality.
|
||||
// bool decodeSanyo(decode_results *results,
|
||||
// uint16_t nbits = SANYO_SA8650B_BITS,
|
||||
// uint16_t nbits = kSanyoSA8650BBits,
|
||||
// bool strict = false);
|
||||
bool decodeSanyoLC7461(decode_results *results,
|
||||
uint16_t nbits = SANYO_LC7461_BITS,
|
||||
bool strict = true);
|
||||
uint16_t nbits = kSanyoLC7461Bits, bool strict = true);
|
||||
#endif
|
||||
#if DECODE_MITSUBISHI
|
||||
bool decodeMitsubishi(decode_results *results,
|
||||
uint16_t nbits = MITSUBISHI_BITS,
|
||||
bool strict = true);
|
||||
uint16_t nbits = kMitsubishiBits, bool strict = true);
|
||||
#endif
|
||||
#if DECODE_MITSUBISHI2
|
||||
bool decodeMitsubishi2(decode_results *results,
|
||||
uint16_t nbits = MITSUBISHI_BITS,
|
||||
bool strict = true);
|
||||
uint16_t nbits = kMitsubishiBits, bool strict = true);
|
||||
#endif
|
||||
#if (DECODE_RC5 || DECODE_R6 || DECODE_LASERTAG)
|
||||
#if DECODE_MITSUBISHI_AC
|
||||
bool decodeMitsubishiAC(decode_results *results,
|
||||
uint16_t nbits = kMitsubishiACBits,
|
||||
bool strict = false);
|
||||
#endif
|
||||
#if (DECODE_RC5 || DECODE_R6 || DECODE_LASERTAG || DECODE_MWM)
|
||||
int16_t getRClevel(decode_results *results, uint16_t *offset, uint16_t *used,
|
||||
uint16_t bitTime, uint8_t tolerance = TOLERANCE,
|
||||
int16_t excess = MARK_EXCESS, uint16_t delta = 0);
|
||||
uint16_t bitTime, uint8_t tolerance = kTolerance,
|
||||
int16_t excess = kMarkExcess, uint16_t delta = 0,
|
||||
uint8_t maxwidth = 3);
|
||||
#endif
|
||||
#if DECODE_RC5
|
||||
bool decodeRC5(decode_results *results, uint16_t nbits = RC5X_BITS,
|
||||
bool decodeRC5(decode_results *results, uint16_t nbits = kRC5XBits,
|
||||
bool strict = true);
|
||||
#endif
|
||||
#if DECODE_RC6
|
||||
bool decodeRC6(decode_results *results, uint16_t nbits = RC6_MODE0_BITS,
|
||||
bool decodeRC6(decode_results *results, uint16_t nbits = kRC6Mode0Bits,
|
||||
bool strict = false);
|
||||
#endif
|
||||
#if DECODE_RCMM
|
||||
bool decodeRCMM(decode_results *results, uint16_t nbits = RCMM_BITS,
|
||||
bool decodeRCMM(decode_results *results, uint16_t nbits = kRCMMBits,
|
||||
bool strict = false);
|
||||
#endif
|
||||
#if (DECODE_PANASONIC || DECODE_DENON)
|
||||
bool decodePanasonic(decode_results *results, uint16_t nbits = PANASONIC_BITS,
|
||||
bool decodePanasonic(decode_results *results, uint16_t nbits = kPanasonicBits,
|
||||
bool strict = false,
|
||||
uint32_t manufacturer = PANASONIC_MANUFACTURER);
|
||||
uint32_t manufacturer = kPanasonicManufacturer);
|
||||
#endif
|
||||
#if DECODE_LG
|
||||
bool decodeLG(decode_results *results, uint16_t nbits = LG_BITS,
|
||||
bool decodeLG(decode_results *results, uint16_t nbits = kLgBits,
|
||||
bool strict = false);
|
||||
#endif
|
||||
#if DECODE_JVC
|
||||
bool decodeJVC(decode_results *results, uint16_t nbits = JVC_BITS,
|
||||
bool decodeJVC(decode_results *results, uint16_t nbits = kJvcBits,
|
||||
bool strict = true);
|
||||
#endif
|
||||
#if DECODE_SAMSUNG
|
||||
bool decodeSAMSUNG(decode_results *results, uint16_t nbits = SAMSUNG_BITS,
|
||||
bool decodeSAMSUNG(decode_results *results, uint16_t nbits = kSamsungBits,
|
||||
bool strict = true);
|
||||
#endif
|
||||
#if DECODE_SAMSUNG_AC
|
||||
bool decodeSamsungAC(decode_results *results, uint16_t nbits = kSamsungAcBits,
|
||||
bool strict = true);
|
||||
#endif
|
||||
#if DECODE_WHYNTER
|
||||
bool decodeWhynter(decode_results *results, uint16_t nbits = WHYNTER_BITS,
|
||||
bool decodeWhynter(decode_results *results, uint16_t nbits = kWhynterBits,
|
||||
bool strict = true);
|
||||
#endif
|
||||
#if DECODE_COOLIX
|
||||
bool decodeCOOLIX(decode_results *results, uint16_t nbits = COOLIX_BITS,
|
||||
bool decodeCOOLIX(decode_results *results, uint16_t nbits = kCoolixBits,
|
||||
bool strict = true);
|
||||
#endif
|
||||
#if DECODE_DENON
|
||||
@@ -217,82 +233,103 @@ class IRrecv {
|
||||
bool strict = true);
|
||||
#endif
|
||||
#if DECODE_DISH
|
||||
bool decodeDISH(decode_results *results, uint16_t nbits = DISH_BITS,
|
||||
bool decodeDISH(decode_results *results, uint16_t nbits = kDishBits,
|
||||
bool strict = true);
|
||||
#endif
|
||||
#if (DECODE_SHARP || DECODE_DENON)
|
||||
bool decodeSharp(decode_results *results, uint16_t nbits = SHARP_BITS,
|
||||
bool decodeSharp(decode_results *results, uint16_t nbits = kSharpBits,
|
||||
bool strict = true, bool expansion = true);
|
||||
#endif
|
||||
#if DECODE_AIWA_RC_T501
|
||||
bool decodeAiwaRCT501(decode_results *results,
|
||||
uint16_t nbits = AIWA_RC_T501_BITS, bool strict = true);
|
||||
uint16_t nbits = kAiwaRcT501Bits, bool strict = true);
|
||||
#endif
|
||||
#if DECODE_NIKAI
|
||||
bool decodeNikai(decode_results *results, uint16_t nbits = NIKAI_BITS,
|
||||
bool decodeNikai(decode_results *results, uint16_t nbits = kNikaiBits,
|
||||
bool strict = true);
|
||||
#endif
|
||||
#if DECODE_MAGIQUEST
|
||||
bool decodeMagiQuest(decode_results *results, uint16_t nbits = MAGIQUEST_BITS,
|
||||
bool decodeMagiQuest(decode_results *results, uint16_t nbits = kMagiquestBits,
|
||||
bool strict = true);
|
||||
#endif
|
||||
#if DECODE_KELVINATOR
|
||||
bool decodeKelvinator(decode_results *results,
|
||||
uint16_t nbits = KELVINATOR_BITS,
|
||||
bool strict = true);
|
||||
uint16_t nbits = kKelvinatorBits, bool strict = true);
|
||||
#endif
|
||||
#if DECODE_DAIKIN
|
||||
bool decodeDaikin(decode_results *results, uint16_t nbits = DAIKIN_RAW_BITS,
|
||||
bool decodeDaikin(decode_results *results, uint16_t nbits = kDaikinRawBits,
|
||||
bool strict = true);
|
||||
#endif
|
||||
#if DECODE_TOSHIBA_AC
|
||||
bool decodeToshibaAC(decode_results *results,
|
||||
uint16_t nbytes = TOSHIBA_AC_BITS,
|
||||
bool strict = true);
|
||||
uint16_t nbytes = kToshibaACBits, bool strict = true);
|
||||
#endif
|
||||
#if DECODE_MIDEA
|
||||
bool decodeMidea(decode_results *results, uint16_t nbits = MIDEA_BITS,
|
||||
bool decodeMidea(decode_results *results, uint16_t nbits = kMideaBits,
|
||||
bool strict = true);
|
||||
#endif
|
||||
#if DECODE_FUJITSU_AC
|
||||
bool decodeFujitsuAC(decode_results *results,
|
||||
uint16_t nbits = FUJITSU_AC_BITS,
|
||||
bool decodeFujitsuAC(decode_results *results, uint16_t nbits = kFujitsuAcBits,
|
||||
bool strict = false);
|
||||
#endif
|
||||
#if DECODE_LASERTAG
|
||||
bool decodeLasertag(decode_results *results, uint16_t nbits = LASERTAG_BITS,
|
||||
bool decodeLasertag(decode_results *results, uint16_t nbits = kLasertagBits,
|
||||
bool strict = true);
|
||||
#endif
|
||||
#if DECODE_CARRIER_AC
|
||||
bool decodeCarrierAC(decode_results *results,
|
||||
uint16_t nbits = CARRIER_AC_BITS,
|
||||
bool decodeCarrierAC(decode_results *results, uint16_t nbits = kCarrierAcBits,
|
||||
bool strict = true);
|
||||
#endif
|
||||
#if DECODE_GREE
|
||||
bool decodeGree(decode_results *results,
|
||||
uint16_t nbits = GREE_BITS, bool strict = true);
|
||||
bool decodeGree(decode_results *results, uint16_t nbits = kGreeBits,
|
||||
bool strict = true);
|
||||
#endif
|
||||
#if (DECODE_HAIER_AC | DECODE_HAIER_AC_YRW02)
|
||||
bool decodeHaierAC(decode_results *results,
|
||||
uint16_t nbits = HAIER_AC_BITS, bool strict = true);
|
||||
bool decodeHaierAC(decode_results *results, uint16_t nbits = kHaierACBits,
|
||||
bool strict = true);
|
||||
#endif
|
||||
#if DECODE_HAIER_AC_YRW02
|
||||
bool decodeHaierACYRW02(decode_results *results,
|
||||
uint16_t nbits = HAIER_AC_YRW02_BITS,
|
||||
uint16_t nbits = kHaierACYRW02Bits,
|
||||
bool strict = true);
|
||||
#endif
|
||||
#if (DECODE_HITACHI_AC || DECODE_HITACHI_AC2)
|
||||
bool decodeHitachiAC(decode_results *results,
|
||||
uint16_t nbits = HITACHI_AC_BITS, bool strict = true);
|
||||
bool decodeHitachiAC(decode_results *results, uint16_t nbits = kHitachiAcBits,
|
||||
bool strict = true);
|
||||
#endif
|
||||
#if DECODE_HITACHI_AC1
|
||||
bool decodeHitachiAC1(decode_results *results,
|
||||
uint16_t nbits = HITACHI_AC1_BITS, bool strict = true);
|
||||
uint16_t nbits = kHitachiAc1Bits, bool strict = true);
|
||||
#endif
|
||||
#if DECODE_GICABLE
|
||||
bool decodeGICable(decode_results *results, uint16_t nbits = GICABLE_BITS,
|
||||
bool decodeGICable(decode_results *results, uint16_t nbits = kGicableBits,
|
||||
bool strict = true);
|
||||
#endif
|
||||
#if DECODE_WHIRLPOOL_AC
|
||||
bool decodeWhirlpoolAC(decode_results *results,
|
||||
uint16_t nbits = kWhirlpoolAcBits, bool strict = true);
|
||||
#endif
|
||||
#if DECODE_LUTRON
|
||||
bool decodeLutron(decode_results *results, uint16_t nbits = kLutronBits,
|
||||
bool strict = true);
|
||||
#endif
|
||||
#if DECODE_ELECTRA_AC
|
||||
bool decodeElectraAC(decode_results *results, uint16_t nbits = kElectraAcBits,
|
||||
bool strict = true);
|
||||
#endif
|
||||
#if DECODE_PANASONIC_AC
|
||||
bool decodePanasonicAC(decode_results *results,
|
||||
uint16_t nbits = kPanasonicAcBits, bool strict = true);
|
||||
#endif
|
||||
#if DECODE_PIONEER
|
||||
bool decodePioneer(decode_results *results,
|
||||
const uint16_t nbits = kPioneerBits,
|
||||
const bool strict = true);
|
||||
#endif
|
||||
#if DECODE_MWM
|
||||
bool decodeMWM(decode_results *results, uint16_t nbits = 24,
|
||||
bool strict = true);
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // IRRECV_H_
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
#endif
|
||||
|
||||
// Library Version
|
||||
#define _IRREMOTEESP8266_VERSION_ "2.4.3"
|
||||
#define _IRREMOTEESP8266_VERSION_ "2.5.2"
|
||||
// Supported IR protocols
|
||||
// Each protocol you include costs memory and, during decode, costs time
|
||||
// Disable (set to false) all the protocols you do not need/want!
|
||||
@@ -85,6 +85,9 @@
|
||||
#define DECODE_SAMSUNG true
|
||||
#define SEND_SAMSUNG true
|
||||
|
||||
#define DECODE_SAMSUNG_AC true
|
||||
#define SEND_SAMSUNG_AC true
|
||||
|
||||
#define DECODE_WHYNTER true
|
||||
#define SEND_WHYNTER true
|
||||
|
||||
@@ -115,7 +118,7 @@
|
||||
#define DECODE_KELVINATOR true
|
||||
#define SEND_KELVINATOR true
|
||||
|
||||
#define DECODE_MITSUBISHI_AC false // Not written.
|
||||
#define DECODE_MITSUBISHI_AC true // Beta.
|
||||
#define SEND_MITSUBISHI_AC true
|
||||
|
||||
#define DECODE_FUJITSU_AC true
|
||||
@@ -178,10 +181,30 @@
|
||||
#define DECODE_HAIER_AC_YRW02 true
|
||||
#define SEND_HAIER_AC_YRW02 true
|
||||
|
||||
#define DECODE_WHIRLPOOL_AC true
|
||||
#define SEND_WHIRLPOOL_AC true
|
||||
|
||||
#define DECODE_LUTRON true
|
||||
#define SEND_LUTRON true
|
||||
|
||||
#define DECODE_ELECTRA_AC true
|
||||
#define SEND_ELECTRA_AC true
|
||||
|
||||
#define DECODE_PANASONIC_AC true
|
||||
#define SEND_PANASONIC_AC true
|
||||
|
||||
#define DECODE_MWM true
|
||||
#define SEND_MWM true
|
||||
|
||||
#define DECODE_PIONEER true
|
||||
#define SEND_PIONEER true
|
||||
|
||||
#if (DECODE_ARGO || DECODE_DAIKIN || DECODE_FUJITSU_AC || DECODE_GREE || \
|
||||
DECODE_KELVINATOR || DECODE_MITSUBISHI_AC || DECODE_TOSHIBA_AC || \
|
||||
DECODE_TROTEC || DECODE_HAIER_AC || DECODE_HITACHI_AC || \
|
||||
DECODE_HITACHI_AC1 || DECODE_HITACHI_AC2 || DECODE_HAIER_AC_YRW02)
|
||||
DECODE_HITACHI_AC1 || DECODE_HITACHI_AC2 || DECODE_HAIER_AC_YRW02 || \
|
||||
DECODE_WHIRLPOOL_AC || DECODE_SAMSUNG_AC || DECODE_ELECTRA_AC || \
|
||||
DECODE_PANASONIC_AC || DECODE_MWM)
|
||||
#define DECODE_AC true // We need some common infrastructure for decoding A/Cs.
|
||||
#else
|
||||
#define DECODE_AC false // We don't need that infrastructure.
|
||||
@@ -244,91 +267,171 @@ enum decode_type_t {
|
||||
HITACHI_AC1,
|
||||
HITACHI_AC2,
|
||||
GICABLE,
|
||||
HAIER_AC_YRW02
|
||||
HAIER_AC_YRW02,
|
||||
WHIRLPOOL_AC,
|
||||
SAMSUNG_AC,
|
||||
LUTRON,
|
||||
ELECTRA_AC,
|
||||
PANASONIC_AC,
|
||||
PIONEER,
|
||||
LG2,
|
||||
MWM,
|
||||
};
|
||||
|
||||
// Message lengths & required repeat values
|
||||
#define AIWA_RC_T501_BITS 15U
|
||||
#define AIWA_RC_T501_MIN_REPEAT 1U
|
||||
#define COOLIX_BITS 24U
|
||||
#define CARRIER_AC_BITS 32U
|
||||
#define CARRIER_AC_MIN_REPEAT 0U
|
||||
const uint16_t kNoRepeat = 0;
|
||||
const uint16_t kSingleRepeat = 1;
|
||||
|
||||
const uint16_t kAiwaRcT501Bits = 15;
|
||||
const uint16_t kAiwaRcT501MinRepeats = kSingleRepeat;
|
||||
const uint16_t kArgoStateLength = 12;
|
||||
const uint16_t kCoolixBits = 24;
|
||||
const uint16_t kCarrierAcBits = 32;
|
||||
const uint16_t kCarrierAcMinRepeat = kNoRepeat;
|
||||
// Daikin has a lot of static stuff that is discarded
|
||||
#define DAIKIN_RAW_BITS 583U
|
||||
#define DAIKIN_COMMAND_LENGTH 27U
|
||||
#define DAIKIN_BITS (DAIKIN_COMMAND_LENGTH * 8)
|
||||
#define DENON_BITS SHARP_BITS
|
||||
#define DENON_48_BITS PANASONIC_BITS
|
||||
#define DENON_LEGACY_BITS 14U
|
||||
#define DISH_BITS 16U
|
||||
#define DISH_MIN_REPEAT 3U
|
||||
#define GICABLE_BITS 16U
|
||||
#define GICABLE_MIN_REPEAT 1U
|
||||
#define GREE_STATE_LENGTH 8U
|
||||
#define GREE_BITS (GREE_STATE_LENGTH * 8)
|
||||
#define HAIER_AC_STATE_LENGTH 9U
|
||||
#define HAIER_AC_BITS (HAIER_AC_STATE_LENGTH * 8)
|
||||
#define HAIER_AC_YRW02_STATE_LENGTH 14U
|
||||
#define HAIER_AC_YRW02_BITS (HAIER_AC_YRW02_STATE_LENGTH * 8)
|
||||
#define HITACHI_AC_STATE_LENGTH 28U
|
||||
#define HITACHI_AC_BITS (HITACHI_AC_STATE_LENGTH * 8)
|
||||
#define HITACHI_AC1_STATE_LENGTH 13U
|
||||
#define HITACHI_AC1_BITS (HITACHI_AC1_STATE_LENGTH * 8)
|
||||
#define HITACHI_AC2_STATE_LENGTH 53U
|
||||
#define HITACHI_AC2_BITS (HITACHI_AC2_STATE_LENGTH * 8)
|
||||
#define JVC_BITS 16U
|
||||
#define KELVINATOR_STATE_LENGTH 16U
|
||||
#define KELVINATOR_BITS (KELVINATOR_STATE_LENGTH * 8)
|
||||
#define LG_BITS 28U
|
||||
#define LG32_BITS 32U
|
||||
#define MITSUBISHI_BITS 16U
|
||||
const uint16_t kDaikinRawBits = 583;
|
||||
const uint16_t kDaikinStateLength = 27;
|
||||
const uint16_t kDaikinBits = kDaikinStateLength * 8;
|
||||
const uint16_t kDenonBits = 15;
|
||||
const uint16_t kDenonLegacyBits = 14;
|
||||
const uint16_t kDishBits = 16;
|
||||
const uint16_t kDishMinRepeat = 3;
|
||||
const uint16_t kElectraAcStateLength = 13;
|
||||
const uint16_t kElectraAcBits = kElectraAcStateLength * 8;
|
||||
const uint16_t kFujitsuAcMinRepeat = kNoRepeat;
|
||||
const uint16_t kFujitsuAcStateLength = 16;
|
||||
const uint16_t kFujitsuAcStateLengthShort = 7;
|
||||
const uint16_t kFujitsuAcBits = kFujitsuAcStateLength * 8;
|
||||
const uint16_t kFujitsuAcMinBits = (kFujitsuAcStateLengthShort - 1) * 8;
|
||||
const uint16_t kGicableBits = 16;
|
||||
const uint16_t kGicableMinRepeat = kSingleRepeat;
|
||||
const uint16_t kGreeStateLength = 8;
|
||||
const uint16_t kGreeBits = kGreeStateLength * 8;
|
||||
const uint16_t kHaierACStateLength = 9;
|
||||
const uint16_t kHaierACBits = kHaierACStateLength * 8;
|
||||
const uint16_t kHaierACYRW02StateLength = 14;
|
||||
const uint16_t kHaierACYRW02Bits = kHaierACYRW02StateLength * 8;
|
||||
const uint16_t kHitachiAcStateLength = 28;
|
||||
const uint16_t kHitachiAcBits = kHitachiAcStateLength * 8;
|
||||
const uint16_t kHitachiAc1StateLength = 13;
|
||||
const uint16_t kHitachiAc1Bits = kHitachiAc1StateLength * 8;
|
||||
const uint16_t kHitachiAc2StateLength = 53;
|
||||
const uint16_t kHitachiAc2Bits = kHitachiAc2StateLength * 8;
|
||||
const uint16_t kJvcBits = 16;
|
||||
const uint16_t kKelvinatorStateLength = 16;
|
||||
const uint16_t kKelvinatorBits = kKelvinatorStateLength * 8;
|
||||
const uint16_t kLasertagBits = 13;
|
||||
const uint16_t kLasertagMinRepeat = kNoRepeat;
|
||||
const uint16_t kLgBits = 28;
|
||||
const uint16_t kLg32Bits = 32;
|
||||
const uint16_t kLutronBits = 35;
|
||||
const uint16_t kMagiquestBits = 56;
|
||||
const uint16_t kMideaBits = 48;
|
||||
const uint16_t kMideaMinRepeat = kNoRepeat;
|
||||
const uint16_t kMitsubishiBits = 16;
|
||||
// TODO(anyone): Verify that the Mitsubishi repeat is really needed.
|
||||
#define MITSUBISHI_MIN_REPEAT 1U // Based on marcosamarinho's code.
|
||||
#define MITSUBISHI_AC_STATE_LENGTH 18U
|
||||
#define MITSUBISHI_AC_MIN_REPEAT 1U
|
||||
#define FUJITSU_AC_MIN_REPEAT 0U
|
||||
#define FUJITSU_AC_STATE_LENGTH 16U
|
||||
#define FUJITSU_AC_STATE_LENGTH_SHORT 7U
|
||||
#define FUJITSU_AC_BITS (FUJITSU_AC_STATE_LENGTH * 8)
|
||||
#define FUJITSU_AC_MIN_BITS ((FUJITSU_AC_STATE_LENGTH_SHORT - 1) * 8)
|
||||
#define NEC_BITS 32U
|
||||
#define PANASONIC_BITS 48U
|
||||
#define PANASONIC_MANUFACTURER 0x4004ULL
|
||||
#define PRONTO_MIN_LENGTH 6U
|
||||
#define RC5_RAW_BITS 14U
|
||||
#define RC5_BITS RC5_RAW_BITS - 2U
|
||||
#define RC5X_BITS RC5_RAW_BITS - 1U
|
||||
#define RC6_MODE0_BITS 20U // Excludes the 'start' bit.
|
||||
#define RC6_36_BITS 36U // Excludes the 'start' bit.
|
||||
#define RCMM_BITS 24U
|
||||
#define SAMSUNG_BITS 32U
|
||||
#define SANYO_SA8650B_BITS 12U
|
||||
#define SANYO_LC7461_ADDRESS_BITS 13U
|
||||
#define SANYO_LC7461_COMMAND_BITS 8U
|
||||
#define SANYO_LC7461_BITS ((SANYO_LC7461_ADDRESS_BITS + \
|
||||
SANYO_LC7461_COMMAND_BITS) * 2)
|
||||
#define SHARP_ADDRESS_BITS 5U
|
||||
#define SHARP_COMMAND_BITS 8U
|
||||
#define SHARP_BITS (SHARP_ADDRESS_BITS + SHARP_COMMAND_BITS + 2) // 15U
|
||||
#define SHERWOOD_BITS NEC_BITS
|
||||
#define SHERWOOD_MIN_REPEAT 1U
|
||||
#define SONY_12_BITS 12U
|
||||
#define SONY_15_BITS 15U
|
||||
#define SONY_20_BITS 20U
|
||||
#define SONY_MIN_BITS SONY_12_BITS
|
||||
#define SONY_MIN_REPEAT 2U
|
||||
#define TOSHIBA_AC_STATE_LENGTH 9U
|
||||
#define TOSHIBA_AC_BITS (TOSHIBA_AC_STATE_LENGTH * 8)
|
||||
#define TOSHIBA_AC_MIN_REPEAT 1U
|
||||
#define TROTEC_COMMAND_LENGTH 9U
|
||||
#define WHYNTER_BITS 32U
|
||||
#define ARGO_COMMAND_LENGTH 12U
|
||||
#define NIKAI_BITS 24U
|
||||
#define MAGIQUEST_BITS 56U
|
||||
#define MIDEA_BITS 48U
|
||||
#define MIDEA_MIN_REPEAT 0U
|
||||
#define LASERTAG_BITS 13U
|
||||
#define LASERTAG_MIN_REPEAT 0U
|
||||
// Based on marcosamarinho's code.
|
||||
const uint16_t kMitsubishiMinRepeat = kSingleRepeat;
|
||||
const uint16_t kMitsubishiACStateLength = 18;
|
||||
const uint16_t kMitsubishiACBits = kMitsubishiACStateLength * 8;
|
||||
const uint16_t kMitsubishiACMinRepeat = kSingleRepeat;
|
||||
const uint16_t kNikaiBits = 24;
|
||||
const uint16_t kNECBits = 32;
|
||||
const uint16_t kPanasonicBits = 48;
|
||||
const uint32_t kPanasonicManufacturer = 0x4004;
|
||||
const uint16_t kPanasonicAcStateLength = 27;
|
||||
const uint16_t kPanasonicAcStateShortLength = 16;
|
||||
const uint16_t kPanasonicAcBits = kPanasonicAcStateLength * 8;
|
||||
const uint16_t kPanasonicAcShortBits = kPanasonicAcStateShortLength * 8;
|
||||
const uint16_t kPioneerBits = 64;
|
||||
const uint16_t kProntoMinLength = 6;
|
||||
const uint16_t kRC5RawBits = 14;
|
||||
const uint16_t kRC5Bits = kRC5RawBits - 2;
|
||||
const uint16_t kRC5XBits = kRC5RawBits - 1;
|
||||
const uint16_t kRC6Mode0Bits = 20; // Excludes the 'start' bit.
|
||||
const uint16_t kRC6_36Bits = 36; // Excludes the 'start' bit.
|
||||
const uint16_t kRCMMBits = 24;
|
||||
const uint16_t kSamsungBits = 32;
|
||||
const uint16_t kSamsungAcStateLength = 14;
|
||||
const uint16_t kSamsungAcBits = kSamsungAcStateLength * 8;
|
||||
const uint16_t kSamsungAcExtendedStateLength = 21;
|
||||
const uint16_t kSamsungAcExtendedBits = kSamsungAcExtendedStateLength * 8;
|
||||
const uint16_t kSanyoSA8650BBits = 12;
|
||||
const uint16_t kSanyoLC7461AddressBits = 13;
|
||||
const uint16_t kSanyoLC7461CommandBits = 8;
|
||||
const uint16_t kSanyoLC7461Bits = (kSanyoLC7461AddressBits +
|
||||
kSanyoLC7461CommandBits) * 2;
|
||||
const uint8_t kSharpAddressBits = 5;
|
||||
const uint8_t kSharpCommandBits = 8;
|
||||
const uint16_t kSharpBits = kSharpAddressBits + kSharpCommandBits + 2; // 15
|
||||
const uint8_t kSherwoodBits = kNECBits;
|
||||
const uint16_t kSherwoodMinRepeat = kSingleRepeat;
|
||||
const uint16_t kSony12Bits = 12;
|
||||
const uint16_t kSony15Bits = 15;
|
||||
const uint16_t kSony20Bits = 20;
|
||||
const uint16_t kSonyMinBits = 12;
|
||||
const uint16_t kSonyMinRepeat = 2;
|
||||
const uint16_t kToshibaACStateLength = 9;
|
||||
const uint16_t kToshibaACBits = kToshibaACStateLength * 8;
|
||||
const uint16_t kToshibaACMinRepeat = kSingleRepeat;
|
||||
const uint16_t kTrotecStateLength = 9;
|
||||
const uint16_t kWhirlpoolAcStateLength = 21;
|
||||
const uint16_t kWhirlpoolAcBits = kWhirlpoolAcStateLength * 8;
|
||||
const uint16_t kWhynterBits = 32;
|
||||
|
||||
// Legacy defines. (Deprecated)
|
||||
#define AIWA_RC_T501_BITS kAiwaRcT501Bits
|
||||
#define ARGO_COMMAND_LENGTH kArgoStateLength
|
||||
#define COOLIX_BITS kCoolixBits
|
||||
#define CARRIER_AC_BITS kCarrierAcBits
|
||||
#define DAIKIN_COMMAND_LENGTH kDaikinStateLength
|
||||
#define DENON_BITS kDenonBits
|
||||
#define DENON_48_BITS kPanasonicBits
|
||||
#define DENON_LEGACY_BITS kDenonLegacyBits
|
||||
#define DISH_BITS kDishBits
|
||||
#define FUJITSU_AC_MIN_REPEAT kFujitsuAcMinRepeat
|
||||
#define FUJITSU_AC_STATE_LENGTH kFujitsuAcStateLength
|
||||
#define FUJITSU_AC_STATE_LENGTH_SHORT kFujitsuAcStateLengthShort
|
||||
#define FUJITSU_AC_BITS kFujitsuAcBits
|
||||
#define FUJITSU_AC_MIN_BITS kFujitsuAcMinBits
|
||||
#define GICABLE_BITS kGicableBits
|
||||
#define GREE_STATE_LENGTH kGreeStateLength
|
||||
#define HAIER_AC_STATE_LENGTH kHaierACStateLength
|
||||
#define HAIER_AC_YRW02_STATE_LENGTH kHaierACYRW02StateLength
|
||||
#define HITACHI_AC_STATE_LENGTH kHitachiAcStateLength
|
||||
#define HITACHI_AC_BITS kHitachiAcBits
|
||||
#define HITACHI_AC1_STATE_LENGTH kHitachiAc1StateLength
|
||||
#define HITACHI_AC1_BITS kHitachiAc1Bits
|
||||
#define HITACHI_AC2_STATE_LENGTH kHitachiAc2StateLength
|
||||
#define HITACHI_AC2_BITS kHitachiAc2Bits
|
||||
#define JVC_BITS kJvcBits
|
||||
#define KELVINATOR_STATE_LENGTH kKelvinatorStateLength
|
||||
#define LASERTAG_BITS kLasertagBits
|
||||
#define LG_BITS kLgBits
|
||||
#define LG32_BITS kLg32Bits
|
||||
#define MAGIQUEST_BITS kMagiquestBits
|
||||
#define MIDEA_BITS kMideaBits
|
||||
#define MITSUBISHI_BITS kMitsubishiBits
|
||||
#define MITSUBISHI_AC_STATE_LENGTH kMitsubishiACStateLength
|
||||
#define NEC_BITS kNECBits
|
||||
#define NIKAI_BITS kNikaiBits
|
||||
#define PANASONIC_BITS kPanasonicBits
|
||||
#define RC5_BITS kRC5Bits
|
||||
#define RC5X_BITS kRC5XBits
|
||||
#define RC6_MODE0_BITS kRC6Mode0Bits
|
||||
#define RC6_36_BITS kRC6_36Bits
|
||||
#define RCMM_BITS kRCMMBits
|
||||
#define SANYO_LC7461_BITS kSanyoLC7461Bits
|
||||
#define SAMSUNG_BITS kSamsungBits
|
||||
#define SANYO_SA8650B_BITS kSanyoSA8650BBits
|
||||
#define SHARP_BITS kSharpBits
|
||||
#define SHERWOOD_BITS kSherwoodBits
|
||||
#define SONY_12_BITS kSony12Bits
|
||||
#define SONY_15_BITS kSony15Bits
|
||||
#define SONY_20_BITS kSony20Bits
|
||||
#define TOSHIBA_AC_STATE_LENGTH kToshibaACStateLength
|
||||
#define TROTEC_COMMAND_LENGTH kTrotecStateLength
|
||||
#define WHYNTER_BITS kWhynterBits
|
||||
|
||||
// Turn on Debugging information by uncommenting the following line.
|
||||
// #define DEBUG 1
|
||||
|
||||
@@ -34,9 +34,8 @@
|
||||
// to change the duty cycle etc.
|
||||
// Returns:
|
||||
// An IRsend object.
|
||||
IRsend::IRsend(uint16_t IRsendPin, bool inverted,
|
||||
bool use_modulation) : IRpin(IRsendPin),
|
||||
periodOffset(PERIOD_OFFSET) {
|
||||
IRsend::IRsend(uint16_t IRsendPin, bool inverted, bool use_modulation)
|
||||
: IRpin(IRsendPin), periodOffset(kPeriodOffset) {
|
||||
if (inverted) {
|
||||
outputOn = LOW;
|
||||
outputOff = HIGH;
|
||||
@@ -46,9 +45,9 @@ IRsend::IRsend(uint16_t IRsendPin, bool inverted,
|
||||
}
|
||||
modulation = use_modulation;
|
||||
if (modulation)
|
||||
_dutycycle = DUTY_DEFAULT;
|
||||
_dutycycle = kDutyDefault;
|
||||
else
|
||||
_dutycycle = DUTY_MAX;
|
||||
_dutycycle = kDutyMax;
|
||||
}
|
||||
|
||||
// Enable the pin for output.
|
||||
@@ -82,12 +81,13 @@ void IRsend::ledOn() {
|
||||
// nr. of uSeconds.
|
||||
uint32_t IRsend::calcUSecPeriod(uint32_t hz, bool use_offset) {
|
||||
if (hz == 0) hz = 1; // Avoid Zero hz. Divide by Zero is nasty.
|
||||
uint32_t period = (1000000UL + hz/2) / hz; // The equiv of round(1000000/hz).
|
||||
uint32_t period =
|
||||
(1000000UL + hz / 2) / hz; // The equiv of round(1000000/hz).
|
||||
// Apply the offset and ensure we don't result in a <= 0 value.
|
||||
if (use_offset)
|
||||
return std::max((uint32_t) 1, period + periodOffset);
|
||||
return std::max((uint32_t)1, period + periodOffset);
|
||||
else
|
||||
return std::max((uint32_t) 1, period);
|
||||
return std::max((uint32_t)1, period);
|
||||
}
|
||||
|
||||
// Set the output frequency modulation and duty cycle.
|
||||
@@ -104,15 +104,15 @@ uint32_t IRsend::calcUSecPeriod(uint32_t hz, bool use_offset) {
|
||||
void IRsend::enableIROut(uint32_t freq, uint8_t duty) {
|
||||
// Set the duty cycle to use if we want freq. modulation.
|
||||
if (modulation) {
|
||||
_dutycycle = std::min(duty, (uint8_t) DUTY_MAX);
|
||||
_dutycycle = std::min(duty, kDutyMax);
|
||||
} else {
|
||||
_dutycycle = DUTY_MAX;
|
||||
_dutycycle = kDutyMax;
|
||||
}
|
||||
if (freq < 1000) // Were we given kHz? Supports the old call usage.
|
||||
freq *= 1000;
|
||||
uint32_t period = calcUSecPeriod(freq);
|
||||
// Nr. of uSeconds the LED will be on per pulse.
|
||||
onTimePeriod = (period * _dutycycle) / DUTY_MAX;
|
||||
onTimePeriod = (period * _dutycycle) / kDutyMax;
|
||||
// Nr. of uSeconds the LED will be off per pulse.
|
||||
offTimePeriod = period - onTimePeriod;
|
||||
}
|
||||
@@ -124,7 +124,7 @@ void IRsend::enableIROut(uint32_t freq, uint8_t duty) {
|
||||
void IRsend::_delayMicroseconds(uint32_t usec) {
|
||||
// delayMicroseconds() is only accurate to 16383us.
|
||||
// Ref: https://www.arduino.cc/en/Reference/delayMicroseconds
|
||||
if (usec <= MAX_ACCURATE_USEC_DELAY) {
|
||||
if (usec <= kMaxAccurateUsecDelay) {
|
||||
#ifndef UNIT_TEST
|
||||
delayMicroseconds(usec);
|
||||
#endif
|
||||
@@ -146,9 +146,9 @@ void IRsend::_delayMicroseconds(uint32_t usec) {
|
||||
// NOTE: Use this only if you know what you are doing as it may cause the WDT
|
||||
// to reset the ESP8266.
|
||||
void IRsend::_delayMicroseconds(uint32_t usec) {
|
||||
for (; usec > MAX_ACCURATE_USEC_DELAY; usec -= MAX_ACCURATE_USEC_DELAY)
|
||||
for (; usec > kMaxAccurateUsecDelay; usec -= kMaxAccurateUsecDelay)
|
||||
#ifndef UNIT_TEST
|
||||
delayMicroseconds(MAX_ACCURATE_USEC_DELAY);
|
||||
delayMicroseconds(kMaxAccurateUsecDelay);
|
||||
delayMicroseconds(static_cast<uint16_t>(usec));
|
||||
#endif // UNIT_TEST
|
||||
}
|
||||
@@ -190,14 +190,14 @@ uint16_t IRsend::mark(uint16_t usec) {
|
||||
ledOn();
|
||||
// Calculate how long we should pulse on for.
|
||||
// e.g. Are we to close to the end of our requested mark time (usec)?
|
||||
_delayMicroseconds(std::min((uint32_t) onTimePeriod, usec - elapsed));
|
||||
_delayMicroseconds(std::min((uint32_t)onTimePeriod, usec - elapsed));
|
||||
ledOff();
|
||||
counter++;
|
||||
if (elapsed + onTimePeriod >= usec)
|
||||
return counter; // LED is now off & we've passed our allotted time.
|
||||
// Wait for the lesser of the rest of the duty cycle, or the time remaining.
|
||||
_delayMicroseconds(std::min(usec - elapsed - onTimePeriod,
|
||||
(uint32_t) offTimePeriod));
|
||||
_delayMicroseconds(
|
||||
std::min(usec - elapsed - onTimePeriod, (uint32_t)offTimePeriod));
|
||||
elapsed = usecTimer.elapsed(); // Update & recache the actual elapsed time.
|
||||
}
|
||||
return counter;
|
||||
@@ -238,7 +238,7 @@ int8_t IRsend::calibrate(uint16_t hz) {
|
||||
uint32_t timeTaken = usecTimer.elapsed(); // Record the time it took.
|
||||
// While it shouldn't be necessary, assume at least 1 pulse, to avoid a
|
||||
// divide by 0 situation.
|
||||
pulses = std::max(pulses, (uint16_t) 1U);
|
||||
pulses = std::max(pulses, (uint16_t)1U);
|
||||
uint32_t calcPeriod = calcUSecPeriod(hz); // e.g. @38kHz it should be 26us.
|
||||
// Assuming 38kHz for the example calculations:
|
||||
// In a 65535us pulse, we should have 2520.5769 pulses @ 26us periods.
|
||||
@@ -250,9 +250,9 @@ int8_t IRsend::calibrate(uint16_t hz) {
|
||||
//
|
||||
// Calculate the actual period from the actual time & the actual pulses
|
||||
// generated.
|
||||
double_t actualPeriod = (double_t) timeTaken / (double_t) pulses;
|
||||
double_t actualPeriod = (double_t)timeTaken / (double_t)pulses;
|
||||
// Store the difference between the actual time per period vs. calculated.
|
||||
periodOffset = (int8_t) ((double_t) calcPeriod - actualPeriod);
|
||||
periodOffset = (int8_t)((double_t)calcPeriod - actualPeriod);
|
||||
return periodOffset;
|
||||
}
|
||||
|
||||
@@ -268,9 +268,9 @@ int8_t IRsend::calibrate(uint16_t hz) {
|
||||
// data: The data to be transmitted.
|
||||
// nbits: Nr. of bits of data to be sent.
|
||||
// MSBfirst: Flag for bit transmission order. Defaults to MSB->LSB order.
|
||||
void IRsend::sendData(uint16_t onemark, uint32_t onespace,
|
||||
uint16_t zeromark, uint32_t zerospace,
|
||||
uint64_t data, uint16_t nbits, bool MSBfirst) {
|
||||
void IRsend::sendData(uint16_t onemark, uint32_t onespace, uint16_t zeromark,
|
||||
uint32_t zerospace, uint64_t data, uint16_t nbits,
|
||||
bool MSBfirst) {
|
||||
if (nbits == 0) // If we are asked to send nothing, just return.
|
||||
return;
|
||||
if (MSBfirst) { // Send the MSB first.
|
||||
@@ -281,7 +281,7 @@ void IRsend::sendData(uint16_t onemark, uint32_t onespace,
|
||||
nbits--;
|
||||
}
|
||||
// Send the supplied data.
|
||||
for (uint64_t mask = 1ULL << (nbits - 1); mask; mask >>= 1)
|
||||
for (uint64_t mask = 1ULL << (nbits - 1); mask; mask >>= 1)
|
||||
if (data & mask) { // Send a 1
|
||||
mark(onemark);
|
||||
space(onespace);
|
||||
@@ -376,10 +376,10 @@ void IRsend::sendGeneric(const uint16_t headermark, const uint32_t headerspace,
|
||||
const uint16_t onemark, const uint32_t onespace,
|
||||
const uint16_t zeromark, const uint32_t zerospace,
|
||||
const uint16_t footermark, const uint32_t gap,
|
||||
const uint32_t mesgtime,
|
||||
const uint64_t data, const uint16_t nbits,
|
||||
const uint16_t frequency, const bool MSBfirst,
|
||||
const uint16_t repeat, const uint8_t dutycycle) {
|
||||
const uint32_t mesgtime, const uint64_t data,
|
||||
const uint16_t nbits, const uint16_t frequency,
|
||||
const bool MSBfirst, const uint16_t repeat,
|
||||
const uint8_t dutycycle) {
|
||||
// Setup
|
||||
enableIROut(frequency, dutycycle);
|
||||
IRtimer usecs = IRtimer();
|
||||
@@ -389,14 +389,14 @@ void IRsend::sendGeneric(const uint16_t headermark, const uint32_t headerspace,
|
||||
usecs.reset();
|
||||
|
||||
// Header
|
||||
if (headermark) mark(headermark);
|
||||
if (headerspace) space(headerspace);
|
||||
if (headermark) mark(headermark);
|
||||
if (headerspace) space(headerspace);
|
||||
|
||||
// Data
|
||||
sendData(onemark, onespace, zeromark, zerospace, data, nbits, MSBfirst);
|
||||
|
||||
// Footer
|
||||
if (footermark) mark(footermark);
|
||||
if (footermark) mark(footermark);
|
||||
uint32_t elapsed = usecs.elapsed();
|
||||
// Avoid potential unsigned integer underflow. e.g. when mesgtime is 0.
|
||||
if (elapsed >= mesgtime)
|
||||
@@ -445,16 +445,16 @@ void IRsend::sendGeneric(const uint16_t headermark, const uint32_t headerspace,
|
||||
// We always send a message, even for repeat=0, hence '<= repeat'.
|
||||
for (uint16_t r = 0; r <= repeat; r++) {
|
||||
// Header
|
||||
if (headermark) mark(headermark);
|
||||
if (headerspace) space(headerspace);
|
||||
if (headermark) mark(headermark);
|
||||
if (headerspace) space(headerspace);
|
||||
|
||||
// Data
|
||||
for (uint16_t i = 0; i < nbytes; i++)
|
||||
sendData(onemark, onespace, zeromark, zerospace,
|
||||
*(dataptr + i), 8, MSBfirst);
|
||||
sendData(onemark, onespace, zeromark, zerospace, *(dataptr + i), 8,
|
||||
MSBfirst);
|
||||
|
||||
// Footer
|
||||
if (footermark) mark(footermark);
|
||||
if (footermark) mark(footermark);
|
||||
space(gap);
|
||||
}
|
||||
}
|
||||
@@ -492,61 +492,109 @@ void IRsend::sendRaw(uint16_t buf[], uint16_t len, uint16_t hz) {
|
||||
void IRsend::send(uint16_t type, uint64_t data, uint16_t nbits) {
|
||||
switch (type) {
|
||||
#if SEND_NEC
|
||||
case NEC: sendNEC(data, nbits); break;
|
||||
case NEC:
|
||||
sendNEC(data, nbits);
|
||||
break;
|
||||
#endif
|
||||
#if SEND_SONY
|
||||
case SONY: sendSony(data, nbits); break;
|
||||
case SONY:
|
||||
sendSony(data, nbits);
|
||||
break;
|
||||
#endif
|
||||
#if SEND_RC5
|
||||
case RC5: sendRC5(data, nbits); break;
|
||||
case RC5:
|
||||
sendRC5(data, nbits);
|
||||
break;
|
||||
#endif
|
||||
#if SEND_RC6
|
||||
case RC6: sendRC6(data, nbits); break;
|
||||
case RC6:
|
||||
sendRC6(data, nbits);
|
||||
break;
|
||||
#endif
|
||||
#if SEND_DISH
|
||||
case DISH: sendDISH(data, nbits); break;
|
||||
case DISH:
|
||||
sendDISH(data, nbits);
|
||||
break;
|
||||
#endif
|
||||
#if SEND_JVC
|
||||
case JVC: sendJVC(data, nbits); break;
|
||||
case JVC:
|
||||
sendJVC(data, nbits);
|
||||
break;
|
||||
#endif
|
||||
#if SEND_SAMSUNG
|
||||
case SAMSUNG: sendSAMSUNG(data, nbits); break;
|
||||
case SAMSUNG:
|
||||
sendSAMSUNG(data, nbits);
|
||||
break;
|
||||
#endif
|
||||
#if SEND_LG
|
||||
case LG: sendLG(data, nbits); break;
|
||||
case LG:
|
||||
sendLG(data, nbits);
|
||||
break;
|
||||
#endif
|
||||
#if SEND_LG
|
||||
case LG2:
|
||||
sendLG2(data, nbits);
|
||||
break;
|
||||
#endif
|
||||
#if SEND_WHYNTER
|
||||
case WHYNTER: sendWhynter(data, nbits); break;
|
||||
case WHYNTER:
|
||||
sendWhynter(data, nbits);
|
||||
break;
|
||||
#endif
|
||||
#if SEND_COOLIX
|
||||
case COOLIX: sendCOOLIX(data, nbits); break;
|
||||
case COOLIX:
|
||||
sendCOOLIX(data, nbits);
|
||||
break;
|
||||
#endif
|
||||
#if SEND_DENON
|
||||
case DENON: sendDenon(data, nbits); break;
|
||||
case DENON:
|
||||
sendDenon(data, nbits);
|
||||
break;
|
||||
#endif
|
||||
#if SEND_SHERWOOD
|
||||
case SHERWOOD: sendSherwood(data, nbits); break;
|
||||
case SHERWOOD:
|
||||
sendSherwood(data, nbits);
|
||||
break;
|
||||
#endif
|
||||
#if SEND_RCMM
|
||||
case RCMM: sendRCMM(data, nbits); break;
|
||||
case RCMM:
|
||||
sendRCMM(data, nbits);
|
||||
break;
|
||||
#endif
|
||||
#if SEND_MITSUBISHI
|
||||
case MITSUBISHI: sendMitsubishi(data, nbits); break;
|
||||
case MITSUBISHI:
|
||||
sendMitsubishi(data, nbits);
|
||||
break;
|
||||
#endif
|
||||
#if SEND_MITSUBISHI2
|
||||
case MITSUBISHI2: sendMitsubishi2(data, nbits); break;
|
||||
case MITSUBISHI2:
|
||||
sendMitsubishi2(data, nbits);
|
||||
break;
|
||||
#endif
|
||||
#if SEND_SHARP
|
||||
case SHARP: sendSharpRaw(data, nbits); break;
|
||||
case SHARP:
|
||||
sendSharpRaw(data, nbits);
|
||||
break;
|
||||
#endif
|
||||
#if SEND_AIWA_RC_T501
|
||||
case AIWA_RC_T501: sendAiwaRCT501(data, nbits); break;
|
||||
case AIWA_RC_T501:
|
||||
sendAiwaRCT501(data, nbits);
|
||||
break;
|
||||
#endif
|
||||
#if SEND_MIDEA
|
||||
case MIDEA: sendMidea(data, nbits); break;
|
||||
case MIDEA:
|
||||
sendMidea(data, nbits);
|
||||
break;
|
||||
#endif
|
||||
#if SEND_GICABLE
|
||||
case GICABLE: sendGICable(data, nbits); break;
|
||||
case GICABLE:
|
||||
sendGICable(data, nbits);
|
||||
break;
|
||||
#endif
|
||||
#if SEND_PIONEER
|
||||
case PIONEER:
|
||||
sendPioneer(data, nbits);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,12 +22,12 @@
|
||||
// Offset (in microseconds) to use in Period time calculations to account for
|
||||
// code excution time in producing the software PWM signal.
|
||||
// Value was calculated on Wemos D1 mini using v2.4.1 with v2.4.0 ESP core
|
||||
#define PERIOD_OFFSET -5
|
||||
#define DUTY_DEFAULT 50
|
||||
#define DUTY_MAX 100 // Percentage
|
||||
const int8_t kPeriodOffset = -5;
|
||||
const uint8_t kDutyDefault = 50; // Percentage
|
||||
const uint8_t kDutyMax = 100; // Percentage
|
||||
// delayMicroseconds() is only accurate to 16383us.
|
||||
// Ref: https://www.arduino.cc/en/Reference/delayMicroseconds
|
||||
#define MAX_ACCURATE_USEC_DELAY 16383U
|
||||
const uint16_t kMaxAccurateUsecDelay = 16383;
|
||||
|
||||
// Classes
|
||||
class IRsend {
|
||||
@@ -35,7 +35,7 @@ class IRsend {
|
||||
explicit IRsend(uint16_t IRsendPin, bool inverted = false,
|
||||
bool use_modulation = true);
|
||||
void begin();
|
||||
void enableIROut(uint32_t freq, uint8_t duty = DUTY_DEFAULT);
|
||||
void enableIROut(uint32_t freq, uint8_t duty = kDutyDefault);
|
||||
VIRTUAL void _delayMicroseconds(uint32_t usec);
|
||||
VIRTUAL uint16_t mark(uint16_t usec);
|
||||
VIRTUAL void space(uint32_t usec);
|
||||
@@ -55,10 +55,10 @@ class IRsend {
|
||||
const uint16_t onemark, const uint32_t onespace,
|
||||
const uint16_t zeromark, const uint32_t zerospace,
|
||||
const uint16_t footermark, const uint32_t gap,
|
||||
const uint32_t mesgtime,
|
||||
const uint64_t data, const uint16_t nbits,
|
||||
const uint16_t frequency, const bool MSBfirst,
|
||||
const uint16_t repeat, const uint8_t dutycycle);
|
||||
const uint32_t mesgtime, const uint64_t data,
|
||||
const uint16_t nbits, const uint16_t frequency,
|
||||
const bool MSBfirst, const uint16_t repeat,
|
||||
const uint8_t dutycycle);
|
||||
void sendGeneric(const uint16_t headermark, const uint32_t headerspace,
|
||||
const uint16_t onemark, const uint32_t onespace,
|
||||
const uint16_t zeromark, const uint32_t zerospace,
|
||||
@@ -66,9 +66,10 @@ class IRsend {
|
||||
const uint8_t *dataptr, const uint16_t nbytes,
|
||||
const uint16_t frequency, const bool MSBfirst,
|
||||
const uint16_t repeat, const uint8_t dutycycle);
|
||||
void send(uint16_t type, uint64_t data, uint16_t nbits);
|
||||
void send(uint16_t type, uint64_t data, uint16_t nbits);
|
||||
#if (SEND_NEC || SEND_SHERWOOD || SEND_AIWA_RC_T501 || SEND_SANYO)
|
||||
void sendNEC(uint64_t data, uint16_t nbits = NEC_BITS, uint16_t repeat = 0);
|
||||
void sendNEC(uint64_t data, uint16_t nbits = kNECBits,
|
||||
uint16_t repeat = kNoRepeat);
|
||||
uint32_t encodeNEC(uint16_t address, uint16_t command);
|
||||
#endif
|
||||
#if SEND_SONY
|
||||
@@ -77,22 +78,30 @@ void send(uint16_t type, uint64_t data, uint16_t nbits);
|
||||
// Legacy use of this procedure was to only send a single code so call it with
|
||||
// repeat=0 for backward compatibility. As of v2.0 it defaults to sending
|
||||
// a Sony command that will be accepted be a device.
|
||||
void sendSony(uint64_t data, uint16_t nbits = SONY_20_BITS,
|
||||
uint16_t repeat = SONY_MIN_REPEAT);
|
||||
void sendSony(uint64_t data, uint16_t nbits = kSony20Bits,
|
||||
uint16_t repeat = kSonyMinRepeat);
|
||||
uint32_t encodeSony(uint16_t nbits, uint16_t command, uint16_t address,
|
||||
uint16_t extended = 0);
|
||||
#endif
|
||||
#if SEND_SHERWOOD
|
||||
void sendSherwood(uint64_t data, uint16_t nbits = SHERWOOD_BITS,
|
||||
uint16_t repeat = SHERWOOD_MIN_REPEAT);
|
||||
void sendSherwood(uint64_t data, uint16_t nbits = kSherwoodBits,
|
||||
uint16_t repeat = kSherwoodMinRepeat);
|
||||
#endif
|
||||
#if SEND_SAMSUNG
|
||||
void sendSAMSUNG(uint64_t data, uint16_t nbits = SAMSUNG_BITS,
|
||||
uint16_t repeat = 0);
|
||||
void sendSAMSUNG(uint64_t data, uint16_t nbits = kSamsungBits,
|
||||
uint16_t repeat = kNoRepeat);
|
||||
uint32_t encodeSAMSUNG(uint8_t customer, uint8_t command);
|
||||
#endif
|
||||
#if SEND_SAMSUNG_AC
|
||||
void sendSamsungAC(unsigned char data[],
|
||||
uint16_t nbytes = kSamsungAcStateLength,
|
||||
uint16_t repeat = kNoRepeat);
|
||||
#endif
|
||||
#if SEND_LG
|
||||
void sendLG(uint64_t data, uint16_t nbits = LG_BITS, uint16_t repeat = 0);
|
||||
void sendLG(uint64_t data, uint16_t nbits = kLgBits,
|
||||
uint16_t repeat = kNoRepeat);
|
||||
void sendLG2(uint64_t data, uint16_t nbits = kLgBits,
|
||||
uint16_t repeat = kNoRepeat);
|
||||
uint32_t encodeLG(uint16_t address, uint16_t command);
|
||||
#endif
|
||||
#if (SEND_SHARP || SEND_DENON)
|
||||
@@ -100,41 +109,44 @@ void send(uint16_t type, uint64_t data, uint16_t nbits);
|
||||
uint16_t expansion = 1, uint16_t check = 0,
|
||||
bool MSBfirst = false);
|
||||
void sendSharp(uint16_t address, uint16_t command,
|
||||
uint16_t nbits = SHARP_BITS, uint16_t repeat = 0);
|
||||
void sendSharpRaw(uint64_t data, uint16_t nbits = SHARP_BITS,
|
||||
uint16_t repeat = 0);
|
||||
uint16_t nbits = kSharpBits, uint16_t repeat = kNoRepeat);
|
||||
void sendSharpRaw(uint64_t data, uint16_t nbits = kSharpBits,
|
||||
uint16_t repeat = kNoRepeat);
|
||||
#endif
|
||||
#if SEND_JVC
|
||||
void sendJVC(uint64_t data, uint16_t nbits = JVC_BITS, uint16_t repeat = 0);
|
||||
void sendJVC(uint64_t data, uint16_t nbits = kJvcBits,
|
||||
uint16_t repeat = kNoRepeat);
|
||||
uint16_t encodeJVC(uint8_t address, uint8_t command);
|
||||
#endif
|
||||
#if SEND_DENON
|
||||
void sendDenon(uint64_t data, uint16_t nbits = DENON_BITS,
|
||||
uint16_t repeat = 0);
|
||||
uint16_t repeat = kNoRepeat);
|
||||
#endif
|
||||
#if SEND_SANYO
|
||||
uint64_t encodeSanyoLC7461(uint16_t address, uint8_t command);
|
||||
void sendSanyoLC7461(uint64_t data, uint16_t nbits = SANYO_LC7461_BITS,
|
||||
uint16_t repeat = 0);
|
||||
void sendSanyoLC7461(uint64_t data, uint16_t nbits = kSanyoLC7461Bits,
|
||||
uint16_t repeat = kNoRepeat);
|
||||
#endif
|
||||
#if SEND_DISH
|
||||
// sendDISH() should typically be called with repeat=3 as DISH devices
|
||||
// expect the code to be sent at least 4 times. (code + 3 repeats = 4 codes)
|
||||
// Legacy use of this procedure was only to send a single code
|
||||
// so use repeat=0 for backward compatibility.
|
||||
void sendDISH(uint64_t data, uint16_t nbits = DISH_BITS,
|
||||
uint16_t repeat = DISH_MIN_REPEAT);
|
||||
void sendDISH(uint64_t data, uint16_t nbits = kDishBits,
|
||||
uint16_t repeat = kDishMinRepeat);
|
||||
#endif
|
||||
#if (SEND_PANASONIC || SEND_DENON)
|
||||
void sendPanasonic64(uint64_t data, uint16_t nbits = PANASONIC_BITS,
|
||||
uint16_t repeat = 0);
|
||||
void sendPanasonic64(uint64_t data, uint16_t nbits = kPanasonicBits,
|
||||
uint16_t repeat = kNoRepeat);
|
||||
void sendPanasonic(uint16_t address, uint32_t data,
|
||||
uint16_t nbits = PANASONIC_BITS, uint16_t repeat = 0);
|
||||
uint16_t nbits = kPanasonicBits,
|
||||
uint16_t repeat = kNoRepeat);
|
||||
uint64_t encodePanasonic(uint16_t manufacturer, uint8_t device,
|
||||
uint8_t subdevice, uint8_t function);
|
||||
#endif
|
||||
#if SEND_RC5
|
||||
void sendRC5(uint64_t data, uint16_t nbits = RC5X_BITS, uint16_t repeat = 0);
|
||||
void sendRC5(uint64_t data, uint16_t nbits = kRC5XBits,
|
||||
uint16_t repeat = kNoRepeat);
|
||||
uint16_t encodeRC5(uint8_t address, uint8_t command,
|
||||
bool key_released = false);
|
||||
uint16_t encodeRC5X(uint8_t address, uint8_t command,
|
||||
@@ -142,131 +154,156 @@ void send(uint16_t type, uint64_t data, uint16_t nbits);
|
||||
uint64_t toggleRC5(uint64_t data);
|
||||
#endif
|
||||
#if SEND_RC6
|
||||
void sendRC6(uint64_t data, uint16_t nbits = RC6_MODE0_BITS,
|
||||
uint16_t repeat = 0);
|
||||
void sendRC6(uint64_t data, uint16_t nbits = kRC6Mode0Bits,
|
||||
uint16_t repeat = kNoRepeat);
|
||||
uint64_t encodeRC6(uint32_t address, uint8_t command,
|
||||
uint16_t mode = RC6_MODE0_BITS);
|
||||
uint64_t toggleRC6(uint64_t data, uint16_t nbits = RC6_MODE0_BITS);
|
||||
uint16_t mode = kRC6Mode0Bits);
|
||||
uint64_t toggleRC6(uint64_t data, uint16_t nbits = kRC6Mode0Bits);
|
||||
#endif
|
||||
#if SEND_RCMM
|
||||
void sendRCMM(uint64_t data, uint16_t nbits = RCMM_BITS, uint16_t repeat = 0);
|
||||
void sendRCMM(uint64_t data, uint16_t nbits = kRCMMBits,
|
||||
uint16_t repeat = kNoRepeat);
|
||||
#endif
|
||||
#if SEND_COOLIX
|
||||
void sendCOOLIX(uint64_t data, uint16_t nbits = COOLIX_BITS,
|
||||
uint16_t repeat = 0);
|
||||
void sendCOOLIX(uint64_t data, uint16_t nbits = kCoolixBits,
|
||||
uint16_t repeat = kNoRepeat);
|
||||
#endif
|
||||
#if SEND_WHYNTER
|
||||
void sendWhynter(uint64_t data, uint16_t nbits = WHYNTER_BITS,
|
||||
uint16_t repeat = 0);
|
||||
void sendWhynter(uint64_t data, uint16_t nbits = kWhynterBits,
|
||||
uint16_t repeat = kNoRepeat);
|
||||
#endif
|
||||
#if SEND_MITSUBISHI
|
||||
void sendMitsubishi(uint64_t data, uint16_t nbits = MITSUBISHI_BITS,
|
||||
uint16_t repeat = MITSUBISHI_MIN_REPEAT);
|
||||
void sendMitsubishi(uint64_t data, uint16_t nbits = kMitsubishiBits,
|
||||
uint16_t repeat = kMitsubishiMinRepeat);
|
||||
#endif
|
||||
#if SEND_MITSUBISHI2
|
||||
void sendMitsubishi2(uint64_t data, uint16_t nbits = MITSUBISHI_BITS,
|
||||
uint16_t repeat = MITSUBISHI_MIN_REPEAT);
|
||||
void sendMitsubishi2(uint64_t data, uint16_t nbits = kMitsubishiBits,
|
||||
uint16_t repeat = kMitsubishiMinRepeat);
|
||||
#endif
|
||||
#if SEND_MITSUBISHI_AC
|
||||
void sendMitsubishiAC(unsigned char data[],
|
||||
uint16_t nbytes = MITSUBISHI_AC_STATE_LENGTH,
|
||||
uint16_t repeat = MITSUBISHI_AC_MIN_REPEAT);
|
||||
uint16_t nbytes = kMitsubishiACStateLength,
|
||||
uint16_t repeat = kMitsubishiACMinRepeat);
|
||||
#endif
|
||||
#if SEND_FUJITSU_AC
|
||||
void sendFujitsuAC(unsigned char data[],
|
||||
uint16_t nbytes,
|
||||
uint16_t repeat = FUJITSU_AC_MIN_REPEAT);
|
||||
void sendFujitsuAC(unsigned char data[], uint16_t nbytes,
|
||||
uint16_t repeat = kFujitsuAcMinRepeat);
|
||||
#endif
|
||||
#if SEND_GLOBALCACHE
|
||||
void sendGC(uint16_t buf[], uint16_t len);
|
||||
#endif
|
||||
#if SEND_KELVINATOR
|
||||
void sendKelvinator(unsigned char data[],
|
||||
uint16_t nbytes = KELVINATOR_STATE_LENGTH,
|
||||
uint16_t repeat = 0);
|
||||
uint16_t nbytes = kKelvinatorStateLength,
|
||||
uint16_t repeat = kNoRepeat);
|
||||
#endif
|
||||
#if SEND_DAIKIN
|
||||
void sendDaikin(unsigned char data[],
|
||||
uint16_t nbytes = DAIKIN_COMMAND_LENGTH,
|
||||
uint16_t repeat = 0);
|
||||
void sendDaikin(unsigned char data[], uint16_t nbytes = kDaikinStateLength,
|
||||
uint16_t repeat = kNoRepeat);
|
||||
void sendDaikinGapHeader();
|
||||
#endif
|
||||
#if SEND_AIWA_RC_T501
|
||||
void sendAiwaRCT501(uint64_t data, uint16_t nbits = AIWA_RC_T501_BITS,
|
||||
uint16_t repeat = AIWA_RC_T501_MIN_REPEAT);
|
||||
void sendAiwaRCT501(uint64_t data, uint16_t nbits = kAiwaRcT501Bits,
|
||||
uint16_t repeat = kAiwaRcT501MinRepeats);
|
||||
#endif
|
||||
#if SEND_GREE
|
||||
void sendGree(uint64_t data, uint16_t nbits = GREE_BITS, uint16_t repeat = 0);
|
||||
void sendGree(uint8_t data[], uint16_t nbytes = GREE_STATE_LENGTH,
|
||||
uint16_t repeat = 0);
|
||||
void sendGree(uint64_t data, uint16_t nbits = kGreeBits,
|
||||
uint16_t repeat = kNoRepeat);
|
||||
void sendGree(uint8_t data[], uint16_t nbytes = kGreeStateLength,
|
||||
uint16_t repeat = kNoRepeat);
|
||||
#endif
|
||||
#if SEND_PRONTO
|
||||
void sendPronto(uint16_t data[], uint16_t len, uint16_t repeat = 0);
|
||||
void sendPronto(uint16_t data[], uint16_t len, uint16_t repeat = kNoRepeat);
|
||||
#endif
|
||||
#if SEND_ARGO
|
||||
void sendArgo(unsigned char data[],
|
||||
uint16_t nbytes = ARGO_COMMAND_LENGTH,
|
||||
uint16_t repeat = 0);
|
||||
void sendArgo(unsigned char data[], uint16_t nbytes = kArgoStateLength,
|
||||
uint16_t repeat = kNoRepeat);
|
||||
#endif
|
||||
#if SEND_TROTEC
|
||||
void sendTrotec(unsigned char data[],
|
||||
uint16_t nbytes = TROTEC_COMMAND_LENGTH,
|
||||
uint16_t repeat = 0);
|
||||
void sendTrotec(unsigned char data[], uint16_t nbytes = kTrotecStateLength,
|
||||
uint16_t repeat = kNoRepeat);
|
||||
#endif
|
||||
#if SEND_NIKAI
|
||||
void sendNikai(uint64_t data, uint16_t nbits = NIKAI_BITS,
|
||||
uint16_t repeat = 0);
|
||||
void sendNikai(uint64_t data, uint16_t nbits = kNikaiBits,
|
||||
uint16_t repeat = kNoRepeat);
|
||||
#endif
|
||||
#if SEND_TOSHIBA_AC
|
||||
void sendToshibaAC(unsigned char data[],
|
||||
uint16_t nbytes = TOSHIBA_AC_STATE_LENGTH,
|
||||
uint16_t repeat = TOSHIBA_AC_MIN_REPEAT);
|
||||
uint16_t nbytes = kToshibaACStateLength,
|
||||
uint16_t repeat = kToshibaACMinRepeat);
|
||||
#endif
|
||||
#if SEND_MIDEA
|
||||
void sendMidea(uint64_t data, uint16_t nbits = MIDEA_BITS,
|
||||
uint16_t repeat = MIDEA_MIN_REPEAT);
|
||||
void sendMidea(uint64_t data, uint16_t nbits = kMideaBits,
|
||||
uint16_t repeat = kMideaMinRepeat);
|
||||
#endif
|
||||
#if SEND_MAGIQUEST
|
||||
void sendMagiQuest(uint64_t data, uint16_t nbits = MAGIQUEST_BITS,
|
||||
uint16_t repeat = 0);
|
||||
void sendMagiQuest(uint64_t data, uint16_t nbits = kMagiquestBits,
|
||||
uint16_t repeat = kNoRepeat);
|
||||
uint64_t encodeMagiQuest(uint32_t wand_id, uint16_t magnitude);
|
||||
#endif
|
||||
#if SEND_LASERTAG
|
||||
void sendLasertag(uint64_t data, uint16_t nbits = LASERTAG_BITS,
|
||||
uint16_t repeat = LASERTAG_MIN_REPEAT);
|
||||
void sendLasertag(uint64_t data, uint16_t nbits = kLasertagBits,
|
||||
uint16_t repeat = kLasertagMinRepeat);
|
||||
#endif
|
||||
#if SEND_CARRIER_AC
|
||||
void sendCarrierAC(uint64_t data, uint16_t nbits = CARRIER_AC_BITS,
|
||||
uint16_t repeat = CARRIER_AC_MIN_REPEAT);
|
||||
void sendCarrierAC(uint64_t data, uint16_t nbits = kCarrierAcBits,
|
||||
uint16_t repeat = kCarrierAcMinRepeat);
|
||||
#endif
|
||||
#if (SEND_HAIER_AC || SEND_HAIER_AC_YRW02)
|
||||
void sendHaierAC(unsigned char data[],
|
||||
uint16_t nbytes = HAIER_AC_STATE_LENGTH,
|
||||
uint16_t repeat = 0);
|
||||
void sendHaierAC(unsigned char data[], uint16_t nbytes = kHaierACStateLength,
|
||||
uint16_t repeat = kNoRepeat);
|
||||
#endif
|
||||
#if SEND_HAIER_AC_YRW02
|
||||
void sendHaierACYRW02(unsigned char data[],
|
||||
uint16_t nbytes = HAIER_AC_YRW02_STATE_LENGTH,
|
||||
uint16_t repeat = 0);
|
||||
uint16_t nbytes = kHaierACYRW02StateLength,
|
||||
uint16_t repeat = kNoRepeat);
|
||||
#endif
|
||||
#if SEND_HITACHI_AC
|
||||
void sendHitachiAC(unsigned char data[],
|
||||
uint16_t nbytes = HITACHI_AC_STATE_LENGTH,
|
||||
uint16_t repeat = 0);
|
||||
uint16_t nbytes = kHitachiAcStateLength,
|
||||
uint16_t repeat = kNoRepeat);
|
||||
#endif
|
||||
#if SEND_HITACHI_AC1
|
||||
void sendHitachiAC1(unsigned char data[],
|
||||
uint16_t nbytes = HITACHI_AC1_STATE_LENGTH,
|
||||
uint16_t repeat = 0);
|
||||
uint16_t nbytes = kHitachiAc1StateLength,
|
||||
uint16_t repeat = kNoRepeat);
|
||||
#endif
|
||||
#if SEND_HITACHI_AC2
|
||||
void sendHitachiAC2(unsigned char data[],
|
||||
uint16_t nbytes = HITACHI_AC2_STATE_LENGTH,
|
||||
uint16_t repeat = 0);
|
||||
uint16_t nbytes = kHitachiAc2StateLength,
|
||||
uint16_t repeat = kNoRepeat);
|
||||
#endif
|
||||
#if SEND_GICABLE
|
||||
void sendGICable(uint64_t data, uint16_t nbits = GICABLE_BITS,
|
||||
uint16_t repeat = GICABLE_MIN_REPEAT);
|
||||
void sendGICable(uint64_t data, uint16_t nbits = kGicableBits,
|
||||
uint16_t repeat = kGicableMinRepeat);
|
||||
#endif
|
||||
#if SEND_WHIRLPOOL_AC
|
||||
void sendWhirlpoolAC(unsigned char data[],
|
||||
uint16_t nbytes = kWhirlpoolAcStateLength,
|
||||
uint16_t repeat = kNoRepeat);
|
||||
#endif
|
||||
#if SEND_LUTRON
|
||||
void sendLutron(uint64_t data, uint16_t nbits = kLutronBits,
|
||||
uint16_t repeat = kNoRepeat);
|
||||
#endif
|
||||
#if SEND_ELECTRA_AC
|
||||
void sendElectraAC(unsigned char data[],
|
||||
uint16_t nbytes = kElectraAcStateLength,
|
||||
uint16_t repeat = kNoRepeat);
|
||||
#endif
|
||||
#if SEND_PANASONIC_AC
|
||||
void sendPanasonicAC(unsigned char data[],
|
||||
uint16_t nbytes = kPanasonicAcStateLength,
|
||||
uint16_t repeat = kNoRepeat);
|
||||
#endif
|
||||
#if SEND_PIONEER
|
||||
void sendPioneer(const uint64_t data, const uint16_t nbits = kPioneerBits,
|
||||
const uint16_t repeat = kNoRepeat);
|
||||
uint64_t encodePioneer(uint16_t address, uint16_t command);
|
||||
#endif
|
||||
#if SEND_MWM
|
||||
void sendMWM(unsigned char data[], uint16_t nbytes,
|
||||
uint16_t repeat = kNoRepeat);
|
||||
#endif
|
||||
|
||||
protected:
|
||||
|
||||
@@ -13,9 +13,7 @@ extern uint32_t _IRtimer_unittest_now;
|
||||
// This class performs a simple time in useconds since instantiated.
|
||||
// Handles when the system timer wraps around (once).
|
||||
|
||||
IRtimer::IRtimer() {
|
||||
reset();
|
||||
}
|
||||
IRtimer::IRtimer() { reset(); }
|
||||
|
||||
void IRtimer::reset() {
|
||||
#ifndef UNIT_TEST
|
||||
@@ -31,7 +29,7 @@ uint32_t IRtimer::elapsed() {
|
||||
#else
|
||||
uint32_t now = _IRtimer_unittest_now;
|
||||
#endif
|
||||
if (start <= now) // Check if the system timer has wrapped.
|
||||
if (start <= now) // Check if the system timer has wrapped.
|
||||
return now - start; // No wrap.
|
||||
else
|
||||
return UINT32_MAX - start + now; // Has wrapped.
|
||||
@@ -39,7 +37,5 @@ uint32_t IRtimer::elapsed() {
|
||||
|
||||
// Only used in unit testing.
|
||||
#ifdef UNIT_TEST
|
||||
void IRtimer::add(uint32_t usecs) {
|
||||
_IRtimer_unittest_now += usecs;
|
||||
}
|
||||
void IRtimer::add(uint32_t usecs) { _IRtimer_unittest_now += usecs; }
|
||||
#endif // UNIT_TEST
|
||||
|
||||
@@ -21,10 +21,9 @@
|
||||
// Returns:
|
||||
// The reversed bit pattern.
|
||||
uint64_t reverseBits(uint64_t input, uint16_t nbits) {
|
||||
if (nbits <= 1)
|
||||
return input; // Reversing <= 1 bits makes no change at all.
|
||||
if (nbits <= 1) return input; // Reversing <= 1 bits makes no change at all.
|
||||
// Cap the nr. of bits to rotate to the max nr. of bits in the input.
|
||||
nbits = std::min(nbits, (uint16_t) (sizeof(input) * 8));
|
||||
nbits = std::min(nbits, (uint16_t)(sizeof(input) * 8));
|
||||
uint64_t output = 0;
|
||||
for (uint16_t i = 0; i < nbits; i++) {
|
||||
output <<= 1;
|
||||
@@ -62,7 +61,7 @@ std::string uint64ToString(uint64_t input, uint8_t base) {
|
||||
input /= base;
|
||||
|
||||
if (c < 10)
|
||||
c +='0';
|
||||
c += '0';
|
||||
else
|
||||
c += 'A' - 10;
|
||||
result = c + result;
|
||||
@@ -92,58 +91,173 @@ void serialPrintUint64(uint64_t input, uint8_t base) {
|
||||
String typeToString(const decode_type_t protocol, const bool isRepeat) {
|
||||
String result = "";
|
||||
#else
|
||||
std::string typeToString(const decode_type_t protocol,
|
||||
const bool isRepeat) {
|
||||
std::string typeToString(const decode_type_t protocol, const bool isRepeat) {
|
||||
std::string result = "";
|
||||
#endif
|
||||
switch (protocol) {
|
||||
default:
|
||||
case UNKNOWN: result = "UNKNOWN"; break;
|
||||
case UNUSED: result = "UNUSED"; break;
|
||||
case AIWA_RC_T501: result = "AIWA_RC_T501"; break;
|
||||
case ARGO: result = "ARGO"; break;
|
||||
case CARRIER_AC: result = "CARRIER_AC"; break;
|
||||
case COOLIX: result = "COOLIX"; break;
|
||||
case DAIKIN: result = "DAIKIN"; break;
|
||||
case DENON: result = "DENON"; break;
|
||||
case DISH: result = "DISH"; break;
|
||||
case FUJITSU_AC: result = "FUJITSU_AC"; break;
|
||||
case GICABLE: result = "GICABLE"; break;
|
||||
case GLOBALCACHE: result = "GLOBALCACHE"; break;
|
||||
case GREE: result = "GREE"; break;
|
||||
case HAIER_AC: result = "HAIER_AC"; break;
|
||||
case HAIER_AC_YRW02: result = "HAIER_AC_YRW02"; break;
|
||||
case HITACHI_AC: result = "HITACHI_AC"; break;
|
||||
case HITACHI_AC1: result = "HITACHI_AC1"; break;
|
||||
case HITACHI_AC2: result = "HITACHI_AC2"; break;
|
||||
case JVC: result = "JVC"; break;
|
||||
case KELVINATOR: result = "KELVINATOR"; break;
|
||||
case LG: result = "LG"; break;
|
||||
case LASERTAG: result = "LASERTAG"; break;
|
||||
case MAGIQUEST: result = "MAGIQUEST"; break;
|
||||
case MIDEA: result = "MIDEA"; break;
|
||||
case MITSUBISHI: result = "MITSUBISHI"; break;
|
||||
case MITSUBISHI2: result = "MITSUBISHI2"; break;
|
||||
case MITSUBISHI_AC: result = "MITSUBISHI_AC"; break;
|
||||
case NEC: result = "NEC"; break;
|
||||
case NEC_LIKE: result = "NEC (non-strict)"; break;
|
||||
case NIKAI: result = "NIKAI"; break;
|
||||
case PANASONIC: result = "PANASONIC"; break;
|
||||
case PRONTO: result = "PRONTO"; break;
|
||||
case RAW: result = "RAW"; break;
|
||||
case RC5: result = "RC5"; break;
|
||||
case RC5X: result = "RC5X"; break;
|
||||
case RC6: result = "RC6"; break;
|
||||
case RCMM: result = "RCMM"; break;
|
||||
case SAMSUNG: result = "SAMSUNG"; break;
|
||||
case SANYO: result = "SANYO"; break;
|
||||
case SANYO_LC7461: result = "SANYO_LC7461"; break;
|
||||
case SHARP: result = "SHARP"; break;
|
||||
case SHERWOOD: result = "SHERWOOD"; break;
|
||||
case SONY: result = "SONY"; break;
|
||||
case TOSHIBA_AC: result = "TOSHIBA_AC"; break;
|
||||
case TROTEC: result = "TROTEC"; break;
|
||||
case WHYNTER: result = "WHYNTER"; break;
|
||||
case UNKNOWN:
|
||||
result = "UNKNOWN";
|
||||
break;
|
||||
case UNUSED:
|
||||
result = "UNUSED";
|
||||
break;
|
||||
case AIWA_RC_T501:
|
||||
result = "AIWA_RC_T501";
|
||||
break;
|
||||
case ARGO:
|
||||
result = "ARGO";
|
||||
break;
|
||||
case CARRIER_AC:
|
||||
result = "CARRIER_AC";
|
||||
break;
|
||||
case COOLIX:
|
||||
result = "COOLIX";
|
||||
break;
|
||||
case DAIKIN:
|
||||
result = "DAIKIN";
|
||||
break;
|
||||
case DENON:
|
||||
result = "DENON";
|
||||
break;
|
||||
case DISH:
|
||||
result = "DISH";
|
||||
break;
|
||||
case ELECTRA_AC:
|
||||
result = "ELECTRA_AC";
|
||||
break;
|
||||
case FUJITSU_AC:
|
||||
result = "FUJITSU_AC";
|
||||
break;
|
||||
case GICABLE:
|
||||
result = "GICABLE";
|
||||
break;
|
||||
case GLOBALCACHE:
|
||||
result = "GLOBALCACHE";
|
||||
break;
|
||||
case GREE:
|
||||
result = "GREE";
|
||||
break;
|
||||
case HAIER_AC:
|
||||
result = "HAIER_AC";
|
||||
break;
|
||||
case HAIER_AC_YRW02:
|
||||
result = "HAIER_AC_YRW02";
|
||||
break;
|
||||
case HITACHI_AC:
|
||||
result = "HITACHI_AC";
|
||||
break;
|
||||
case HITACHI_AC1:
|
||||
result = "HITACHI_AC1";
|
||||
break;
|
||||
case HITACHI_AC2:
|
||||
result = "HITACHI_AC2";
|
||||
break;
|
||||
case JVC:
|
||||
result = "JVC";
|
||||
break;
|
||||
case KELVINATOR:
|
||||
result = "KELVINATOR";
|
||||
break;
|
||||
case LG:
|
||||
result = "LG";
|
||||
break;
|
||||
case LG2:
|
||||
result = "LG2";
|
||||
break;
|
||||
case LASERTAG:
|
||||
result = "LASERTAG";
|
||||
break;
|
||||
case LUTRON:
|
||||
result = "LUTRON";
|
||||
break;
|
||||
case MAGIQUEST:
|
||||
result = "MAGIQUEST";
|
||||
break;
|
||||
case MIDEA:
|
||||
result = "MIDEA";
|
||||
break;
|
||||
case MITSUBISHI:
|
||||
result = "MITSUBISHI";
|
||||
break;
|
||||
case MITSUBISHI2:
|
||||
result = "MITSUBISHI2";
|
||||
break;
|
||||
case MITSUBISHI_AC:
|
||||
result = "MITSUBISHI_AC";
|
||||
break;
|
||||
case MWM:
|
||||
result = "MWM";
|
||||
break;
|
||||
case NEC:
|
||||
result = "NEC";
|
||||
break;
|
||||
case NEC_LIKE:
|
||||
result = "NEC (non-strict)";
|
||||
break;
|
||||
case NIKAI:
|
||||
result = "NIKAI";
|
||||
break;
|
||||
case PANASONIC:
|
||||
result = "PANASONIC";
|
||||
break;
|
||||
case PANASONIC_AC:
|
||||
result = "PANASONIC_AC";
|
||||
break;
|
||||
case PIONEER:
|
||||
result = "PIONEER";
|
||||
break;
|
||||
case PRONTO:
|
||||
result = "PRONTO";
|
||||
break;
|
||||
case RAW:
|
||||
result = "RAW";
|
||||
break;
|
||||
case RC5:
|
||||
result = "RC5";
|
||||
break;
|
||||
case RC5X:
|
||||
result = "RC5X";
|
||||
break;
|
||||
case RC6:
|
||||
result = "RC6";
|
||||
break;
|
||||
case RCMM:
|
||||
result = "RCMM";
|
||||
break;
|
||||
case SAMSUNG:
|
||||
result = "SAMSUNG";
|
||||
break;
|
||||
case SAMSUNG_AC:
|
||||
result = "SAMSUNG_AC";
|
||||
break;
|
||||
case SANYO:
|
||||
result = "SANYO";
|
||||
break;
|
||||
case SANYO_LC7461:
|
||||
result = "SANYO_LC7461";
|
||||
break;
|
||||
case SHARP:
|
||||
result = "SHARP";
|
||||
break;
|
||||
case SHERWOOD:
|
||||
result = "SHERWOOD";
|
||||
break;
|
||||
case SONY:
|
||||
result = "SONY";
|
||||
break;
|
||||
case TOSHIBA_AC:
|
||||
result = "TOSHIBA_AC";
|
||||
break;
|
||||
case TROTEC:
|
||||
result = "TROTEC";
|
||||
break;
|
||||
case WHIRLPOOL_AC:
|
||||
result = "WHIRLPOOL_AC";
|
||||
break;
|
||||
case WHYNTER:
|
||||
result = "WHYNTER";
|
||||
break;
|
||||
}
|
||||
if (isRepeat) result += " (Repeat)";
|
||||
return result;
|
||||
@@ -153,6 +267,7 @@ std::string typeToString(const decode_type_t protocol,
|
||||
bool hasACState(const decode_type_t protocol) {
|
||||
switch (protocol) {
|
||||
case DAIKIN:
|
||||
case ELECTRA_AC:
|
||||
case FUJITSU_AC:
|
||||
case GREE:
|
||||
case HAIER_AC:
|
||||
@@ -162,7 +277,11 @@ bool hasACState(const decode_type_t protocol) {
|
||||
case HITACHI_AC2:
|
||||
case KELVINATOR:
|
||||
case MITSUBISHI_AC:
|
||||
case MWM:
|
||||
case PANASONIC_AC:
|
||||
case SAMSUNG_AC:
|
||||
case TOSHIBA_AC:
|
||||
case WHIRLPOOL_AC:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
@@ -178,7 +297,7 @@ bool hasACState(const decode_type_t protocol) {
|
||||
uint16_t getCorrectedRawLength(const decode_results *results) {
|
||||
uint16_t extended_length = results->rawlen - 1;
|
||||
for (uint16_t i = 0; i < results->rawlen - 1; i++) {
|
||||
uint32_t usecs = results->rawbuf[i] * RAWTICK;
|
||||
uint32_t usecs = results->rawbuf[i] * kRawTick;
|
||||
// Add two extra entries for multiple larger than UINT16_MAX it is.
|
||||
extended_length += (usecs / (UINT16_MAX + 1)) * 2;
|
||||
}
|
||||
@@ -198,14 +317,13 @@ std::string resultToSourceCode(const decode_results *results) {
|
||||
output += "uint16_t "; // variable type
|
||||
output += "rawData["; // array name
|
||||
output += uint64ToString(getCorrectedRawLength(results), 10);
|
||||
// array size
|
||||
output += "] = {"; // Start declaration
|
||||
// array size
|
||||
output += "] = {"; // Start declaration
|
||||
|
||||
// Dump data
|
||||
for (uint16_t i = 1; i < results->rawlen; i++) {
|
||||
uint32_t usecs;
|
||||
for (usecs = results->rawbuf[i] * RAWTICK;
|
||||
usecs > UINT16_MAX;
|
||||
for (usecs = results->rawbuf[i] * kRawTick; usecs > UINT16_MAX;
|
||||
usecs -= UINT16_MAX) {
|
||||
output += uint64ToString(UINT16_MAX);
|
||||
if (i % 2)
|
||||
@@ -215,18 +333,18 @@ std::string resultToSourceCode(const decode_results *results) {
|
||||
}
|
||||
output += uint64ToString(usecs, 10);
|
||||
if (i < results->rawlen - 1)
|
||||
output += ", "; // ',' not needed on the last one
|
||||
if (i % 2 == 0) output += " "; // Extra if it was even.
|
||||
output += ", "; // ',' not needed on the last one
|
||||
if (i % 2 == 0) output += " "; // Extra if it was even.
|
||||
}
|
||||
|
||||
// End declaration
|
||||
output +="};";
|
||||
output += "};";
|
||||
|
||||
// Comment
|
||||
output += " // " + typeToString(results->decode_type, results->repeat);
|
||||
// Only display the value if the decode type doesn't have an A/C state.
|
||||
if (!hasACState(results->decode_type))
|
||||
output += " " + uint64ToString(results->value, 16);
|
||||
output += ' ' + uint64ToString(results->value, 16);
|
||||
output += "\n";
|
||||
|
||||
// Now dump "known" codes
|
||||
@@ -237,10 +355,9 @@ std::string resultToSourceCode(const decode_results *results) {
|
||||
output += "uint8_t state[" + uint64ToString(nbytes) + "] = {";
|
||||
for (uint16_t i = 0; i < nbytes; i++) {
|
||||
output += "0x";
|
||||
if (results->state[i] < 0x10) output += "0";
|
||||
if (results->state[i] < 0x10) output += "0";
|
||||
output += uint64ToString(results->state[i], 16);
|
||||
if (i < nbytes - 1)
|
||||
output += ", ";
|
||||
if (i < nbytes - 1) output += ", ";
|
||||
}
|
||||
output += "};\n";
|
||||
#endif // DECODE_AC
|
||||
@@ -256,8 +373,8 @@ std::string resultToSourceCode(const decode_results *results) {
|
||||
uint64ToString(results->command, 16) + ";\n";
|
||||
}
|
||||
// Most protocols have data
|
||||
output += "uint64_t data = 0x" + uint64ToString(results->value, 16) +
|
||||
";\n";
|
||||
output +=
|
||||
"uint64_t data = 0x" + uint64ToString(results->value, 16) + ";\n";
|
||||
}
|
||||
}
|
||||
return output;
|
||||
@@ -278,22 +395,42 @@ std::string resultToTimingInfo(const decode_results *results) {
|
||||
|
||||
for (uint16_t i = 1; i < results->rawlen; i++) {
|
||||
if (i % 2 == 0)
|
||||
output += "-"; // even
|
||||
output += '-'; // even
|
||||
else
|
||||
output += " +"; // odd
|
||||
value = uint64ToString(results->rawbuf[i] * RAWTICK);
|
||||
value = uint64ToString(results->rawbuf[i] * kRawTick);
|
||||
// Space pad the value till it is at least 6 chars long.
|
||||
while (value.length() < 6)
|
||||
value = " " + value;
|
||||
while (value.length() < 6) value = " " + value;
|
||||
output += value;
|
||||
if (i < results->rawlen - 1)
|
||||
output += ", "; // ',' not needed for last one
|
||||
if (!(i % 8)) output += "\n"; // Newline every 8 entries.
|
||||
if (i < results->rawlen - 1) output += ", "; // ',' not needed for last one
|
||||
if (!(i % 8)) output += "\n"; // Newline every 8 entries.
|
||||
}
|
||||
output += "\n";
|
||||
return output;
|
||||
}
|
||||
|
||||
// Convert the decode_results structure's value/state to simple hexadecimal.
|
||||
//
|
||||
#ifdef ARDUINO
|
||||
String resultToHexidecimal(const decode_results *result) {
|
||||
String output = "";
|
||||
#else
|
||||
std::string resultToHexidecimal(const decode_results *result) {
|
||||
std::string output = "";
|
||||
#endif
|
||||
if (hasACState(result->decode_type)) {
|
||||
#if DECODE_AC
|
||||
for (uint16_t i = 0; result->bits > i * 8; i++) {
|
||||
if (result->state[i] < 0x10) output += "0"; // Zero pad
|
||||
output += uint64ToString(result->state[i], 16);
|
||||
}
|
||||
#endif // DECODE_AC
|
||||
} else {
|
||||
output += uint64ToString(result->value, 16);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
// Dump out the decode_results structure.
|
||||
//
|
||||
#ifdef ARDUINO
|
||||
@@ -304,21 +441,13 @@ std::string resultToHumanReadableBasic(const decode_results *results) {
|
||||
std::string output = "";
|
||||
#endif
|
||||
// Show Encoding standard
|
||||
output += "Encoding : " +
|
||||
typeToString(results->decode_type, results->repeat) + "\n";
|
||||
output +=
|
||||
"Encoding : " + typeToString(results->decode_type, results->repeat) +
|
||||
"\n";
|
||||
|
||||
// Show Code & length
|
||||
output += "Code : ";
|
||||
if (hasACState(results->decode_type)) {
|
||||
#if DECODE_AC
|
||||
for (uint16_t i = 0; results->bits > i * 8; i++) {
|
||||
if (results->state[i] < 0x10) output += "0"; // Zero pad
|
||||
output += uint64ToString(results->state[i], 16);
|
||||
}
|
||||
#endif // DECODE_AC
|
||||
} else {
|
||||
output += uint64ToString(results->value, 16);
|
||||
}
|
||||
output += resultToHexidecimal(results);
|
||||
output += " (" + uint64ToString(results->bits) + " bits)\n";
|
||||
return output;
|
||||
}
|
||||
@@ -326,17 +455,16 @@ std::string resultToHumanReadableBasic(const decode_results *results) {
|
||||
uint8_t sumBytes(uint8_t *start, const uint16_t length, const uint8_t init) {
|
||||
uint8_t checksum = init;
|
||||
uint8_t *ptr;
|
||||
for (ptr = start; ptr - start < length; ptr++)
|
||||
checksum += *ptr;
|
||||
for (ptr = start; ptr - start < length; ptr++) checksum += *ptr;
|
||||
return checksum;
|
||||
}
|
||||
|
||||
uint64_t invertBits(const uint64_t data, const uint16_t nbits) {
|
||||
// No change if we are asked to invert no bits.
|
||||
if (nbits == 0) return data;
|
||||
if (nbits == 0) return data;
|
||||
uint64_t result = ~data;
|
||||
// If we are asked to invert all the bits or more than we have, it's simple.
|
||||
if (nbits >= sizeof(data) * 8) return result;
|
||||
if (nbits >= sizeof(data) * 8) return result;
|
||||
// Mask off any unwanted bits and return the result.
|
||||
return (result & ((1ULL << nbits) - 1));
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ void serialPrintUint64(uint64_t input, uint8_t base = 10);
|
||||
String resultToSourceCode(const decode_results *results);
|
||||
String resultToTimingInfo(const decode_results *results);
|
||||
String resultToHumanReadableBasic(const decode_results *results);
|
||||
String resultToHexidecimal(const decode_results *result);
|
||||
#else
|
||||
std::string uint64ToString(uint64_t input, uint8_t base = 10);
|
||||
std::string typeToString(const decode_type_t protocol,
|
||||
@@ -30,6 +31,7 @@ std::string typeToString(const decode_type_t protocol,
|
||||
std::string resultToSourceCode(const decode_results *results);
|
||||
std::string resultToTimingInfo(const decode_results *results);
|
||||
std::string resultToHumanReadableBasic(const decode_results *results);
|
||||
std::string resultToHexidecimal(const decode_results *result);
|
||||
#endif
|
||||
bool hasACState(const decode_type_t protocol);
|
||||
uint16_t getCorrectedRawLength(const decode_results *results);
|
||||
|
||||
@@ -13,12 +13,12 @@
|
||||
// Added by David Conran. (Inspired by IRremoteESP8266's implementation:
|
||||
// https://github.com/z3t0/Arduino-IRremote)
|
||||
|
||||
#define AIWA_RC_T501_PRE_BITS 26U
|
||||
#define AIWA_RC_T501_POST_BITS 1U
|
||||
const uint16_t kAiwaRcT501PreBits = 26;
|
||||
const uint16_t kAiwaRcT501PostBits = 1;
|
||||
// NOTE: These are the compliment (inverted) of lirc values as
|
||||
// lirc uses a '0' for a mark, and a '1' for a space.
|
||||
#define AIWA_RC_T501_PRE_DATA 0x1D8113FULL // 26-bits
|
||||
#define AIWA_RC_T501_POST_DATA 1ULL
|
||||
const uint64_t kAiwaRcT501PreData = 0x1D8113FULL; // 26-bits
|
||||
const uint64_t kAiwaRcT501PostData = 1ULL;
|
||||
|
||||
#if SEND_AIWA_RC_T501
|
||||
// Send an Aiwa RC T501 formatted message.
|
||||
@@ -26,7 +26,7 @@
|
||||
// Args:
|
||||
// data: The message to be sent.
|
||||
// nbits: The number of bits of the message to be sent.
|
||||
// Typically AIWA_RC_T501_BITS. Max is 37 = (64 - 27)
|
||||
// Typically kAiwaRcT501Bits. Max is 37 = (64 - 27)
|
||||
// repeat: The number of times the command is to be repeated.
|
||||
//
|
||||
// Status: BETA / Should work.
|
||||
@@ -37,10 +37,9 @@ void IRsend::sendAiwaRCT501(uint64_t data, uint16_t nbits, uint16_t repeat) {
|
||||
// Appears to be an extended NEC1 protocol. i.e. 42 bits instead of 32 bits.
|
||||
// So use sendNEC instead, however the twist is it has a fixed 26 bit
|
||||
// prefix, and a fixed postfix bit.
|
||||
uint64_t new_data = (
|
||||
(AIWA_RC_T501_PRE_DATA << (nbits + AIWA_RC_T501_POST_BITS)) |
|
||||
(data << AIWA_RC_T501_POST_BITS) | AIWA_RC_T501_POST_DATA);
|
||||
nbits += AIWA_RC_T501_PRE_BITS + AIWA_RC_T501_POST_BITS;
|
||||
uint64_t new_data = ((kAiwaRcT501PreData << (nbits + kAiwaRcT501PostBits)) |
|
||||
(data << kAiwaRcT501PostBits) | kAiwaRcT501PostData);
|
||||
nbits += kAiwaRcT501PreBits + kAiwaRcT501PostBits;
|
||||
if (nbits > sizeof(new_data) * 8)
|
||||
return; // We are overflowing. Abort, and don't send.
|
||||
sendNEC(new_data, nbits, repeat);
|
||||
@@ -52,7 +51,7 @@ void IRsend::sendAiwaRCT501(uint64_t data, uint16_t nbits, uint16_t repeat) {
|
||||
//
|
||||
// Args:
|
||||
// results: Ptr to the data to decode and where to store the decode result.
|
||||
// nbits: The number of data bits to expect. Typically AIWA_RC_T501_BITS.
|
||||
// nbits: The number of data bits to expect. Typically kAiwaRcT501Bits.
|
||||
// strict: Flag indicating if we should perform strict matching.
|
||||
// Returns:
|
||||
// boolean: True if it can decode it, false if it can't.
|
||||
@@ -71,12 +70,11 @@ void IRsend::sendAiwaRCT501(uint64_t data, uint16_t nbits, uint16_t repeat) {
|
||||
bool IRrecv::decodeAiwaRCT501(decode_results *results, uint16_t nbits,
|
||||
bool strict) {
|
||||
// Compliance
|
||||
if (strict && nbits != AIWA_RC_T501_BITS)
|
||||
if (strict && nbits != kAiwaRcT501Bits)
|
||||
return false; // Doesn't match our protocol defn.
|
||||
|
||||
// Add on the pre & post bits to our requested bit length.
|
||||
uint16_t expected_nbits = nbits + AIWA_RC_T501_PRE_BITS +
|
||||
AIWA_RC_T501_POST_BITS;
|
||||
uint16_t expected_nbits = nbits + kAiwaRcT501PreBits + kAiwaRcT501PostBits;
|
||||
uint64_t new_data;
|
||||
if (expected_nbits > sizeof(new_data) * 8)
|
||||
return false; // We can't possibly match something that big.
|
||||
@@ -88,24 +86,23 @@ bool IRrecv::decodeAiwaRCT501(decode_results *results, uint16_t nbits,
|
||||
new_data = results->value;
|
||||
if (actual_bits < expected_nbits)
|
||||
return false; // The data we caught was undersized. Throw it back.
|
||||
if ((new_data & 0x1ULL) != AIWA_RC_T501_POST_DATA)
|
||||
if ((new_data & 0x1ULL) != kAiwaRcT501PostData)
|
||||
return false; // The post data doesn't match, so it can't be this protocol.
|
||||
// Trim off the post data bit.
|
||||
new_data >>= AIWA_RC_T501_POST_BITS;
|
||||
actual_bits -= AIWA_RC_T501_POST_BITS;
|
||||
new_data >>= kAiwaRcT501PostBits;
|
||||
actual_bits -= kAiwaRcT501PostBits;
|
||||
|
||||
// Extract out our likely new value and put it back in the results.
|
||||
actual_bits -= AIWA_RC_T501_PRE_BITS;
|
||||
actual_bits -= kAiwaRcT501PreBits;
|
||||
results->value = new_data & ((1ULL << actual_bits) - 1);
|
||||
|
||||
// Check the prefix data matches.
|
||||
new_data >>= actual_bits; // Trim off the new data to expose the prefix.
|
||||
if (new_data != AIWA_RC_T501_PRE_DATA) // Check the prefix.
|
||||
if (new_data != kAiwaRcT501PreData) // Check the prefix.
|
||||
return false;
|
||||
|
||||
// Compliance
|
||||
if (strict && results->bits != expected_nbits)
|
||||
return false;
|
||||
if (strict && results->bits != expected_nbits) return false;
|
||||
|
||||
// Success
|
||||
results->decode_type = AIWA_RC_T501;
|
||||
|
||||
@@ -11,39 +11,33 @@ Copyright 2017 Schmolders
|
||||
|
||||
// Constants
|
||||
// using SPACE modulation. MARK is always const 400u
|
||||
#define ARGO_HDR_MARK 6400U // Mark
|
||||
#define ARGO_HDR_SPACE 3300U // Space
|
||||
#define ARGO_BIT_MARK 400U
|
||||
#define ARGO_ONE_SPACE 2200U
|
||||
#define ARGO_ZERO_SPACE 900U
|
||||
const uint16_t kArgoHdrMark = 6400;
|
||||
const uint16_t kArgoHdrSpace = 3300;
|
||||
const uint16_t kArgoBitMark = 400;
|
||||
const uint16_t kArgoOneSpace = 2200;
|
||||
const uint16_t kArgoZeroSpace = 900;
|
||||
|
||||
#if SEND_ARGO
|
||||
// Send an Argo A/C message.
|
||||
//
|
||||
// Args:
|
||||
// data: An array of ARGO_COMMAND_LENGTH bytes containing the IR command.
|
||||
// data: An array of kArgoStateLength bytes containing the IR command.
|
||||
//
|
||||
// Status: ALPHA / Untested.
|
||||
|
||||
void IRsend::sendArgo(unsigned char data[], uint16_t nbytes, uint16_t repeat) {
|
||||
// Check if we have enough bytes to send a proper message.
|
||||
if (nbytes < ARGO_COMMAND_LENGTH) return;
|
||||
if (nbytes < kArgoStateLength) return;
|
||||
// TODO(kaschmo): validate
|
||||
sendGeneric(ARGO_HDR_MARK, ARGO_HDR_SPACE,
|
||||
ARGO_BIT_MARK, ARGO_ONE_SPACE,
|
||||
ARGO_BIT_MARK, ARGO_ZERO_SPACE,
|
||||
0, 0, // No Footer.
|
||||
data, nbytes, 38, false, repeat, 50);
|
||||
sendGeneric(kArgoHdrMark, kArgoHdrSpace, kArgoBitMark, kArgoOneSpace,
|
||||
kArgoBitMark, kArgoZeroSpace, 0, 0, // No Footer.
|
||||
data, nbytes, 38, false, repeat, kDutyDefault);
|
||||
}
|
||||
#endif // SEND_ARGO
|
||||
|
||||
IRArgoAC::IRArgoAC(uint16_t pin) : _irsend(pin) {
|
||||
stateReset();
|
||||
}
|
||||
IRArgoAC::IRArgoAC(uint16_t pin) : _irsend(pin) { stateReset(); }
|
||||
|
||||
void IRArgoAC::begin() {
|
||||
_irsend.begin();
|
||||
}
|
||||
void IRArgoAC::begin() { _irsend.begin(); }
|
||||
|
||||
#if SEND_ARGO
|
||||
void IRArgoAC::send() {
|
||||
@@ -58,20 +52,18 @@ void IRArgoAC::checksum() {
|
||||
|
||||
// Only add up bytes to 9. byte 10 is 0b01 constant anyway.
|
||||
// Assume that argo array is MSB first (left)
|
||||
for (i = 0; i < 10; i++)
|
||||
sum += argo[i];
|
||||
for (i = 0; i < 10; i++) sum += argo[i];
|
||||
|
||||
sum = sum % 256; // modulo 256
|
||||
// Append sum to end of array
|
||||
// Set const part of checksum bit 10
|
||||
argo[10] = 0b00000010;
|
||||
argo[10] += sum << 2; // Shift up 2 bits and append to byte 10
|
||||
argo[11] = sum >> 6; // Shift down 6 bits and add in two LSBs of bit 11
|
||||
argo[11] = sum >> 6; // Shift down 6 bits and add in two LSBs of bit 11
|
||||
}
|
||||
|
||||
void IRArgoAC::stateReset() {
|
||||
for (uint8_t i = 0; i < ARGO_COMMAND_LENGTH; i++)
|
||||
argo[i] = 0x0;
|
||||
for (uint8_t i = 0; i < kArgoStateLength; i++) argo[i] = 0x0;
|
||||
|
||||
// Argo Message. Store MSB left.
|
||||
// Default message:
|
||||
@@ -84,8 +76,8 @@ void IRArgoAC::stateReset() {
|
||||
this->off();
|
||||
this->setTemp(20);
|
||||
this->setRoomTemp(25);
|
||||
this->setCoolMode(ARGO_COOL_AUTO);
|
||||
this->setFan(ARGO_FAN_AUTO);
|
||||
this->setCoolMode(kArgoCoolAuto);
|
||||
this->setFan(kArgoFanAuto);
|
||||
}
|
||||
|
||||
uint8_t* IRArgoAC::getRaw() {
|
||||
@@ -116,9 +108,7 @@ void IRArgoAC::setPower(bool state) {
|
||||
off();
|
||||
}
|
||||
|
||||
uint8_t IRArgoAC::getPower() {
|
||||
return ac_state;
|
||||
}
|
||||
uint8_t IRArgoAC::getPower() { return ac_state; }
|
||||
|
||||
void IRArgoAC::setMax(bool state) {
|
||||
max_mode = state;
|
||||
@@ -128,17 +118,15 @@ void IRArgoAC::setMax(bool state) {
|
||||
argo[9] &= 0b11110111;
|
||||
}
|
||||
|
||||
bool IRArgoAC::getMax() {
|
||||
return max_mode;
|
||||
}
|
||||
bool IRArgoAC::getMax() { return max_mode; }
|
||||
|
||||
// Set the temp in deg C
|
||||
// Sending 0 equals +4
|
||||
void IRArgoAC::setTemp(uint8_t temp) {
|
||||
if (temp < ARGO_MIN_TEMP)
|
||||
temp = ARGO_MIN_TEMP;
|
||||
else if (temp > ARGO_MAX_TEMP)
|
||||
temp = ARGO_MAX_TEMP;
|
||||
if (temp < kArgoMinTemp)
|
||||
temp = kArgoMinTemp;
|
||||
else if (temp > kArgoMaxTemp)
|
||||
temp = kArgoMaxTemp;
|
||||
|
||||
// Store in attributes
|
||||
set_temp = temp;
|
||||
@@ -154,9 +142,7 @@ void IRArgoAC::setTemp(uint8_t temp) {
|
||||
argo[3] += temp >> 2; // remove lowest to bits and append in 0-2
|
||||
}
|
||||
|
||||
uint8_t IRArgoAC::getTemp() {
|
||||
return set_temp;
|
||||
}
|
||||
uint8_t IRArgoAC::getTemp() { return set_temp; }
|
||||
|
||||
// Set the speed of the fan
|
||||
void IRArgoAC::setFan(uint8_t fan) {
|
||||
@@ -168,18 +154,14 @@ void IRArgoAC::setFan(uint8_t fan) {
|
||||
argo[3] += fan << 3;
|
||||
}
|
||||
|
||||
uint8_t IRArgoAC::getFan() {
|
||||
return fan_mode;
|
||||
}
|
||||
uint8_t IRArgoAC::getFan() { return fan_mode; }
|
||||
|
||||
void IRArgoAC::setFlap(uint8_t flap) {
|
||||
flap_mode = flap;
|
||||
// TODO(kaschmo): set correct bits for flap mode
|
||||
}
|
||||
|
||||
uint8_t IRArgoAC::getFlap() {
|
||||
return flap_mode;
|
||||
}
|
||||
uint8_t IRArgoAC::getFlap() { return flap_mode; }
|
||||
|
||||
uint8_t IRArgoAC::getMode() {
|
||||
// return cooling 0, heating 1
|
||||
@@ -196,9 +178,7 @@ void IRArgoAC::setCoolMode(uint8_t mode) {
|
||||
argo[2] += mode << 3;
|
||||
}
|
||||
|
||||
uint8_t IRArgoAC::getCoolMode() {
|
||||
return cool_mode;
|
||||
}
|
||||
uint8_t IRArgoAC::getCoolMode() { return cool_mode; }
|
||||
|
||||
void IRArgoAC::setHeatMode(uint8_t mode) {
|
||||
ac_mode = 1; // Set ac mode to heating
|
||||
@@ -211,9 +191,7 @@ void IRArgoAC::setHeatMode(uint8_t mode) {
|
||||
argo[2] += mode << 3;
|
||||
}
|
||||
|
||||
uint8_t IRArgoAC::getHeatMode() {
|
||||
return heat_mode;
|
||||
}
|
||||
uint8_t IRArgoAC::getHeatMode() { return heat_mode; }
|
||||
|
||||
void IRArgoAC::setNight(bool state) {
|
||||
night_mode = state;
|
||||
@@ -224,9 +202,7 @@ void IRArgoAC::setNight(bool state) {
|
||||
argo[9] &= 0b11111011;
|
||||
}
|
||||
|
||||
bool IRArgoAC::getNight() {
|
||||
return night_mode;
|
||||
}
|
||||
bool IRArgoAC::getNight() { return night_mode; }
|
||||
|
||||
void IRArgoAC::setiFeel(bool state) {
|
||||
ifeel_mode = state;
|
||||
@@ -237,9 +213,7 @@ void IRArgoAC::setiFeel(bool state) {
|
||||
argo[9] &= 0b01111111;
|
||||
}
|
||||
|
||||
bool IRArgoAC::getiFeel() {
|
||||
return ifeel_mode;
|
||||
}
|
||||
bool IRArgoAC::getiFeel() { return ifeel_mode; }
|
||||
|
||||
void IRArgoAC::setTime() {
|
||||
// TODO(kaschmo): use function call from checksum to set time first
|
||||
|
||||
@@ -29,32 +29,50 @@
|
||||
|
||||
// Constants. Store MSB left.
|
||||
|
||||
#define ARGO_COOL_ON 0U // 0b000
|
||||
#define ARGO_COOL_OFF 3U // 0b110
|
||||
#define ARGO_COOL_AUTO 2U // 0b010
|
||||
#define ARGO_COOl_HUM 1U // 0b100
|
||||
const uint8_t kArgoCoolOn = 0; // 0b000
|
||||
const uint8_t kArgoCoolOff = 3; // 0b110
|
||||
const uint8_t kArgoCoolAuto = 2; // 0b010
|
||||
const uint8_t kArgoCoolHum = 1; // 0b100
|
||||
const uint8_t kArgoHeatOn = 0; // 0b001
|
||||
const uint8_t kArgoHeatAuto = 1; // 0b101
|
||||
const uint8_t kArgoHeatBlink = 2; // 0b011 // ??no idea what mode that is
|
||||
const uint8_t kArgoMinTemp = 10; // Celsius offset +4
|
||||
const uint8_t kArgoMaxTemp = 32; // Celsius
|
||||
const uint8_t kArgoFanAuto = 0; // 0b00
|
||||
const uint8_t kArgoFan3 = 3; // 0b11
|
||||
const uint8_t kArgoFan2 = 2; // 0b01
|
||||
const uint8_t kArgoFan1 = 1; // 0b10
|
||||
const uint8_t kArgoFlapAuto = 0; // 0b000
|
||||
const uint8_t kArgoFlap1 = 1; // 0b100
|
||||
const uint8_t kArgoFlap2 = 2; // 0b010
|
||||
const uint8_t kArgoFlap3 = 3; // 0b110
|
||||
const uint8_t kArgoFlap4 = 4; // 0b001
|
||||
const uint8_t kArgoFlap5 = 5; // 0b101
|
||||
const uint8_t kArgoFlap6 = 6; // 0b011
|
||||
const uint8_t kArgoFlapFull = 7; // 0b111
|
||||
|
||||
#define ARGO_HEAT_ON 0U // 0b001
|
||||
#define ARGO_HEAT_AUTO 1U // 0b101
|
||||
#define ARGO_HEAT_BLINK 2U // 0b011 // ??no idea what mode that is
|
||||
|
||||
|
||||
#define ARGO_MIN_TEMP 10U // Celsius offset +4
|
||||
#define ARGO_MAX_TEMP 32U // Celsius
|
||||
|
||||
#define ARGO_FAN_AUTO 0U // 0b00
|
||||
#define ARGO_FAN_3 3U // 0b11
|
||||
#define ARGO_FAN_2 2U // 0b01
|
||||
#define ARGO_FAN_1 1U // 0b10
|
||||
|
||||
#define ARGO_FLAP_AUTO 0U // 0b000
|
||||
#define ARGO_FLAP_1 1U // 0b100
|
||||
#define ARGO_FLAP_2 2U // 0b010
|
||||
#define ARGO_FLAP_3 3U // 0b110
|
||||
#define ARGO_FLAP_4 4U // 0b001
|
||||
#define ARGO_FLAP_5 5U // 0b101
|
||||
#define ARGO_FLAP_6 6U // 0b011
|
||||
#define ARGO_FLAP_FULL 7U // 0b111
|
||||
// Legacy defines. (Deperecated)
|
||||
#define ARGO_COOL_ON kArgoCoolOn
|
||||
#define ARGO_COOL_OFF kArgoCoolOff
|
||||
#define ARGO_COOL_AUTO kArgoCoolAuto
|
||||
#define ARGO_COOl_HUM kArgoCoolHum
|
||||
#define ARGO_HEAT_ON kArgoHeatOn
|
||||
#define ARGO_HEAT_AUTO kArgoHeatAuto
|
||||
#define ARGO_HEAT_BLINK kArgoHeatBlink
|
||||
#define ARGO_MIN_TEMP kArgoMinTemp
|
||||
#define ARGO_MAX_TEMP kArgoMaxTemp
|
||||
#define ARGO_FAN_AUTO kArgoFanAuto
|
||||
#define ARGO_FAN_3 kArgoFan3
|
||||
#define ARGO_FAN_2 kArgoFan2
|
||||
#define ARGO_FAN_1 kArgoFan1
|
||||
#define ARGO_FLAP_AUTO kArgoFlapAuto
|
||||
#define ARGO_FLAP_1 kArgoFlap1
|
||||
#define ARGO_FLAP_2 kArgoFlap2
|
||||
#define ARGO_FLAP_3 kArgoFlap3
|
||||
#define ARGO_FLAP_4 kArgoFlap4
|
||||
#define ARGO_FLAP_5 kArgoFlap5
|
||||
#define ARGO_FLAP_6 kArgoFlap6
|
||||
#define ARGO_FLAP_FULL kArgoFlapFull
|
||||
|
||||
|
||||
class IRArgoAC {
|
||||
@@ -103,7 +121,7 @@ class IRArgoAC {
|
||||
|
||||
private:
|
||||
// # of bytes per command
|
||||
uint8_t argo[ARGO_COMMAND_LENGTH]; // Defined in IRremoteESP8266.h
|
||||
uint8_t argo[kArgoStateLength]; // Defined in IRremoteESP8266.h
|
||||
void stateReset();
|
||||
void checksum();
|
||||
IRsend _irsend; // instance of the IR send class
|
||||
|
||||
@@ -18,19 +18,19 @@
|
||||
// Constants
|
||||
// Ref:
|
||||
// https://github.com/markszabo/IRremoteESP8266/issues/385
|
||||
#define CARRIER_AC_HDR_MARK 8532U
|
||||
#define CARRIER_AC_HDR_SPACE 4228U
|
||||
#define CARRIER_AC_BIT_MARK 628U
|
||||
#define CARRIER_AC_ONE_SPACE 1320U
|
||||
#define CARRIER_AC_ZERO_SPACE 532U
|
||||
#define CARRIER_AC_GAP 20000U
|
||||
const uint16_t kCarrierAcHdrMark = 8532;
|
||||
const uint16_t kCarrierAcHdrSpace = 4228;
|
||||
const uint16_t kCarrierAcBitMark = 628;
|
||||
const uint16_t kCarrierAcOneSpace = 1320;
|
||||
const uint16_t kCarrierAcZeroSpace = 532;
|
||||
const uint16_t kCarrierAcGap = 20000;
|
||||
|
||||
#if SEND_CARRIER_AC
|
||||
// Send a Carrier HVAC formatted message.
|
||||
//
|
||||
// Args:
|
||||
// data: The message to be sent.
|
||||
// nbits: The bit size of the message being sent. typically CARRIER_AC_BITS.
|
||||
// nbits: The bit size of the message being sent. typically kCarrierAcBits.
|
||||
// repeat: The number of times the message is to be repeated.
|
||||
//
|
||||
// Status: BETA / Appears to work on real devices.
|
||||
@@ -40,11 +40,10 @@ void IRsend::sendCarrierAC(uint64_t data, uint16_t nbits, uint16_t repeat) {
|
||||
uint64_t temp_data = data;
|
||||
// Carrier sends the data block three times. normal + inverted + normal.
|
||||
for (uint16_t i = 0; i < 3; i++) {
|
||||
sendGeneric(CARRIER_AC_HDR_MARK, CARRIER_AC_HDR_SPACE,
|
||||
CARRIER_AC_BIT_MARK, CARRIER_AC_ONE_SPACE,
|
||||
CARRIER_AC_BIT_MARK, CARRIER_AC_ZERO_SPACE,
|
||||
CARRIER_AC_BIT_MARK, CARRIER_AC_GAP,
|
||||
temp_data, nbits, 38, true, 0, 50);
|
||||
sendGeneric(kCarrierAcHdrMark, kCarrierAcHdrSpace, kCarrierAcBitMark,
|
||||
kCarrierAcOneSpace, kCarrierAcBitMark, kCarrierAcZeroSpace,
|
||||
kCarrierAcBitMark, kCarrierAcGap, temp_data, nbits, 38, true,
|
||||
0, kDutyDefault);
|
||||
temp_data = invertBits(temp_data, nbits);
|
||||
}
|
||||
}
|
||||
@@ -58,7 +57,7 @@ void IRsend::sendCarrierAC(uint64_t data, uint16_t nbits, uint16_t repeat) {
|
||||
// Args:
|
||||
// results: Ptr to the data to decode and where to store the decode result.
|
||||
// nbits: Nr. of bits to expect in the data portion.
|
||||
// Typically CARRIER_AC_BITS.
|
||||
// Typically kCarrierAcBits.
|
||||
// strict: Flag to indicate if we strictly adhere to the specification.
|
||||
// Returns:
|
||||
// boolean: True if it can decode it, false if it can't.
|
||||
@@ -66,42 +65,38 @@ void IRsend::sendCarrierAC(uint64_t data, uint16_t nbits, uint16_t repeat) {
|
||||
// Status: ALPHA / Untested.
|
||||
//
|
||||
bool IRrecv::decodeCarrierAC(decode_results *results, uint16_t nbits,
|
||||
bool strict) {
|
||||
if (results->rawlen < ((2 * nbits + HEADER + FOOTER) * 3) - 1)
|
||||
bool strict) {
|
||||
if (results->rawlen < ((2 * nbits + kHeader + kFooter) * 3) - 1)
|
||||
return false; // Can't possibly be a valid Carrier message.
|
||||
if (strict && nbits != CARRIER_AC_BITS)
|
||||
if (strict && nbits != kCarrierAcBits)
|
||||
return false; // We expect Carrier to be 32 bits of message.
|
||||
|
||||
uint64_t data = 0;
|
||||
uint64_t prev_data = 0;
|
||||
uint16_t offset = OFFSET_START;
|
||||
uint16_t offset = kStartOffset;
|
||||
|
||||
for (uint8_t i = 0; i < 3; i++) {
|
||||
prev_data = data;
|
||||
// Header
|
||||
if (!matchMark(results->rawbuf[offset++], CARRIER_AC_HDR_MARK))
|
||||
return false;
|
||||
if (!matchSpace(results->rawbuf[offset++], CARRIER_AC_HDR_SPACE))
|
||||
if (!matchMark(results->rawbuf[offset++], kCarrierAcHdrMark)) return false;
|
||||
if (!matchSpace(results->rawbuf[offset++], kCarrierAcHdrSpace))
|
||||
return false;
|
||||
// Data
|
||||
match_result_t data_result = matchData(&(results->rawbuf[offset]), nbits,
|
||||
CARRIER_AC_BIT_MARK,
|
||||
CARRIER_AC_ONE_SPACE,
|
||||
CARRIER_AC_BIT_MARK,
|
||||
CARRIER_AC_ZERO_SPACE);
|
||||
match_result_t data_result =
|
||||
matchData(&(results->rawbuf[offset]), nbits, kCarrierAcBitMark,
|
||||
kCarrierAcOneSpace, kCarrierAcBitMark, kCarrierAcZeroSpace);
|
||||
if (data_result.success == false) return false;
|
||||
data = data_result.data;
|
||||
offset += data_result.used;
|
||||
// Footer
|
||||
if (!matchMark(results->rawbuf[offset++], CARRIER_AC_BIT_MARK))
|
||||
return false;
|
||||
if (!matchMark(results->rawbuf[offset++], kCarrierAcBitMark)) return false;
|
||||
if (offset < results->rawlen &&
|
||||
!matchAtLeast(results->rawbuf[offset++], CARRIER_AC_GAP))
|
||||
!matchAtLeast(results->rawbuf[offset++], kCarrierAcGap))
|
||||
return false;
|
||||
// Compliance.
|
||||
if (strict) {
|
||||
// Check if the data is an inverted copy of the previous data.
|
||||
if (i > 0 && prev_data != invertBits(data, nbits)) return false;
|
||||
if (i > 0 && prev_data != invertBits(data, nbits)) return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
// Copyright bakrus
|
||||
// Copyright 2017 David Conran
|
||||
|
||||
#include "ir_Coolix.h"
|
||||
#include <algorithm>
|
||||
#ifndef ARDUINO
|
||||
#include <string>
|
||||
#endif
|
||||
#include "IRrecv.h"
|
||||
#include "IRsend.h"
|
||||
#include "IRutils.h"
|
||||
@@ -12,32 +17,36 @@
|
||||
// CCCCC OOOO0 OOOO0 LLLLLLL IIIII XX XX
|
||||
|
||||
// Coolix A/C / heatpump added by (send) bakrus & (decode) crankyoldgit
|
||||
//
|
||||
// Supports:
|
||||
// RG57K7(B)/BGEF remote control for Beko BINR 070/071 split-type aircon.
|
||||
// Ref:
|
||||
// https://github.com/markszabo/IRremoteESP8266/issues/484
|
||||
|
||||
// Constants
|
||||
// Pulse parms are *50-100 for the Mark and *50+100 for the space
|
||||
// First MARK is the one after the long gap
|
||||
// pulse parameters in usec
|
||||
#define COOLIX_TICK 560U // Approximately 21 cycles at 38kHz
|
||||
#define COOLIX_BIT_MARK_TICKS 1U
|
||||
#define COOLIX_BIT_MARK (COOLIX_BIT_MARK_TICKS * COOLIX_TICK)
|
||||
#define COOLIX_ONE_SPACE_TICKS 3U
|
||||
#define COOLIX_ONE_SPACE (COOLIX_ONE_SPACE_TICKS * COOLIX_TICK)
|
||||
#define COOLIX_ZERO_SPACE_TICKS 1U
|
||||
#define COOLIX_ZERO_SPACE (COOLIX_ZERO_SPACE_TICKS * COOLIX_TICK)
|
||||
#define COOLIX_HDR_MARK_TICKS 8U
|
||||
#define COOLIX_HDR_MARK (COOLIX_HDR_MARK_TICKS * COOLIX_TICK)
|
||||
#define COOLIX_HDR_SPACE_TICKS 8U
|
||||
#define COOLIX_HDR_SPACE (COOLIX_HDR_SPACE_TICKS * COOLIX_TICK)
|
||||
#define COOLIX_MIN_GAP_TICKS (COOLIX_HDR_MARK_TICKS + \
|
||||
COOLIX_ZERO_SPACE_TICKS)
|
||||
#define COOLIX_MIN_GAP (COOLIX_MIN_GAP_TICKS * COOLIX_TICK)
|
||||
const uint16_t kCoolixTick = 560; // Approximately 21 cycles at 38kHz
|
||||
const uint16_t kCoolixBitMarkTicks = 1;
|
||||
const uint16_t kCoolixBitMark = kCoolixBitMarkTicks * kCoolixTick;
|
||||
const uint16_t kCoolixOneSpaceTicks = 3;
|
||||
const uint16_t kCoolixOneSpace = kCoolixOneSpaceTicks * kCoolixTick;
|
||||
const uint16_t kCoolixZeroSpaceTicks = 1;
|
||||
const uint16_t kCoolixZeroSpace = kCoolixZeroSpaceTicks * kCoolixTick;
|
||||
const uint16_t kCoolixHdrMarkTicks = 8;
|
||||
const uint16_t kCoolixHdrMark = kCoolixHdrMarkTicks * kCoolixTick;
|
||||
const uint16_t kCoolixHdrSpaceTicks = 8;
|
||||
const uint16_t kCoolixHdrSpace = kCoolixHdrSpaceTicks * kCoolixTick;
|
||||
const uint16_t kCoolixMinGapTicks = kCoolixHdrMarkTicks + kCoolixZeroSpaceTicks;
|
||||
const uint16_t kCoolixMinGap = kCoolixMinGapTicks * kCoolixTick;
|
||||
|
||||
#if SEND_COOLIX
|
||||
// Send a Coolix message
|
||||
//
|
||||
// Args:
|
||||
// data: Contents of the message to be sent.
|
||||
// nbits: Nr. of bits of data to be sent. Typically COOLIX_BITS.
|
||||
// nbits: Nr. of bits of data to be sent. Typically kCoolixBits.
|
||||
// repeat: Nr. of additional times the message is to be sent.
|
||||
//
|
||||
// Status: BETA / Probably works.
|
||||
@@ -46,16 +55,15 @@
|
||||
// https://github.com/z3t0/Arduino-IRremote/blob/master/ir_COOLIX.cpp
|
||||
// TODO(anyone): Verify repeat functionality against a real unit.
|
||||
void IRsend::sendCOOLIX(uint64_t data, uint16_t nbits, uint16_t repeat) {
|
||||
if (nbits % 8 != 0)
|
||||
return; // nbits is required to be a multiple of 8.
|
||||
if (nbits % 8 != 0) return; // nbits is required to be a multiple of 8.
|
||||
|
||||
// Set IR carrier frequency
|
||||
enableIROut(38);
|
||||
|
||||
for (uint16_t r = 0; r <= repeat; r++) {
|
||||
// Header
|
||||
mark(COOLIX_HDR_MARK);
|
||||
space(COOLIX_HDR_SPACE);
|
||||
mark(kCoolixHdrMark);
|
||||
space(kCoolixHdrSpace);
|
||||
|
||||
// Data
|
||||
// Break data into byte segments, starting at the Most Significant
|
||||
@@ -64,28 +72,279 @@ void IRsend::sendCOOLIX(uint64_t data, uint16_t nbits, uint16_t repeat) {
|
||||
// Grab a bytes worth of data.
|
||||
uint8_t segment = (data >> (nbits - i)) & 0xFF;
|
||||
// Normal
|
||||
sendData(COOLIX_BIT_MARK, COOLIX_ONE_SPACE,
|
||||
COOLIX_BIT_MARK, COOLIX_ZERO_SPACE,
|
||||
segment, 8, true);
|
||||
sendData(kCoolixBitMark, kCoolixOneSpace, kCoolixBitMark,
|
||||
kCoolixZeroSpace, segment, 8, true);
|
||||
// Inverted.
|
||||
sendData(COOLIX_BIT_MARK, COOLIX_ONE_SPACE,
|
||||
COOLIX_BIT_MARK, COOLIX_ZERO_SPACE,
|
||||
segment ^ 0xFF, 8, true);
|
||||
sendData(kCoolixBitMark, kCoolixOneSpace, kCoolixBitMark,
|
||||
kCoolixZeroSpace, segment ^ 0xFF, 8, true);
|
||||
}
|
||||
|
||||
// Footer
|
||||
mark(COOLIX_BIT_MARK);
|
||||
space(COOLIX_MIN_GAP); // Pause before repeating
|
||||
mark(kCoolixBitMark);
|
||||
space(kCoolixMinGap); // Pause before repeating
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// IRCoolixAC class
|
||||
// Supports:
|
||||
// RG57K7(B)/BGEF remote control for Beko BINR 070/071 split-type aircon.
|
||||
// Ref:
|
||||
// https://github.com/markszabo/IRremoteESP8266/issues/484
|
||||
IRCoolixAC::IRCoolixAC(uint16_t pin) : _irsend(pin) { stateReset(); }
|
||||
|
||||
void IRCoolixAC::stateReset() { remote_state = kCoolixDefaultState; }
|
||||
|
||||
void IRCoolixAC::begin() { _irsend.begin(); }
|
||||
|
||||
#if SEND_COOLIX
|
||||
void IRCoolixAC::send() { _irsend.sendCOOLIX(remote_state); }
|
||||
#endif // SEND_COOLIX
|
||||
|
||||
uint32_t IRCoolixAC::getRaw() { return remote_state; }
|
||||
|
||||
void IRCoolixAC::setRaw(const uint32_t new_code) { remote_state = new_code; }
|
||||
|
||||
void IRCoolixAC::setTempRaw(const uint8_t code) {
|
||||
remote_state &= ~kCoolixTempMask; // Clear the old temp.
|
||||
remote_state |= (code << 4);
|
||||
}
|
||||
|
||||
uint8_t IRCoolixAC::getTempRaw() {
|
||||
return (remote_state & kCoolixTempMask) >> 4;
|
||||
}
|
||||
|
||||
void IRCoolixAC::setTemp(const uint8_t desired) {
|
||||
// Range check.
|
||||
uint8_t temp = std::min(desired, kCoolixTempMax);
|
||||
temp = std::max(temp, kCoolixTempMin);
|
||||
setTempRaw(kCoolixTempMap[temp - kCoolixTempMin]);
|
||||
}
|
||||
|
||||
uint8_t IRCoolixAC::getTemp() {
|
||||
uint8_t code = getTempRaw();
|
||||
uint8_t i;
|
||||
for (i = 0; i < kCoolixTempRange; i++)
|
||||
if (kCoolixTempMap[i] == code) return kCoolixTempMin + i;
|
||||
return kCoolixUnknown; // Not a temp we expected.
|
||||
}
|
||||
|
||||
void IRCoolixAC::setSensorTempRaw(const uint8_t code) {
|
||||
remote_state &= ~kCoolixSensorTempMask; // Clear previous sensor temp.
|
||||
remote_state |= ((code & 0xF) << 8);
|
||||
}
|
||||
|
||||
void IRCoolixAC::setSensorTemp(const uint8_t desired) {
|
||||
uint8_t temp = desired;
|
||||
temp = std::min(temp, kCoolixSensorTempMax);
|
||||
temp = std::max(temp, kCoolixSensorTempMin);
|
||||
setSensorTempRaw(temp - kCoolixSensorTempMin);
|
||||
setZoneFollow(true); // Setting a Sensor temp means you want to Zone Follow.
|
||||
}
|
||||
|
||||
uint8_t IRCoolixAC::getSensorTemp() {
|
||||
return ((remote_state & kCoolixSensorTempMask) >> 8) + kCoolixSensorTempMin;
|
||||
}
|
||||
|
||||
bool IRCoolixAC::getPower() {
|
||||
// There is only an off state. Everything else is "on".
|
||||
return remote_state != kCoolixOff;
|
||||
}
|
||||
|
||||
void IRCoolixAC::setPower(const bool power) {
|
||||
if (!power) remote_state = kCoolixOff;
|
||||
// There really is no distinct "on" setting, so do nothing.
|
||||
}
|
||||
|
||||
bool IRCoolixAC::getSwing() { return remote_state == kCoolixSwing; }
|
||||
|
||||
void IRCoolixAC::setSwing() {
|
||||
// Assumes that repeated sending "swing" toggles the action on the device.
|
||||
remote_state = kCoolixSwing;
|
||||
}
|
||||
|
||||
bool IRCoolixAC::getSleep() { return remote_state == kCoolixSleep; }
|
||||
|
||||
void IRCoolixAC::setSleep() { remote_state = kCoolixSleep; }
|
||||
|
||||
bool IRCoolixAC::getTurbo() { return remote_state == kCoolixTurbo; }
|
||||
|
||||
void IRCoolixAC::setTurbo() {
|
||||
// Assumes that repeated sending "turbo" toggles the action on the device.
|
||||
remote_state = kCoolixTurbo;
|
||||
}
|
||||
|
||||
bool IRCoolixAC::getLed() { return remote_state == kCoolixLed; }
|
||||
|
||||
void IRCoolixAC::setLed() {
|
||||
// Assumes that repeated sending "Led" toggles the action on the device.
|
||||
remote_state = kCoolixLed;
|
||||
}
|
||||
|
||||
bool IRCoolixAC::getClean() { return remote_state == kCoolixClean; }
|
||||
|
||||
void IRCoolixAC::setClean() { remote_state = kCoolixClean; }
|
||||
|
||||
bool IRCoolixAC::getZoneFollow() {
|
||||
return remote_state & kCoolixZoneFollowMask;
|
||||
}
|
||||
|
||||
// Internal use only.
|
||||
void IRCoolixAC::setZoneFollow(bool state) {
|
||||
if (state) {
|
||||
remote_state |= kCoolixZoneFollowMask;
|
||||
} else {
|
||||
remote_state &= ~kCoolixZoneFollowMask;
|
||||
}
|
||||
}
|
||||
|
||||
void IRCoolixAC::clearSensorTemp() {
|
||||
setZoneFollow(false);
|
||||
setSensorTempRaw(kCoolixSensorTempIgnoreCode);
|
||||
}
|
||||
|
||||
void IRCoolixAC::setMode(const uint8_t mode) {
|
||||
uint32_t actualmode = mode;
|
||||
// Fan mode is a special case of Dry.
|
||||
if (mode == kCoolixFan) actualmode = kCoolixDry;
|
||||
switch (actualmode) {
|
||||
case kCoolixCool:
|
||||
case kCoolixAuto:
|
||||
case kCoolixHeat:
|
||||
case kCoolixDry:
|
||||
remote_state = (remote_state & ~kCoolixModeMask) | (actualmode << 2);
|
||||
// Force the temp into a known-good state.
|
||||
setTemp(getTemp());
|
||||
}
|
||||
if (mode == kCoolixFan) setTempRaw(kCoolixFanTempCode);
|
||||
}
|
||||
|
||||
uint8_t IRCoolixAC::getMode() {
|
||||
uint8_t mode = (remote_state & kCoolixModeMask) >> 2;
|
||||
if (mode == kCoolixDry)
|
||||
if (getTempRaw() == kCoolixFanTempCode) return kCoolixFan;
|
||||
return mode;
|
||||
}
|
||||
|
||||
uint8_t IRCoolixAC::getFan() { return (remote_state & kCoolixFanMask) >> 13; }
|
||||
|
||||
void IRCoolixAC::setFan(const uint8_t speed) {
|
||||
uint8_t newspeed = speed;
|
||||
switch (speed) {
|
||||
case kCoolixFanMin:
|
||||
case kCoolixFanMed:
|
||||
case kCoolixFanMax:
|
||||
case kCoolixFanAuto:
|
||||
case kCoolixFanZoneFollow:
|
||||
case kCoolixFanFixed:
|
||||
break;
|
||||
default: // Unknown speed requested.
|
||||
newspeed = kCoolixFanAuto;
|
||||
}
|
||||
remote_state &= ~kCoolixFanMask;
|
||||
remote_state |= ((newspeed << 13) & kCoolixFanMask);
|
||||
}
|
||||
|
||||
// Convert the internal state into a human readable string.
|
||||
#ifdef ARDUINO
|
||||
String IRCoolixAC::toString() {
|
||||
String result = "";
|
||||
#else
|
||||
std::string IRCoolixAC::toString() {
|
||||
std::string result = "";
|
||||
#endif // ARDUINO
|
||||
result += "Power: ";
|
||||
if (getPower()) {
|
||||
result += "On";
|
||||
} else {
|
||||
result += "Off";
|
||||
return result; // If it's off, there is no other info.
|
||||
}
|
||||
result += ", Fan: " + uint64ToString(getFan());
|
||||
switch (getFan()) {
|
||||
case kCoolixFanAuto:
|
||||
result += " (AUTO)";
|
||||
break;
|
||||
case kCoolixFanMax:
|
||||
result += " (MAX)";
|
||||
break;
|
||||
case kCoolixFanMin:
|
||||
result += " (MIN)";
|
||||
break;
|
||||
case kCoolixFanMed:
|
||||
result += " (MED)";
|
||||
break;
|
||||
case kCoolixFanZoneFollow:
|
||||
result += " (ZONEFOLLOW)";
|
||||
break;
|
||||
case kCoolixFanFixed:
|
||||
result += " (FIXED)";
|
||||
break;
|
||||
default:
|
||||
result += " (UNKNOWN)";
|
||||
}
|
||||
// Special modes.
|
||||
if (getSwing()) {
|
||||
result += ", Swing: Toggle";
|
||||
return result;
|
||||
}
|
||||
if (getSleep()) {
|
||||
result += ", Sleep: Toggle";
|
||||
return result;
|
||||
}
|
||||
if (getTurbo()) {
|
||||
result += ", Turbo: Toggle";
|
||||
return result;
|
||||
}
|
||||
if (getLed()) {
|
||||
result += ", Led: Toggle";
|
||||
return result;
|
||||
}
|
||||
if (getClean()) {
|
||||
result += ", Mode: Self clean";
|
||||
return result;
|
||||
}
|
||||
result += ", Mode: " + uint64ToString(getMode());
|
||||
switch (getMode()) {
|
||||
case kCoolixAuto:
|
||||
result += " (AUTO)";
|
||||
break;
|
||||
case kCoolixCool:
|
||||
result += " (COOL)";
|
||||
break;
|
||||
case kCoolixHeat:
|
||||
result += " (HEAT)";
|
||||
break;
|
||||
case kCoolixDry:
|
||||
result += " (DRY)";
|
||||
break;
|
||||
case kCoolixFan:
|
||||
result += " (FAN)";
|
||||
break;
|
||||
default:
|
||||
result += " (UNKNOWN)";
|
||||
}
|
||||
if (getMode() != kCoolixFan) // Fan mode doesn't have a temperature.
|
||||
result += ", Temp: " + uint64ToString(getTemp()) + "C";
|
||||
result += ", Zone Follow: ";
|
||||
if (getZoneFollow())
|
||||
result += "On";
|
||||
else
|
||||
result += "Off";
|
||||
result += ", Sensor Temp: ";
|
||||
if (getSensorTemp() > kCoolixSensorTempMax)
|
||||
result += "Ignored";
|
||||
else
|
||||
result += uint64ToString(getSensorTemp()) + "C";
|
||||
return result;
|
||||
}
|
||||
|
||||
#if DECODE_COOLIX
|
||||
// Decode the supplied Coolix message.
|
||||
//
|
||||
// Args:
|
||||
// results: Ptr to the data to decode and where to store the decode result.
|
||||
// nbits: The number of data bits to expect. Typically COOLIX_BITS.
|
||||
// nbits: The number of data bits to expect. Typically kCoolixBits.
|
||||
// strict: Flag indicating if we should perform strict matching.
|
||||
// Returns:
|
||||
// boolean: True if it can decode it, false if it can't.
|
||||
@@ -95,42 +354,41 @@ bool IRrecv::decodeCOOLIX(decode_results *results, uint16_t nbits,
|
||||
bool strict) {
|
||||
// The protocol sends the data normal + inverted, alternating on
|
||||
// each byte. Hence twice the number of expected data bits.
|
||||
if (results->rawlen < 2 * 2 * nbits + HEADER + FOOTER - 1)
|
||||
if (results->rawlen < 2 * 2 * nbits + kHeader + kFooter - 1)
|
||||
return false; // Can't possibly be a valid COOLIX message.
|
||||
if (strict && nbits != COOLIX_BITS)
|
||||
return false; // Not strictly a COOLIX message.
|
||||
if (strict && nbits != kCoolixBits)
|
||||
return false; // Not strictly a COOLIX message.
|
||||
if (nbits % 8 != 0) // nbits has to be a multiple of nr. of bits in a byte.
|
||||
return false;
|
||||
|
||||
uint64_t data = 0;
|
||||
uint64_t inverted = 0;
|
||||
uint16_t offset = OFFSET_START;
|
||||
uint16_t offset = kStartOffset;
|
||||
|
||||
if (nbits > sizeof(data) * 8)
|
||||
return false; // We can't possibly capture a Coolix packet that big.
|
||||
|
||||
// Header
|
||||
if (!matchMark(results->rawbuf[offset], COOLIX_HDR_MARK)) return false;
|
||||
if (!matchMark(results->rawbuf[offset], kCoolixHdrMark)) return false;
|
||||
// Calculate how long the common tick time is based on the header mark.
|
||||
uint32_t m_tick = results->rawbuf[offset++] * RAWTICK / COOLIX_HDR_MARK_TICKS;
|
||||
if (!matchSpace(results->rawbuf[offset], COOLIX_HDR_SPACE)) return false;
|
||||
uint32_t m_tick = results->rawbuf[offset++] * kRawTick / kCoolixHdrMarkTicks;
|
||||
if (!matchSpace(results->rawbuf[offset], kCoolixHdrSpace)) return false;
|
||||
// Calculate how long the common tick time is based on the header space.
|
||||
uint32_t s_tick = results->rawbuf[offset++] * RAWTICK /
|
||||
COOLIX_HDR_SPACE_TICKS;
|
||||
uint32_t s_tick = results->rawbuf[offset++] * kRawTick / kCoolixHdrSpaceTicks;
|
||||
|
||||
// Data
|
||||
// Twice as many bits as there are normal plus inverted bits.
|
||||
for (uint16_t i = 0; i < nbits * 2; i++, offset++) {
|
||||
bool flip = (i / 8) % 2;
|
||||
if (!matchMark(results->rawbuf[offset++], COOLIX_BIT_MARK_TICKS * m_tick))
|
||||
if (!matchMark(results->rawbuf[offset++], kCoolixBitMarkTicks * m_tick))
|
||||
return false;
|
||||
if (matchSpace(results->rawbuf[offset], COOLIX_ONE_SPACE_TICKS * s_tick)) {
|
||||
if (matchSpace(results->rawbuf[offset], kCoolixOneSpaceTicks * s_tick)) {
|
||||
if (flip)
|
||||
inverted = (inverted << 1) | 1;
|
||||
else
|
||||
data = (data << 1) | 1;
|
||||
} else if (matchSpace(results->rawbuf[offset],
|
||||
COOLIX_ZERO_SPACE_TICKS * s_tick)) {
|
||||
kCoolixZeroSpaceTicks * s_tick)) {
|
||||
if (flip)
|
||||
inverted <<= 1;
|
||||
else
|
||||
@@ -141,18 +399,17 @@ bool IRrecv::decodeCOOLIX(decode_results *results, uint16_t nbits,
|
||||
}
|
||||
|
||||
// Footer
|
||||
if (!matchMark(results->rawbuf[offset++], COOLIX_BIT_MARK_TICKS * m_tick))
|
||||
if (!matchMark(results->rawbuf[offset++], kCoolixBitMarkTicks * m_tick))
|
||||
return false;
|
||||
if (offset < results->rawlen &&
|
||||
!matchAtLeast(results->rawbuf[offset], COOLIX_MIN_GAP_TICKS * s_tick))
|
||||
!matchAtLeast(results->rawbuf[offset], kCoolixMinGapTicks * s_tick))
|
||||
return false;
|
||||
|
||||
// Compliance
|
||||
uint64_t orig = data; // Save a copy of the data.
|
||||
if (strict) {
|
||||
for (uint16_t i = 0; i < nbits; i += 8, data >>= 8, inverted >>= 8)
|
||||
if ((data & 0xFF) != ((inverted & 0xFF) ^ 0xFF))
|
||||
return false;
|
||||
if ((data & 0xFF) != ((inverted & 0xFF) ^ 0xFF)) return false;
|
||||
}
|
||||
|
||||
// Success
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
// Coolix A/C
|
||||
//
|
||||
// Copyright 2018 David Conran
|
||||
|
||||
#ifndef IR_COOLIX_H_
|
||||
#define IR_COOLIX_H_
|
||||
|
||||
#define __STDC_LIMIT_MACROS
|
||||
#include <stdint.h>
|
||||
#ifndef UNIT_TEST
|
||||
#include <Arduino.h>
|
||||
#else
|
||||
#include <string>
|
||||
#endif
|
||||
#include "IRremoteESP8266.h"
|
||||
#include "IRsend.h"
|
||||
|
||||
// CCCCC OOOOO OOOOO LL IIIII XX XX
|
||||
// CC C OO OO OO OO LL III XX XX
|
||||
// CC OO OO OO OO LL III XXXX
|
||||
// CC C OO OO OO OO LL III XX XX
|
||||
// CCCCC OOOO0 OOOO0 LLLLLLL IIIII XX XX
|
||||
|
||||
// Supports:
|
||||
// RG57K7(B)/BGEF remote control for Beko BINR 070/071 split-type aircon.
|
||||
// Ref:
|
||||
// https://github.com/markszabo/IRremoteESP8266/issues/484
|
||||
// Kudos:
|
||||
// Hamper: For the breakdown and mapping of the bit values.
|
||||
|
||||
// Constants
|
||||
// Modes
|
||||
const uint8_t kCoolixCool = 0b00;
|
||||
const uint8_t kCoolixDry = 0b01;
|
||||
const uint8_t kCoolixAuto = 0b10;
|
||||
const uint8_t kCoolixHeat = 0b11;
|
||||
const uint8_t kCoolixFan = 4; // Synthetic.
|
||||
const uint32_t kCoolixModeMask = 0b000000000000000000001100; // 0xC
|
||||
const uint32_t kCoolixZoneFollowMask = 0b000010000000000000000000; // 0x80000
|
||||
// Fan Control
|
||||
const uint8_t kCoolixFanMin = 0b100;
|
||||
const uint8_t kCoolixFanMed = 0b010;
|
||||
const uint8_t kCoolixFanMax = 0b001;
|
||||
const uint8_t kCoolixFanAuto = 0b101;
|
||||
const uint8_t kCoolixFanZoneFollow = 0b110;
|
||||
const uint8_t kCoolixFanFixed = 0b111;
|
||||
const uint32_t kCoolixFanMask = 0b000000001110000000000000; // 0x00E000
|
||||
// Temperature
|
||||
const uint8_t kCoolixTempMin = 17; // Celsius
|
||||
const uint8_t kCoolixTempMax = 30; // Celsius
|
||||
const uint8_t kCoolixTempRange = kCoolixTempMax - kCoolixTempMin + 1;
|
||||
const uint8_t kCoolixFanTempCode = 0b1110; // Part of Fan Mode.
|
||||
const uint32_t kCoolixTempMask = 0b11110000;
|
||||
const uint8_t kCoolixTempMap[kCoolixTempRange] = {
|
||||
0b0000, // 17C
|
||||
0b0001, // 18c
|
||||
0b0011, // 19C
|
||||
0b0010, // 20C
|
||||
0b0110, // 21C
|
||||
0b0111, // 22C
|
||||
0b0101, // 23C
|
||||
0b0100, // 24C
|
||||
0b1100, // 25C
|
||||
0b1101, // 26C
|
||||
0b1001, // 27C
|
||||
0b1000, // 28C
|
||||
0b1010, // 29C
|
||||
0b1011 // 30C
|
||||
};
|
||||
const uint8_t kCoolixSensorTempMin = 16; // Celsius
|
||||
const uint8_t kCoolixSensorTempMax = 30; // Celsius
|
||||
const uint8_t kCoolixSensorTempIgnoreCode = 0b1111;
|
||||
const uint32_t kCoolixSensorTempMask = 0b000000000000111100000000; // 0xF00
|
||||
// Fixed states/messages.
|
||||
const uint8_t kCoolixPrefix = 0b1011; // 0xB
|
||||
const uint8_t kCoolixUnknown = 0xFF;
|
||||
const uint32_t kCoolixOff = 0b101100100111101111100000; // 0xB27BE0
|
||||
const uint32_t kCoolixSwing = 0b101100100110101111100000; // 0xB26BE0
|
||||
const uint32_t kCoolixSleep = 0b101100101110000000000011; // 0xB2E003
|
||||
const uint32_t kCoolixTurbo = 0b101101011111010110100010; // 0xB5F5A2
|
||||
const uint32_t kCoolixLed = 0b101101011111010110100101; // 0xB5F5A5
|
||||
const uint32_t kCoolixClean = 0b101101011111010110101010; // 0xB5F5AA
|
||||
// On, 25C, Mode: Auto, Fan: Auto, Zone Follow: Off, Sensor Temp: Ignore.
|
||||
const uint32_t kCoolixDefaultState = 0b101100101011111111001000; // 0xB2BFC8
|
||||
|
||||
// Classes
|
||||
class IRCoolixAC {
|
||||
public:
|
||||
explicit IRCoolixAC(uint16_t pin);
|
||||
|
||||
void stateReset();
|
||||
#if SEND_COOLIX
|
||||
void send();
|
||||
#endif // SEND_COOLIX
|
||||
void begin();
|
||||
void on();
|
||||
void off();
|
||||
void setPower(const bool state);
|
||||
bool getPower();
|
||||
void setTemp(const uint8_t temp);
|
||||
uint8_t getTemp();
|
||||
void setSensorTemp(const uint8_t desired);
|
||||
uint8_t getSensorTemp();
|
||||
void clearSensorTemp();
|
||||
void setFan(const uint8_t fan);
|
||||
uint8_t getFan();
|
||||
void setMode(const uint8_t mode);
|
||||
uint8_t getMode();
|
||||
void setSwing();
|
||||
bool getSwing();
|
||||
void setSleep();
|
||||
bool getSleep();
|
||||
void setTurbo();
|
||||
bool getTurbo();
|
||||
void setLed();
|
||||
bool getLed();
|
||||
void setClean();
|
||||
bool getClean();
|
||||
bool getZoneFollow();
|
||||
uint32_t getRaw();
|
||||
void setRaw(const uint32_t new_code);
|
||||
|
||||
#ifdef ARDUINO
|
||||
String toString();
|
||||
#else
|
||||
std::string toString();
|
||||
#endif
|
||||
|
||||
private:
|
||||
// The state of the IR remote in IR code form.
|
||||
uint32_t remote_state;
|
||||
IRsend _irsend;
|
||||
void setTempRaw(const uint8_t code);
|
||||
uint8_t getTempRaw();
|
||||
void setSensorTempRaw(const uint8_t code);
|
||||
void setZoneFollow(const bool state);
|
||||
};
|
||||
|
||||
#endif // IR_COOLIX_H_
|
||||
@@ -12,10 +12,10 @@ Copyright 2017 sillyfrog, crankyoldgit
|
||||
#ifndef ARDUINO
|
||||
#include <string>
|
||||
#endif
|
||||
#include "IRremoteESP8266.h"
|
||||
#include "IRutils.h"
|
||||
#include "IRrecv.h"
|
||||
#include "IRremoteESP8266.h"
|
||||
#include "IRsend.h"
|
||||
#include "IRutils.h"
|
||||
|
||||
// DDDDD AAA IIIII KK KK IIIII NN NN
|
||||
// DD DD AAAAA III KK KK III NNN NN
|
||||
@@ -43,7 +43,7 @@ Copyright 2017 sillyfrog, crankyoldgit
|
||||
// Send a Daikin A/C message.
|
||||
//
|
||||
// Args:
|
||||
// data: An array of DAIKIN_COMMAND_LENGTH bytes containing the IR command.
|
||||
// data: An array of kDaikinStateLength bytes containing the IR command.
|
||||
//
|
||||
// Status: STABLE
|
||||
//
|
||||
@@ -52,46 +52,38 @@ Copyright 2017 sillyfrog, crankyoldgit
|
||||
// https://github.com/mharizanov/Daikin-AC-remote-control-over-the-Internet/tree/master/IRremote
|
||||
void IRsend::sendDaikin(unsigned char data[], uint16_t nbytes,
|
||||
uint16_t repeat) {
|
||||
if (nbytes < DAIKIN_COMMAND_LENGTH)
|
||||
if (nbytes < kDaikinStateLength)
|
||||
return; // Not enough bytes to send a proper message.
|
||||
|
||||
for (uint16_t r = 0; r <= repeat; r++) {
|
||||
// Send the header, 0b00000
|
||||
sendGeneric(0, 0, // No header for the header
|
||||
DAIKIN_BIT_MARK, DAIKIN_ONE_SPACE,
|
||||
DAIKIN_BIT_MARK, DAIKIN_ZERO_SPACE,
|
||||
DAIKIN_BIT_MARK, DAIKIN_ZERO_SPACE + DAIKIN_GAP,
|
||||
(uint64_t) 0b00000, 5, 38, false, 0, 50);
|
||||
kDaikinBitMark, kDaikinOneSpace, kDaikinBitMark,
|
||||
kDaikinZeroSpace, kDaikinBitMark, kDaikinZeroSpace + kDaikinGap,
|
||||
(uint64_t)0b00000, 5, 38, false, 0, 50);
|
||||
// Leading header
|
||||
// Do this as a constant to save RAM and keep in flash memory
|
||||
sendGeneric(DAIKIN_HDR_MARK, DAIKIN_HDR_SPACE,
|
||||
DAIKIN_BIT_MARK, DAIKIN_ONE_SPACE,
|
||||
DAIKIN_BIT_MARK, DAIKIN_ZERO_SPACE,
|
||||
DAIKIN_BIT_MARK, DAIKIN_ZERO_SPACE + DAIKIN_GAP,
|
||||
DAIKIN_FIRST_HEADER64, 64, 38, false, 0, 50);
|
||||
sendGeneric(kDaikinHdrMark, kDaikinHdrSpace, kDaikinBitMark,
|
||||
kDaikinOneSpace, kDaikinBitMark, kDaikinZeroSpace,
|
||||
kDaikinBitMark, kDaikinZeroSpace + kDaikinGap,
|
||||
kDaikinFirstHeader64, 64, 38, false, 0, 50);
|
||||
// Data #1
|
||||
sendGeneric(DAIKIN_HDR_MARK, DAIKIN_HDR_SPACE,
|
||||
DAIKIN_BIT_MARK, DAIKIN_ONE_SPACE,
|
||||
DAIKIN_BIT_MARK, DAIKIN_ZERO_SPACE,
|
||||
DAIKIN_BIT_MARK, DAIKIN_ZERO_SPACE + DAIKIN_GAP,
|
||||
data, 8, 38, false, 0, 50);
|
||||
sendGeneric(kDaikinHdrMark, kDaikinHdrSpace, kDaikinBitMark,
|
||||
kDaikinOneSpace, kDaikinBitMark, kDaikinZeroSpace,
|
||||
kDaikinBitMark, kDaikinZeroSpace + kDaikinGap, data, 8, 38,
|
||||
false, 0, 50);
|
||||
// Data #2
|
||||
sendGeneric(DAIKIN_HDR_MARK, DAIKIN_HDR_SPACE,
|
||||
DAIKIN_BIT_MARK, DAIKIN_ONE_SPACE,
|
||||
DAIKIN_BIT_MARK, DAIKIN_ZERO_SPACE,
|
||||
DAIKIN_BIT_MARK, DAIKIN_ZERO_SPACE + DAIKIN_GAP,
|
||||
data + 8, nbytes - 8, 38, false, 0, 50);
|
||||
sendGeneric(kDaikinHdrMark, kDaikinHdrSpace, kDaikinBitMark,
|
||||
kDaikinOneSpace, kDaikinBitMark, kDaikinZeroSpace,
|
||||
kDaikinBitMark, kDaikinZeroSpace + kDaikinGap, data + 8,
|
||||
nbytes - 8, 38, false, 0, 50);
|
||||
}
|
||||
}
|
||||
#endif // SEND_DAIKIN
|
||||
|
||||
IRDaikinESP::IRDaikinESP(uint16_t pin) : _irsend(pin) {
|
||||
stateReset();
|
||||
}
|
||||
IRDaikinESP::IRDaikinESP(uint16_t pin) : _irsend(pin) { stateReset(); }
|
||||
|
||||
void IRDaikinESP::begin() {
|
||||
_irsend.begin();
|
||||
}
|
||||
void IRDaikinESP::begin() { _irsend.begin(); }
|
||||
|
||||
#if SEND_DAIKIN
|
||||
void IRDaikinESP::send() {
|
||||
@@ -111,8 +103,7 @@ uint8_t IRDaikinESP::calcBlockChecksum(const uint8_t *block,
|
||||
uint8_t sum = 0;
|
||||
// Daikin checksum is just the addition of all the data bytes
|
||||
// in the block but capped to 8 bits.
|
||||
for (uint16_t i = 0; i < length; i++, block++)
|
||||
sum += *block;
|
||||
for (uint16_t i = 0; i < length; i++, block++) sum += *block;
|
||||
return sum & 0xFFU;
|
||||
}
|
||||
|
||||
@@ -122,9 +113,8 @@ uint8_t IRDaikinESP::calcBlockChecksum(const uint8_t *block,
|
||||
// length: The size of the state.
|
||||
// Returns:
|
||||
// A boolean.
|
||||
bool IRDaikinESP::validChecksum(const uint8_t state[],
|
||||
const uint16_t length) {
|
||||
if (length < 8 || state[7] != calcBlockChecksum(state, 7)) return false;
|
||||
bool IRDaikinESP::validChecksum(const uint8_t state[], const uint16_t length) {
|
||||
if (length < 8 || state[7] != calcBlockChecksum(state, 7)) return false;
|
||||
if (length < 10 ||
|
||||
state[length - 1] != calcBlockChecksum(state + 8, length - 9))
|
||||
return false;
|
||||
@@ -138,8 +128,7 @@ void IRDaikinESP::checksum() {
|
||||
}
|
||||
|
||||
void IRDaikinESP::stateReset() {
|
||||
for (uint8_t i = 0; i < DAIKIN_COMMAND_LENGTH; i++)
|
||||
daikin[i] = 0x0;
|
||||
for (uint8_t i = 0; i < kDaikinStateLength; i++) daikin[i] = 0x0;
|
||||
|
||||
daikin[0] = 0x11;
|
||||
daikin[1] = 0xDA;
|
||||
@@ -159,24 +148,23 @@ void IRDaikinESP::stateReset() {
|
||||
checksum();
|
||||
}
|
||||
|
||||
uint8_t* IRDaikinESP::getRaw() {
|
||||
checksum(); // Ensure correct settings before sending.
|
||||
uint8_t *IRDaikinESP::getRaw() {
|
||||
checksum(); // Ensure correct settings before sending.
|
||||
return daikin;
|
||||
}
|
||||
|
||||
void IRDaikinESP::setRaw(uint8_t new_code[]) {
|
||||
for (uint8_t i = 0; i < DAIKIN_COMMAND_LENGTH; i++)
|
||||
daikin[i] = new_code[i];
|
||||
for (uint8_t i = 0; i < kDaikinStateLength; i++) daikin[i] = new_code[i];
|
||||
}
|
||||
|
||||
void IRDaikinESP::on() {
|
||||
// state = ON;
|
||||
setBit(DAIKIN_BYTE_POWER, DAIKIN_BIT_POWER);
|
||||
setBit(kDaikinBytePower, kDaikinBitPower);
|
||||
}
|
||||
|
||||
void IRDaikinESP::off() {
|
||||
// state = OFF;
|
||||
clearBit(DAIKIN_BYTE_POWER, DAIKIN_BIT_POWER);
|
||||
clearBit(kDaikinBytePower, kDaikinBitPower);
|
||||
}
|
||||
|
||||
void IRDaikinESP::setPower(bool state) {
|
||||
@@ -187,30 +175,28 @@ void IRDaikinESP::setPower(bool state) {
|
||||
}
|
||||
|
||||
bool IRDaikinESP::getPower() {
|
||||
return (getBit(DAIKIN_BYTE_POWER, DAIKIN_BIT_POWER) > 0);
|
||||
return (getBit(kDaikinBytePower, kDaikinBitPower) > 0);
|
||||
}
|
||||
|
||||
// Set the temp in deg C
|
||||
void IRDaikinESP::setTemp(uint8_t temp) {
|
||||
if (temp < DAIKIN_MIN_TEMP)
|
||||
temp = DAIKIN_MIN_TEMP;
|
||||
else if (temp > DAIKIN_MAX_TEMP)
|
||||
temp = DAIKIN_MAX_TEMP;
|
||||
if (temp < kDaikinMinTemp)
|
||||
temp = kDaikinMinTemp;
|
||||
else if (temp > kDaikinMaxTemp)
|
||||
temp = kDaikinMaxTemp;
|
||||
daikin[14] = temp * 2;
|
||||
}
|
||||
|
||||
uint8_t IRDaikinESP::getTemp() {
|
||||
return daikin[14] / 2;
|
||||
}
|
||||
uint8_t IRDaikinESP::getTemp() { return daikin[14] / 2; }
|
||||
|
||||
// Set the speed of the fan, 1-5 or DAIKIN_FAN_AUTO or DAIKIN_FAN_QUIET
|
||||
// Set the speed of the fan, 1-5 or kDaikinFanAuto or kDaikinFanQuiet
|
||||
void IRDaikinESP::setFan(uint8_t fan) {
|
||||
// Set the fan speed bits, leave low 4 bits alone
|
||||
uint8_t fanset;
|
||||
if (fan == DAIKIN_FAN_QUIET || fan == DAIKIN_FAN_AUTO)
|
||||
if (fan == kDaikinFanQuiet || fan == kDaikinFanAuto)
|
||||
fanset = fan;
|
||||
else if (fan < DAIKIN_FAN_MIN || fan > DAIKIN_FAN_MAX)
|
||||
fanset = DAIKIN_FAN_AUTO;
|
||||
else if (fan < kDaikinFanMin || fan > kDaikinFanMax)
|
||||
fanset = kDaikinFanAuto;
|
||||
else
|
||||
fanset = 2 + fan;
|
||||
daikin[16] &= 0x0F;
|
||||
@@ -219,31 +205,30 @@ void IRDaikinESP::setFan(uint8_t fan) {
|
||||
|
||||
uint8_t IRDaikinESP::getFan() {
|
||||
uint8_t fan = daikin[16] >> 4;
|
||||
if (fan != DAIKIN_FAN_QUIET && fan != DAIKIN_FAN_AUTO)
|
||||
fan -= 2;
|
||||
if (fan != kDaikinFanQuiet && fan != kDaikinFanAuto) fan -= 2;
|
||||
return fan;
|
||||
}
|
||||
|
||||
uint8_t IRDaikinESP::getMode() {
|
||||
/*
|
||||
DAIKIN_COOL
|
||||
DAIKIN_HEAT
|
||||
DAIKIN_FAN
|
||||
DAIKIN_AUTO
|
||||
DAIKIN_DRY
|
||||
kDaikinCool
|
||||
kDaikinHeat
|
||||
kDaikinFan
|
||||
kDaikinAuto
|
||||
kDaikinDry
|
||||
*/
|
||||
return daikin[13] >> 4;
|
||||
}
|
||||
|
||||
void IRDaikinESP::setMode(uint8_t mode) {
|
||||
switch (mode) {
|
||||
case DAIKIN_COOL:
|
||||
case DAIKIN_HEAT:
|
||||
case DAIKIN_FAN:
|
||||
case DAIKIN_DRY:
|
||||
case kDaikinCool:
|
||||
case kDaikinHeat:
|
||||
case kDaikinFan:
|
||||
case kDaikinDry:
|
||||
break;
|
||||
default:
|
||||
mode = DAIKIN_AUTO;
|
||||
mode = kDaikinAuto;
|
||||
}
|
||||
mode <<= 4;
|
||||
daikin[13] &= 0b10001111;
|
||||
@@ -257,9 +242,7 @@ void IRDaikinESP::setSwingVertical(bool state) {
|
||||
daikin[16] &= 0xF0;
|
||||
}
|
||||
|
||||
bool IRDaikinESP::getSwingVertical() {
|
||||
return daikin[16] & 0x01;
|
||||
}
|
||||
bool IRDaikinESP::getSwingVertical() { return daikin[16] & 0x01; }
|
||||
|
||||
void IRDaikinESP::setSwingHorizontal(bool state) {
|
||||
if (state)
|
||||
@@ -268,84 +251,82 @@ void IRDaikinESP::setSwingHorizontal(bool state) {
|
||||
daikin[17] &= 0xF0;
|
||||
}
|
||||
|
||||
bool IRDaikinESP::getSwingHorizontal() {
|
||||
return daikin[17] & 0x01;
|
||||
}
|
||||
bool IRDaikinESP::getSwingHorizontal() { return daikin[17] & 0x01; }
|
||||
|
||||
void IRDaikinESP::setQuiet(bool state) {
|
||||
if (state) {
|
||||
setBit(DAIKIN_BYTE_SILENT, DAIKIN_BIT_SILENT);
|
||||
setBit(kDaikinByteSilent, kDaikinBitSilent);
|
||||
// Powerful & Quiet mode being on are mutually exclusive.
|
||||
setPowerful(false);
|
||||
} else {
|
||||
clearBit(DAIKIN_BYTE_SILENT, DAIKIN_BIT_SILENT);
|
||||
clearBit(kDaikinByteSilent, kDaikinBitSilent);
|
||||
}
|
||||
}
|
||||
|
||||
bool IRDaikinESP::getQuiet() {
|
||||
return (getBit(DAIKIN_BYTE_SILENT, DAIKIN_BIT_SILENT) > 0);
|
||||
return (getBit(kDaikinByteSilent, kDaikinBitSilent) > 0);
|
||||
}
|
||||
|
||||
void IRDaikinESP::setPowerful(bool state) {
|
||||
if (state) {
|
||||
setBit(DAIKIN_BYTE_POWERFUL, DAIKIN_BIT_POWERFUL);
|
||||
setBit(kDaikinBytePowerful, kDaikinBitPowerful);
|
||||
// Powerful, Quiet, & Econo mode being on are mutually exclusive.
|
||||
setQuiet(false);
|
||||
setEcono(false);
|
||||
} else {
|
||||
clearBit(DAIKIN_BYTE_POWERFUL, DAIKIN_BIT_POWERFUL);
|
||||
clearBit(kDaikinBytePowerful, kDaikinBitPowerful);
|
||||
}
|
||||
}
|
||||
|
||||
bool IRDaikinESP::getPowerful() {
|
||||
return (getBit(DAIKIN_BYTE_POWERFUL, DAIKIN_BIT_POWERFUL) > 0);
|
||||
return (getBit(kDaikinBytePowerful, kDaikinBitPowerful) > 0);
|
||||
}
|
||||
|
||||
void IRDaikinESP::setSensor(bool state) {
|
||||
if (state)
|
||||
setBit(DAIKIN_BYTE_SENSOR, DAIKIN_BIT_SENSOR);
|
||||
setBit(kDaikinByteSensor, kDaikinBitSensor);
|
||||
else
|
||||
clearBit(DAIKIN_BYTE_SENSOR, DAIKIN_BIT_SENSOR);
|
||||
clearBit(kDaikinByteSensor, kDaikinBitSensor);
|
||||
}
|
||||
|
||||
bool IRDaikinESP::getSensor() {
|
||||
return (getBit(DAIKIN_BYTE_SENSOR, DAIKIN_BIT_SENSOR) > 0);
|
||||
return (getBit(kDaikinByteSensor, kDaikinBitSensor) > 0);
|
||||
}
|
||||
|
||||
void IRDaikinESP::setEcono(bool state) {
|
||||
if (state) {
|
||||
setBit(DAIKIN_BYTE_ECONO, DAIKIN_BIT_ECONO);
|
||||
setBit(kDaikinByteEcono, kDaikinBitEcono);
|
||||
// Powerful & Econo mode being on are mutually exclusive.
|
||||
setPowerful(false);
|
||||
} else {
|
||||
clearBit(DAIKIN_BYTE_ECONO, DAIKIN_BIT_ECONO);
|
||||
clearBit(kDaikinByteEcono, kDaikinBitEcono);
|
||||
}
|
||||
}
|
||||
|
||||
bool IRDaikinESP::getEcono() {
|
||||
return (getBit(DAIKIN_BYTE_ECONO, DAIKIN_BIT_ECONO) > 0);
|
||||
return (getBit(kDaikinByteEcono, kDaikinBitEcono) > 0);
|
||||
}
|
||||
|
||||
void IRDaikinESP::setEye(bool state) {
|
||||
if (state)
|
||||
setBit(DAIKIN_BYTE_EYE, DAIKIN_BIT_EYE);
|
||||
setBit(kDaikinByteEye, kDaikinBitEye);
|
||||
else
|
||||
clearBit(DAIKIN_BYTE_EYE, DAIKIN_BIT_EYE);
|
||||
clearBit(kDaikinByteEye, kDaikinBitEye);
|
||||
}
|
||||
|
||||
bool IRDaikinESP::getEye() {
|
||||
return (getBit(DAIKIN_BYTE_EYE, DAIKIN_BIT_EYE) > 0);
|
||||
return (getBit(kDaikinByteEye, kDaikinBitEye) > 0);
|
||||
}
|
||||
|
||||
void IRDaikinESP::setMold(bool state) {
|
||||
if (state)
|
||||
setBit(DAIKIN_BYTE_MOLD, DAIKIN_BIT_MOLD);
|
||||
setBit(kDaikinByteMold, kDaikinBitMold);
|
||||
else
|
||||
clearBit(DAIKIN_BYTE_MOLD, DAIKIN_BIT_MOLD);
|
||||
clearBit(kDaikinByteMold, kDaikinBitMold);
|
||||
}
|
||||
|
||||
bool IRDaikinESP::getMold() {
|
||||
return (getBit(DAIKIN_BYTE_MOLD, DAIKIN_BIT_MOLD) > 0);
|
||||
return (getBit(kDaikinByteMold, kDaikinBitMold) > 0);
|
||||
}
|
||||
|
||||
void IRDaikinESP::setBit(uint8_t byte, uint8_t bitmask) {
|
||||
@@ -363,16 +344,16 @@ uint8_t IRDaikinESP::getBit(uint8_t byte, uint8_t bitmask) {
|
||||
|
||||
// starttime: Number of minutes after midnight, in 10 minutes increments
|
||||
void IRDaikinESP::enableOnTimer(uint16_t starttime) {
|
||||
setBit(DAIKIN_BYTE_ON_TIMER, DAIKIN_BIT_ON_TIMER);
|
||||
daikin[18] = (uint8_t) (starttime & 0x00FF);
|
||||
setBit(kDaikinByteOnTimer, kDaikinBitOnTimer);
|
||||
daikin[18] = (uint8_t)(starttime & 0x00FF);
|
||||
// only keep 4 bits
|
||||
daikin[19] &= 0xF0;
|
||||
daikin[19] |= (uint8_t) ((starttime >> 8) & 0x0F);
|
||||
daikin[19] |= (uint8_t)((starttime >> 8) & 0x0F);
|
||||
}
|
||||
|
||||
void IRDaikinESP::disableOnTimer() {
|
||||
enableOnTimer(0x600);
|
||||
clearBit(DAIKIN_BYTE_ON_TIMER, DAIKIN_BIT_ON_TIMER);
|
||||
clearBit(kDaikinByteOnTimer, kDaikinBitOnTimer);
|
||||
}
|
||||
|
||||
uint16_t IRDaikinESP::getOnTime() {
|
||||
@@ -384,20 +365,20 @@ uint16_t IRDaikinESP::getOnTime() {
|
||||
}
|
||||
|
||||
bool IRDaikinESP::getOnTimerEnabled() {
|
||||
return getBit(DAIKIN_BYTE_ON_TIMER, DAIKIN_BIT_ON_TIMER);
|
||||
return getBit(kDaikinByteOnTimer, kDaikinBitOnTimer);
|
||||
}
|
||||
|
||||
// endtime: Number of minutes after midnight, in 10 minutes increments
|
||||
void IRDaikinESP::enableOffTimer(uint16_t endtime) {
|
||||
setBit(DAIKIN_BYTE_OFF_TIMER, DAIKIN_BIT_OFF_TIMER);
|
||||
setBit(kDaikinByteOffTimer, kDaikinBitOffTimer);
|
||||
daikin[20] = (uint8_t)((endtime >> 4) & 0xFF);
|
||||
daikin[19] &= 0x0F;
|
||||
daikin[19] |= (uint8_t) ((endtime & 0x000F) << 4);
|
||||
daikin[19] |= (uint8_t)((endtime & 0x000F) << 4);
|
||||
}
|
||||
|
||||
void IRDaikinESP::disableOffTimer() {
|
||||
enableOffTimer(0x600);
|
||||
clearBit(DAIKIN_BYTE_OFF_TIMER, DAIKIN_BIT_OFF_TIMER);
|
||||
clearBit(kDaikinByteOffTimer, kDaikinBitOffTimer);
|
||||
}
|
||||
|
||||
uint16_t IRDaikinESP::getOffTime() {
|
||||
@@ -411,15 +392,15 @@ uint16_t IRDaikinESP::getOffTime() {
|
||||
}
|
||||
|
||||
bool IRDaikinESP::getOffTimerEnabled() {
|
||||
return getBit(DAIKIN_BYTE_OFF_TIMER, DAIKIN_BIT_OFF_TIMER);
|
||||
return getBit(kDaikinByteOffTimer, kDaikinBitOffTimer);
|
||||
}
|
||||
|
||||
void IRDaikinESP::setCurrentTime(uint16_t numMins) {
|
||||
if (numMins > 24 * 60) numMins = 0; // If > 23:59, set to 00:00
|
||||
daikin[5] = (uint8_t) (numMins & 0x00FF);
|
||||
daikin[5] = (uint8_t)(numMins & 0x00FF);
|
||||
// only keep 4 bits
|
||||
daikin[6] &= 0xF0;
|
||||
daikin[6] |= (uint8_t) ((numMins >> 8) & 0x0F);
|
||||
daikin[6] |= (uint8_t)((numMins >> 8) & 0x0F);
|
||||
}
|
||||
|
||||
uint16_t IRDaikinESP::getCurrentTime() {
|
||||
@@ -433,7 +414,7 @@ uint16_t IRDaikinESP::getCurrentTime() {
|
||||
#ifdef ARDUINO
|
||||
String IRDaikinESP::renderTime(uint16_t timemins) {
|
||||
String ret;
|
||||
#else // ARDUINO
|
||||
#else // ARDUINO
|
||||
std::string IRDaikinESP::renderTime(uint16_t timemins) {
|
||||
std::string ret;
|
||||
#endif // ARDUINO
|
||||
@@ -441,8 +422,7 @@ std::string IRDaikinESP::renderTime(uint16_t timemins) {
|
||||
hours = timemins / 60;
|
||||
ret = uint64ToString(hours) + ":";
|
||||
mins = timemins - (hours * 60);
|
||||
if (mins < 10)
|
||||
ret += "0";
|
||||
if (mins < 10) ret += "0";
|
||||
ret += uint64ToString(mins);
|
||||
return ret;
|
||||
}
|
||||
@@ -451,7 +431,7 @@ std::string IRDaikinESP::renderTime(uint16_t timemins) {
|
||||
#ifdef ARDUINO
|
||||
String IRDaikinESP::toString() {
|
||||
String result = "";
|
||||
#else // ARDUINO
|
||||
#else // ARDUINO
|
||||
std::string IRDaikinESP::toString() {
|
||||
std::string result = "";
|
||||
#endif // ARDUINO
|
||||
@@ -462,19 +442,19 @@ std::string IRDaikinESP::toString() {
|
||||
result += "Off";
|
||||
result += ", Mode: " + uint64ToString(getMode());
|
||||
switch (getMode()) {
|
||||
case DAIKIN_AUTO:
|
||||
case kDaikinAuto:
|
||||
result += " (AUTO)";
|
||||
break;
|
||||
case DAIKIN_COOL:
|
||||
case kDaikinCool:
|
||||
result += " (COOL)";
|
||||
break;
|
||||
case DAIKIN_HEAT:
|
||||
case kDaikinHeat:
|
||||
result += " (HEAT)";
|
||||
break;
|
||||
case DAIKIN_DRY:
|
||||
case kDaikinDry:
|
||||
result += " (DRY)";
|
||||
break;
|
||||
case DAIKIN_FAN:
|
||||
case kDaikinFan:
|
||||
result += " (FAN)";
|
||||
break;
|
||||
default:
|
||||
@@ -483,16 +463,16 @@ std::string IRDaikinESP::toString() {
|
||||
result += ", Temp: " + uint64ToString(getTemp()) + "C";
|
||||
result += ", Fan: " + uint64ToString(getFan());
|
||||
switch (getFan()) {
|
||||
case DAIKIN_FAN_AUTO:
|
||||
case kDaikinFanAuto:
|
||||
result += " (AUTO)";
|
||||
break;
|
||||
case DAIKIN_FAN_QUIET:
|
||||
case kDaikinFanQuiet:
|
||||
result += " (QUIET)";
|
||||
break;
|
||||
case DAIKIN_FAN_MIN:
|
||||
case kDaikinFanMin:
|
||||
result += " (MIN)";
|
||||
break;
|
||||
case DAIKIN_FAN_MAX:
|
||||
case kDaikinFanMax:
|
||||
result += " (MAX)";
|
||||
break;
|
||||
}
|
||||
@@ -551,14 +531,13 @@ std::string IRDaikinESP::toString() {
|
||||
void IRDaikinESP::printState() {
|
||||
#ifdef ARDUINO
|
||||
String strbits;
|
||||
#else // ARDUINO
|
||||
#else // ARDUINO
|
||||
std::string strbits;
|
||||
#endif // ARDUINO
|
||||
DPRINTLN("Raw Bits:");
|
||||
for (uint8_t i = 0; i < DAIKIN_COMMAND_LENGTH; i++) {
|
||||
for (uint8_t i = 0; i < kDaikinStateLength; i++) {
|
||||
strbits = uint64ToString(daikin[i], BIN);
|
||||
while (strbits.length() < 8)
|
||||
strbits = "0" + strbits;
|
||||
while (strbits.length() < 8) strbits = "0" + strbits;
|
||||
DPRINT(strbits);
|
||||
DPRINT(" ");
|
||||
}
|
||||
@@ -584,8 +563,7 @@ void IRDaikinESP::printState() {
|
||||
uint32_t IRDaikinESP::getCommand() {
|
||||
uint32_t ret = 0;
|
||||
uint32_t tmp = 0;
|
||||
if (getPower())
|
||||
ret |= 0b00000000000000000000000000000001;
|
||||
if (getPower()) ret |= 0b00000000000000000000000000000001;
|
||||
tmp = getMode();
|
||||
tmp = tmp << 1;
|
||||
ret |= tmp;
|
||||
@@ -598,24 +576,18 @@ uint32_t IRDaikinESP::getCommand() {
|
||||
tmp <<= 8;
|
||||
ret |= tmp;
|
||||
|
||||
if (getEcono())
|
||||
ret |= 0b00000000000000001000000000000000;
|
||||
if (getPowerful())
|
||||
ret |= 0b00000000000000010000000000000000;
|
||||
if (getQuiet())
|
||||
ret |= 0b00000000000000100000000000000000;
|
||||
if (getSensor())
|
||||
ret |= 0b00000000000001000000000000000000;
|
||||
if (getSwingVertical())
|
||||
ret |= 0b00000000000010000000000000000000;
|
||||
if (getEcono()) ret |= 0b00000000000000001000000000000000;
|
||||
if (getPowerful()) ret |= 0b00000000000000010000000000000000;
|
||||
if (getQuiet()) ret |= 0b00000000000000100000000000000000;
|
||||
if (getSensor()) ret |= 0b00000000000001000000000000000000;
|
||||
if (getSwingVertical()) ret |= 0b00000000000010000000000000000000;
|
||||
ret |= (getCurrentTime() << 20);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void IRDaikinESP::setCommand(uint32_t value) {
|
||||
uint32_t tmp = 0;
|
||||
if (value & 0b00000000000000000000000000000001)
|
||||
setPower(true);
|
||||
if (value & 0b00000000000000000000000000000001) setPower(true);
|
||||
tmp = value & 0b00000000000000000000000000001110;
|
||||
tmp >>= 1;
|
||||
setMode(tmp);
|
||||
@@ -628,16 +600,11 @@ void IRDaikinESP::setCommand(uint32_t value) {
|
||||
tmp >>= 8;
|
||||
setTemp(tmp);
|
||||
|
||||
if (value & 0b00000000000000001000000000000000)
|
||||
setEcono(true);
|
||||
if (value & 0b00000000000000010000000000000000)
|
||||
setPowerful(true);
|
||||
if (value & 0b00000000000000100000000000000000)
|
||||
setQuiet(true);
|
||||
if (value & 0b00000000000001000000000000000000)
|
||||
setSensor(true);
|
||||
if (value & 0b00000000000010000000000000000000)
|
||||
setSwingVertical(true);
|
||||
if (value & 0b00000000000000001000000000000000) setEcono(true);
|
||||
if (value & 0b00000000000000010000000000000000) setPowerful(true);
|
||||
if (value & 0b00000000000000100000000000000000) setQuiet(true);
|
||||
if (value & 0b00000000000001000000000000000000) setSensor(true);
|
||||
if (value & 0b00000000000010000000000000000000) setSwingVertical(true);
|
||||
|
||||
value >>= 20;
|
||||
setCurrentTime(value);
|
||||
@@ -646,8 +613,8 @@ void IRDaikinESP::setCommand(uint32_t value) {
|
||||
#if DECODE_DAIKIN
|
||||
|
||||
void addbit(bool val, unsigned char data[]) {
|
||||
uint8_t curbit = data[DAIKIN_CURBIT];
|
||||
uint8_t curindex = data[DAIKIN_CURINDEX];
|
||||
uint8_t curbit = data[kDaikinCurBit];
|
||||
uint8_t curindex = data[kDaikinCurIndex];
|
||||
if (val) {
|
||||
unsigned char bit = 1;
|
||||
bit = bit << curbit;
|
||||
@@ -658,23 +625,23 @@ void addbit(bool val, unsigned char data[]) {
|
||||
curbit = 0;
|
||||
curindex++;
|
||||
}
|
||||
data[DAIKIN_CURBIT] = curbit;
|
||||
data[DAIKIN_CURINDEX] = curindex;
|
||||
data[kDaikinCurBit] = curbit;
|
||||
data[kDaikinCurIndex] = curindex;
|
||||
}
|
||||
|
||||
bool checkheader(decode_results *results, uint16_t* offset) {
|
||||
if (!IRrecv::matchMark(results->rawbuf[(*offset)++], DAIKIN_BIT_MARK,
|
||||
DAIKIN_TOLERANCE, DAIKIN_MARK_EXCESS))
|
||||
bool checkheader(decode_results *results, uint16_t *offset) {
|
||||
if (!IRrecv::matchMark(results->rawbuf[(*offset)++], kDaikinBitMark,
|
||||
kDaikinTolerance, kDaikinMarkExcess))
|
||||
return false;
|
||||
if (!IRrecv::matchSpace(results->rawbuf[(*offset)++],
|
||||
DAIKIN_ZERO_SPACE + DAIKIN_GAP,
|
||||
DAIKIN_TOLERANCE, DAIKIN_MARK_EXCESS))
|
||||
kDaikinZeroSpace + kDaikinGap, kDaikinTolerance,
|
||||
kDaikinMarkExcess))
|
||||
return false;
|
||||
if (!IRrecv::matchMark(results->rawbuf[(*offset)++], DAIKIN_HDR_MARK,
|
||||
DAIKIN_TOLERANCE, DAIKIN_MARK_EXCESS))
|
||||
if (!IRrecv::matchMark(results->rawbuf[(*offset)++], kDaikinHdrMark,
|
||||
kDaikinTolerance, kDaikinMarkExcess))
|
||||
return false;
|
||||
if (!IRrecv::matchSpace(results->rawbuf[(*offset)++], DAIKIN_HDR_SPACE,
|
||||
DAIKIN_TOLERANCE, DAIKIN_MARK_EXCESS))
|
||||
if (!IRrecv::matchSpace(results->rawbuf[(*offset)++], kDaikinHdrSpace,
|
||||
kDaikinTolerance, kDaikinMarkExcess))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@@ -684,14 +651,14 @@ bool readbits(decode_results *results, uint16_t *offset,
|
||||
unsigned char daikin_code[], uint16_t countbits) {
|
||||
for (uint16_t i = 0; i < countbits && *offset < results->rawlen - 1;
|
||||
i++, (*offset)++) {
|
||||
if (!IRrecv::matchMark(results->rawbuf[(*offset)++], DAIKIN_BIT_MARK,
|
||||
DAIKIN_TOLERANCE, DAIKIN_MARK_EXCESS))
|
||||
if (!IRrecv::matchMark(results->rawbuf[(*offset)++], kDaikinBitMark,
|
||||
kDaikinTolerance, kDaikinMarkExcess))
|
||||
return false;
|
||||
if (IRrecv::matchSpace(results->rawbuf[*offset], DAIKIN_ONE_SPACE,
|
||||
DAIKIN_TOLERANCE, DAIKIN_MARK_EXCESS))
|
||||
if (IRrecv::matchSpace(results->rawbuf[*offset], kDaikinOneSpace,
|
||||
kDaikinTolerance, kDaikinMarkExcess))
|
||||
addbit(1, daikin_code);
|
||||
else if (IRrecv::matchSpace(results->rawbuf[*offset], DAIKIN_ZERO_SPACE,
|
||||
DAIKIN_TOLERANCE, DAIKIN_MARK_EXCESS))
|
||||
else if (IRrecv::matchSpace(results->rawbuf[*offset], kDaikinZeroSpace,
|
||||
kDaikinTolerance, kDaikinMarkExcess))
|
||||
addbit(0, daikin_code);
|
||||
else
|
||||
return false;
|
||||
@@ -702,7 +669,7 @@ bool readbits(decode_results *results, uint16_t *offset,
|
||||
// Decode the supplied Daikin A/C message.
|
||||
// Args:
|
||||
// results: Ptr to the data to decode and where to store the decode result.
|
||||
// nbits: Nr. of bits to expect in the data portion. (DAIKIN_RAW_BITS)
|
||||
// nbits: Nr. of bits to expect in the data portion. (kDaikinRawBits)
|
||||
// strict: Flag to indicate if we strictly adhere to the specification.
|
||||
// Returns:
|
||||
// boolean: True if it can decode it, false if it can't.
|
||||
@@ -716,22 +683,18 @@ bool readbits(decode_results *results, uint16_t *offset,
|
||||
// https://github.com/mharizanov/Daikin-AC-remote-control-over-the-Internet/tree/master/IRremote
|
||||
bool IRrecv::decodeDaikin(decode_results *results, uint16_t nbits,
|
||||
bool strict) {
|
||||
if (results->rawlen < DAIKIN_RAW_BITS)
|
||||
return false;
|
||||
if (results->rawlen < kDaikinRawBits) return false;
|
||||
|
||||
// Compliance
|
||||
if (strict && nbits != DAIKIN_RAW_BITS)
|
||||
return false;
|
||||
if (strict && nbits != kDaikinRawBits) return false;
|
||||
|
||||
uint16_t offset = OFFSET_START;
|
||||
unsigned char daikin_code[DAIKIN_COMMAND_LENGTH + 2];
|
||||
for (uint8_t i = 0; i < DAIKIN_COMMAND_LENGTH+2; i++)
|
||||
daikin_code[i] = 0;
|
||||
uint16_t offset = kStartOffset;
|
||||
unsigned char daikin_code[kDaikinStateLength + 2];
|
||||
for (uint8_t i = 0; i < kDaikinStateLength + 2; i++) daikin_code[i] = 0;
|
||||
|
||||
// Header (#1)
|
||||
for (uint8_t i = 0; i < 10; i++) {
|
||||
if (!matchMark(results->rawbuf[offset++], DAIKIN_BIT_MARK))
|
||||
return false;
|
||||
if (!matchMark(results->rawbuf[offset++], kDaikinBitMark)) return false;
|
||||
}
|
||||
if (!checkheader(results, &offset)) return false;
|
||||
|
||||
@@ -741,8 +704,7 @@ bool IRrecv::decodeDaikin(decode_results *results, uint16_t nbits,
|
||||
// Ignore everything that has just been captured as it is not needed.
|
||||
// Some remotes may not send this portion, my remote did, but it's not
|
||||
// required.
|
||||
for (uint8_t i = 0; i < DAIKIN_COMMAND_LENGTH + 2; i++)
|
||||
daikin_code[i] = 0;
|
||||
for (uint8_t i = 0; i < kDaikinStateLength + 2; i++) daikin_code[i] = 0;
|
||||
|
||||
// Header (#2)
|
||||
if (!checkheader(results, &offset)) return false;
|
||||
@@ -754,14 +716,13 @@ bool IRrecv::decodeDaikin(decode_results *results, uint16_t nbits,
|
||||
if (!checkheader(results, &offset)) return false;
|
||||
|
||||
// Data (#3), read up everything else
|
||||
if (!readbits(results, &offset, daikin_code, DAIKIN_BITS - (8 * 8)))
|
||||
if (!readbits(results, &offset, daikin_code, kDaikinBits - (8 * 8)))
|
||||
return false;
|
||||
|
||||
// Footer
|
||||
if (!matchMark(results->rawbuf[offset++], DAIKIN_BIT_MARK))
|
||||
return false;
|
||||
if (offset < results->rawlen && !matchAtLeast(results->rawbuf[offset],
|
||||
DAIKIN_GAP))
|
||||
if (!matchMark(results->rawbuf[offset++], kDaikinBitMark)) return false;
|
||||
if (offset < results->rawlen &&
|
||||
!matchAtLeast(results->rawbuf[offset], kDaikinGap))
|
||||
return false;
|
||||
|
||||
// Compliance
|
||||
@@ -780,9 +741,9 @@ bool IRrecv::decodeDaikin(decode_results *results, uint16_t nbits,
|
||||
#endif // DAIKIN_DEBUG
|
||||
|
||||
// Copy across the bits to state
|
||||
for (uint8_t i = 0; i < DAIKIN_COMMAND_LENGTH; i++)
|
||||
for (uint8_t i = 0; i < kDaikinStateLength; i++)
|
||||
results->state[i] = daikin_code[i];
|
||||
results->bits = DAIKIN_COMMAND_LENGTH * 8;
|
||||
results->bits = kDaikinStateLength * 8;
|
||||
results->decode_type = DAIKIN;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
#else
|
||||
#include <string>
|
||||
#endif
|
||||
#include "IRremoteESP8266.h"
|
||||
#include "IRrecv.h"
|
||||
#include "IRremoteESP8266.h"
|
||||
#include "IRsend.h"
|
||||
|
||||
// Option to disable the additional Daikin debug info to conserve memory
|
||||
@@ -22,111 +22,115 @@
|
||||
// DDDDDD AA AA IIIII KK KK IIIII NN NN
|
||||
|
||||
/*
|
||||
Daikin AC map
|
||||
byte 5=Current time, mins past midnight, low bits
|
||||
byte 6
|
||||
Daikin AC map
|
||||
byte 5=Current time, mins past midnight, low bits
|
||||
byte 6
|
||||
b0-b3=Current time, mins past midnight, high bits
|
||||
byte 7= checksum of the first part (and last byte before a 29ms pause)
|
||||
byte 13=mode
|
||||
b7 = 0
|
||||
b6+b5+b4 = Mode
|
||||
Modes: b6+b5+b4
|
||||
011 = Cool
|
||||
100 = Heat (temp 23)
|
||||
110 = FAN (temp not shown, but 25)
|
||||
000 = Fully Automatic (temp 25)
|
||||
010 = DRY (temp 0xc0 = 96 degrees c)
|
||||
b3 = 1
|
||||
b2 = OFF timer set
|
||||
b1 = ON timer set
|
||||
b0 = Air Conditioner ON
|
||||
byte 14=temp*2 (Temp should be between 10 - 32)
|
||||
byte 16=Fan
|
||||
FAN control
|
||||
b7+b6+b5+b4 = Fan speed
|
||||
Fan: b7+b6+b5+b4
|
||||
0×3 = 1 bar
|
||||
0×4 = 2 bar
|
||||
0×5 = 3 bar
|
||||
0×6 = 4 bar
|
||||
0×7 = 5 bar
|
||||
0xa = Auto
|
||||
0xb = Quite
|
||||
b3+b2+b1+b0 = Swing control up/down
|
||||
Swing control up/down:
|
||||
0000 = Swing up/down off
|
||||
1111 = Swing up/down on
|
||||
byte 17
|
||||
Swing control left/right:
|
||||
0000 = Swing left/right off
|
||||
1111 = Swing left/right on
|
||||
byte 18=On timer mins past midnight, low bits
|
||||
byte 19
|
||||
byte 7= checksum of the first part (and last byte before a 29ms pause)
|
||||
byte 13=mode
|
||||
b7 = 0
|
||||
b6+b5+b4 = Mode
|
||||
Modes: b6+b5+b4
|
||||
011 = Cool
|
||||
100 = Heat (temp 23)
|
||||
110 = FAN (temp not shown, but 25)
|
||||
000 = Fully Automatic (temp 25)
|
||||
010 = DRY (temp 0xc0 = 96 degrees c)
|
||||
b3 = 1
|
||||
b2 = OFF timer set
|
||||
b1 = ON timer set
|
||||
b0 = Air Conditioner ON
|
||||
byte 14=temp*2 (Temp should be between 10 - 32)
|
||||
byte 16=Fan
|
||||
FAN control
|
||||
b7+b6+b5+b4 = Fan speed
|
||||
Fan: b7+b6+b5+b4
|
||||
0×3 = 1 bar
|
||||
0×4 = 2 bar
|
||||
0×5 = 3 bar
|
||||
0×6 = 4 bar
|
||||
0×7 = 5 bar
|
||||
0xa = Auto
|
||||
0xb = Quite
|
||||
b3+b2+b1+b0 = Swing control up/down
|
||||
Swing control up/down:
|
||||
0000 = Swing up/down off
|
||||
1111 = Swing up/down on
|
||||
byte 17
|
||||
Swing control left/right:
|
||||
0000 = Swing left/right off
|
||||
1111 = Swing left/right on
|
||||
byte 18=On timer mins past midnight, low bits
|
||||
byte 19
|
||||
b0-b3=On timer mins past midnight, high bits
|
||||
b4-b7=Off timer mins past midnight, low bits
|
||||
byte 20=Off timer mins past midnight, high bits
|
||||
byte 21=Aux -> Powerful (bit 1), Silent (bit 5)
|
||||
byte 24=Aux2
|
||||
byte 20=Off timer mins past midnight, high bits
|
||||
byte 21=Aux -> Powerful (bit 1), Silent (bit 5)
|
||||
byte 24=Aux2
|
||||
b1: Sensor
|
||||
b2: Econo mode
|
||||
b7: Intelligent eye on
|
||||
byte 25=Aux3
|
||||
byte 25=Aux3
|
||||
b1: Mold Proof
|
||||
byte 26= checksum of the second part
|
||||
byte 26= checksum of the second part
|
||||
*/
|
||||
|
||||
// Constants
|
||||
#define DAIKIN_COOL 0b011
|
||||
#define DAIKIN_HEAT 0b100
|
||||
#define DAIKIN_FAN 0b110
|
||||
#define DAIKIN_AUTO 0b000
|
||||
#define DAIKIN_DRY 0b010
|
||||
#define DAIKIN_MIN_TEMP 10U // Celsius
|
||||
#define DAIKIN_MAX_TEMP 32U // Celsius
|
||||
#define DAIKIN_FAN_MIN (uint8_t) 1U
|
||||
#define DAIKIN_FAN_MAX (uint8_t) 5U
|
||||
#define DAIKIN_FAN_AUTO (uint8_t) 0b1010
|
||||
#define DAIKIN_FAN_QUIET (uint8_t) 0b1011
|
||||
|
||||
#define DAIKIN_BYTE_POWER 13
|
||||
#define DAIKIN_BIT_POWER 0b00000001
|
||||
|
||||
#define DAIKIN_BYTE_POWERFUL 21
|
||||
#define DAIKIN_BIT_POWERFUL 0b00000001
|
||||
#define DAIKIN_BYTE_SILENT 21
|
||||
#define DAIKIN_BIT_SILENT 0b00100000
|
||||
|
||||
#define DAIKIN_BYTE_SENSOR 24
|
||||
#define DAIKIN_BIT_SENSOR 0b00000010
|
||||
#define DAIKIN_BYTE_ECONO 24
|
||||
#define DAIKIN_BIT_ECONO 0b00000100
|
||||
#define DAIKIN_BYTE_EYE 24
|
||||
#define DAIKIN_BIT_EYE 0b10000000
|
||||
#define DAIKIN_BYTE_MOLD 25
|
||||
#define DAIKIN_BIT_MOLD 0b00000010
|
||||
|
||||
#define DAIKIN_BYTE_OFF_TIMER 13
|
||||
#define DAIKIN_BIT_OFF_TIMER 0b00000100
|
||||
#define DAIKIN_BYTE_ON_TIMER 13
|
||||
#define DAIKIN_BIT_ON_TIMER 0b00000010
|
||||
|
||||
#define DAIKIN_CURBIT DAIKIN_COMMAND_LENGTH
|
||||
#define DAIKIN_CURINDEX (DAIKIN_COMMAND_LENGTH + 1)
|
||||
#define OFFSET_ERR 65432
|
||||
|
||||
#define DAIKIN_TOLERANCE 35
|
||||
#define DAIKIN_MARK_EXCESS MARK_EXCESS
|
||||
|
||||
#define DAIKIN_HDR_MARK 3650U // DAIKIN_BIT_MARK * 8
|
||||
#define DAIKIN_HDR_SPACE 1623U // DAIKIN_BIT_MARK * 4
|
||||
#define DAIKIN_BIT_MARK 428U
|
||||
#define DAIKIN_ZERO_SPACE 428U
|
||||
#define DAIKIN_ONE_SPACE 1280U
|
||||
#define DAIKIN_GAP 29000U
|
||||
|
||||
const uint8_t kDaikinAuto = 0b000;
|
||||
const uint8_t kDaikinDry = 0b010;
|
||||
const uint8_t kDaikinCool = 0b011;
|
||||
const uint8_t kDaikinHeat = 0b100;
|
||||
const uint8_t kDaikinFan = 0b110;
|
||||
const uint8_t kDaikinMinTemp = 10; // Celsius
|
||||
const uint8_t kDaikinMaxTemp = 32; // Celsius
|
||||
const uint8_t kDaikinFanMin = 1;
|
||||
const uint8_t kDaikinFanMax = 5;
|
||||
const uint8_t kDaikinFanAuto = 0b1010;
|
||||
const uint8_t kDaikinFanQuiet = 0b1011;
|
||||
const uint8_t kDaikinBytePower = 13;
|
||||
const uint8_t kDaikinBitPower = 0b00000001;
|
||||
const uint8_t kDaikinBytePowerful = 21;
|
||||
const uint8_t kDaikinBitPowerful = 0b00000001;
|
||||
const uint8_t kDaikinByteSilent = 21;
|
||||
const uint8_t kDaikinBitSilent = 0b00100000;
|
||||
const uint8_t kDaikinByteSensor = 24;
|
||||
const uint8_t kDaikinBitSensor = 0b00000010;
|
||||
const uint8_t kDaikinByteEcono = 24;
|
||||
const uint8_t kDaikinBitEcono = 0b00000100;
|
||||
const uint8_t kDaikinByteEye = 24;
|
||||
const uint8_t kDaikinBitEye = 0b10000000;
|
||||
const uint8_t kDaikinByteMold = 25;
|
||||
const uint8_t kDaikinBitMold = 0b00000010;
|
||||
const uint8_t kDaikinByteOffTimer = 13;
|
||||
const uint8_t kDaikinBitOffTimer = 0b00000100;
|
||||
const uint8_t kDaikinByteOnTimer = 13;
|
||||
const uint8_t kDaikinBitOnTimer = 0b00000010;
|
||||
const uint8_t kDaikinCurBit = kDaikinStateLength;
|
||||
const uint8_t kDaikinCurIndex = kDaikinStateLength + 1;
|
||||
const uint8_t kDaikinTolerance = 35;
|
||||
const uint16_t kDaikinMarkExcess = kMarkExcess;
|
||||
const uint16_t kDaikinHdrMark = 3650; // kDaikinBitMark * 8
|
||||
const uint16_t kDaikinHdrSpace = 1623; // kDaikinBitMark * 4
|
||||
const uint16_t kDaikinBitMark = 428;
|
||||
const uint16_t kDaikinZeroSpace = 428;
|
||||
const uint16_t kDaikinOneSpace = 1280;
|
||||
const uint16_t kDaikinGap = 29000;
|
||||
// Note bits in each octet swapped so can be sent as a single value
|
||||
#define DAIKIN_FIRST_HEADER64 \
|
||||
0b1101011100000000000000001100010100000000001001111101101000010001
|
||||
const uint64_t kDaikinFirstHeader64 =
|
||||
0b1101011100000000000000001100010100000000001001111101101000010001;
|
||||
|
||||
// Legacy defines.
|
||||
#define DAIKIN_COOL kDaikinCool
|
||||
#define DAIKIN_HEAT kDaikinHeat
|
||||
#define DAIKIN_FAN kDaikinFan
|
||||
#define DAIKIN_AUTO kDaikinAuto
|
||||
#define DAIKIN_DRY kDaikinDry
|
||||
#define DAIKIN_MIN_TEMP kDaikinMinTemp
|
||||
#define DAIKIN_MAX_TEMP kDaikinMaxTemp
|
||||
#define DAIKIN_FAN_MIN kDaikinFanMin
|
||||
#define DAIKIN_FAN_MAX kDaikinFanMax
|
||||
#define DAIKIN_FAN_AUTO kDaikinFanAuto
|
||||
#define DAIKIN_FAN_QUIET kDaikinFanQuiet
|
||||
|
||||
class IRDaikinESP {
|
||||
public:
|
||||
@@ -180,7 +184,7 @@ class IRDaikinESP {
|
||||
uint32_t getCommand();
|
||||
void setCommand(uint32_t value);
|
||||
static bool validChecksum(const uint8_t state[],
|
||||
const uint16_t length = DAIKIN_COMMAND_LENGTH);
|
||||
const uint16_t length = kDaikinStateLength);
|
||||
#ifdef ARDUINO
|
||||
String toString();
|
||||
static String renderTime(uint16_t timemins);
|
||||
@@ -191,9 +195,9 @@ class IRDaikinESP {
|
||||
|
||||
private:
|
||||
// # of bytes per command
|
||||
uint8_t daikin[DAIKIN_COMMAND_LENGTH];
|
||||
uint8_t daikin[kDaikinStateLength];
|
||||
void stateReset();
|
||||
static uint8_t calcBlockChecksum(const uint8_t *block, const uint16_t length);
|
||||
static uint8_t calcBlockChecksum(const uint8_t* block, const uint16_t length);
|
||||
void checksum();
|
||||
void setBit(uint8_t byte, uint8_t bitmask);
|
||||
void clearBit(uint8_t byte, uint8_t bitmask);
|
||||
|
||||
@@ -18,25 +18,25 @@
|
||||
// Constants
|
||||
// Ref:
|
||||
// https://github.com/z3t0/Arduino-IRremote/blob/master/ir_Denon.cpp
|
||||
#define DENON_TICK 263U
|
||||
#define DENON_HDR_MARK_TICKS 1U
|
||||
#define DENON_HDR_MARK (DENON_HDR_MARK_TICKS * DENON_TICK)
|
||||
#define DENON_HDR_SPACE_TICKS 3U
|
||||
#define DENON_HDR_SPACE (DENON_HDR_SPACE_TICKS * DENON_TICK)
|
||||
#define DENON_BIT_MARK_TICKS 1U
|
||||
#define DENON_BIT_MARK (DENON_BIT_MARK_TICKS * DENON_TICK)
|
||||
#define DENON_ONE_SPACE_TICKS 7U
|
||||
#define DENON_ONE_SPACE (DENON_ONE_SPACE_TICKS * DENON_TICK)
|
||||
#define DENON_ZERO_SPACE_TICKS 3U
|
||||
#define DENON_ZERO_SPACE (DENON_ZERO_SPACE_TICKS * DENON_TICK)
|
||||
#define DENON_MIN_COMMAND_LENGTH_TICKS 510U
|
||||
#define DENON_MIN_COMMAND_LENGTH (DENON_MIN_COMMAND_LENGTH_TICKS * DENON_TICK)
|
||||
#define DENON_MIN_GAP_TICKS (DENON_MIN_COMMAND_LENGTH_TICKS - \
|
||||
(DENON_HDR_MARK_TICKS + DENON_HDR_SPACE_TICKS + \
|
||||
DENON_BITS * (DENON_BIT_MARK_TICKS + DENON_ONE_SPACE_TICKS) + \
|
||||
DENON_BIT_MARK_TICKS))
|
||||
#define DENON_MIN_GAP (DENON_MIN_GAP_TICKS * DENON_TICK)
|
||||
#define DENON_MANUFACTURER 0x2A4CULL
|
||||
const uint16_t kDenonTick = 263;
|
||||
const uint16_t kDenonHdrMarkTicks = 1;
|
||||
const uint16_t kDenonHdrMark = kDenonHdrMarkTicks * kDenonTick;
|
||||
const uint16_t kDenonHdrSpaceTicks = 3;
|
||||
const uint16_t kDenonHdrSpace = kDenonHdrSpaceTicks * kDenonTick;
|
||||
const uint16_t kDenonBitMarkTicks = 1;
|
||||
const uint16_t kDenonBitMark = kDenonBitMarkTicks * kDenonTick;
|
||||
const uint16_t kDenonOneSpaceTicks = 7;
|
||||
const uint16_t kDenonOneSpace = kDenonOneSpaceTicks * kDenonTick;
|
||||
const uint16_t kDenonZeroSpaceTicks = 3;
|
||||
const uint16_t kDenonZeroSpace = kDenonZeroSpaceTicks * kDenonTick;
|
||||
const uint16_t kDenonMinCommandLengthTicks = 510;
|
||||
const uint16_t kDenonMinGapTicks =
|
||||
kDenonMinCommandLengthTicks -
|
||||
(kDenonHdrMarkTicks + kDenonHdrSpaceTicks +
|
||||
kDenonBits * (kDenonBitMarkTicks + kDenonOneSpaceTicks) +
|
||||
kDenonBitMarkTicks);
|
||||
const uint32_t kDenonMinGap = kDenonMinGapTicks * kDenonTick;
|
||||
const uint64_t kDenonManufacturer = 0x2A4CULL;
|
||||
|
||||
#if SEND_DENON
|
||||
// Send a Denon message
|
||||
@@ -55,9 +55,9 @@
|
||||
// https://github.com/z3t0/Arduino-IRremote/blob/master/ir_Denon.cpp
|
||||
// http://assets.denon.com/documentmaster/us/denon%20master%20ir%20hex.xls
|
||||
void IRsend::sendDenon(uint64_t data, uint16_t nbits, uint16_t repeat) {
|
||||
if (nbits >= PANASONIC_BITS) // Is this really Panasonic?
|
||||
if (nbits >= kPanasonicBits) // Is this really Panasonic?
|
||||
sendPanasonic64(data, nbits, repeat);
|
||||
else if (nbits == DENON_LEGACY_BITS)
|
||||
else if (nbits == kDenonLegacyBits)
|
||||
// Support legacy (broken) calls of sendDenon().
|
||||
sendSharpRaw(data & (~0x2000ULL), nbits + 1, repeat);
|
||||
else
|
||||
@@ -84,7 +84,7 @@ bool IRrecv::decodeDenon(decode_results *results, uint16_t nbits, bool strict) {
|
||||
switch (nbits) {
|
||||
case DENON_BITS:
|
||||
case DENON_48_BITS:
|
||||
case DENON_LEGACY_BITS:
|
||||
case kDenonLegacyBits:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
@@ -99,40 +99,36 @@ bool IRrecv::decodeDenon(decode_results *results, uint16_t nbits, bool strict) {
|
||||
// manufacturer code.
|
||||
|
||||
if (!decodeSharp(results, nbits, true, false) &&
|
||||
!decodePanasonic(results, nbits, true, DENON_MANUFACTURER)) {
|
||||
!decodePanasonic(results, nbits, true, kDenonManufacturer)) {
|
||||
// We couldn't decode it as expected, so try the old legacy method.
|
||||
// NOTE: I don't think this following protocol actually exists.
|
||||
// Looks like a partial version of the Sharp protocol.
|
||||
// Check we have enough data
|
||||
if (results->rawlen < 2 * nbits + HEADER + FOOTER - 1)
|
||||
return false;
|
||||
if (strict && nbits != DENON_LEGACY_BITS)
|
||||
return false;
|
||||
if (results->rawlen < 2 * nbits + kHeader + kFooter - 1) return false;
|
||||
if (strict && nbits != kDenonLegacyBits) return false;
|
||||
|
||||
uint64_t data = 0;
|
||||
uint16_t offset = OFFSET_START;
|
||||
uint16_t offset = kStartOffset;
|
||||
|
||||
// Header
|
||||
if (!matchMark(results->rawbuf[offset], DENON_HDR_MARK)) return false;
|
||||
if (!matchMark(results->rawbuf[offset], kDenonHdrMark)) return false;
|
||||
// Calculate how long the common tick time is based on the header mark.
|
||||
uint32_t m_tick = results->rawbuf[offset++] * RAWTICK /
|
||||
DENON_HDR_MARK_TICKS;
|
||||
if (!matchSpace(results->rawbuf[offset], DENON_HDR_SPACE)) return false;
|
||||
uint32_t s_tick = results->rawbuf[offset++] * RAWTICK /
|
||||
DENON_HDR_SPACE_TICKS;
|
||||
uint32_t m_tick = results->rawbuf[offset++] * kRawTick / kDenonHdrMarkTicks;
|
||||
if (!matchSpace(results->rawbuf[offset], kDenonHdrSpace)) return false;
|
||||
uint32_t s_tick =
|
||||
results->rawbuf[offset++] * kRawTick / kDenonHdrSpaceTicks;
|
||||
|
||||
// Data
|
||||
match_result_t data_result = matchData(&(results->rawbuf[offset]), nbits,
|
||||
DENON_BIT_MARK_TICKS * m_tick,
|
||||
DENON_ONE_SPACE_TICKS * s_tick,
|
||||
DENON_BIT_MARK_TICKS * m_tick,
|
||||
DENON_ZERO_SPACE_TICKS * s_tick);
|
||||
match_result_t data_result =
|
||||
matchData(&(results->rawbuf[offset]), nbits,
|
||||
kDenonBitMarkTicks * m_tick, kDenonOneSpaceTicks * s_tick,
|
||||
kDenonBitMarkTicks * m_tick, kDenonZeroSpaceTicks * s_tick);
|
||||
if (data_result.success == false) return false;
|
||||
data = data_result.data;
|
||||
offset += data_result.used;
|
||||
|
||||
// Footer
|
||||
if (!matchMark(results->rawbuf[offset++], DENON_BIT_MARK_TICKS * m_tick))
|
||||
if (!matchMark(results->rawbuf[offset++], kDenonBitMarkTicks * m_tick))
|
||||
return false;
|
||||
|
||||
// Success
|
||||
|
||||
@@ -18,19 +18,19 @@
|
||||
// Ref:
|
||||
// https://github.com/marcosamarinho/IRremoteESP8266/blob/master/ir_Dish.cpp
|
||||
// http://www.hifi-remote.com/wiki/index.php?title=Dish
|
||||
#define DISH_TICK 100U
|
||||
#define DISH_HDR_MARK_TICKS 4U
|
||||
#define DISH_HDR_MARK (DISH_HDR_MARK_TICKS * DISH_TICK)
|
||||
#define DISH_HDR_SPACE_TICKS 61U
|
||||
#define DISH_HDR_SPACE (DISH_HDR_SPACE_TICKS * DISH_TICK)
|
||||
#define DISH_BIT_MARK_TICKS 4U
|
||||
#define DISH_BIT_MARK (DISH_BIT_MARK_TICKS * DISH_TICK)
|
||||
#define DISH_ONE_SPACE_TICKS 17U
|
||||
#define DISH_ONE_SPACE (DISH_ONE_SPACE_TICKS * DISH_TICK)
|
||||
#define DISH_ZERO_SPACE_TICKS 28U
|
||||
#define DISH_ZERO_SPACE (DISH_ZERO_SPACE_TICKS * DISH_TICK)
|
||||
#define DISH_RPT_SPACE_TICKS DISH_HDR_SPACE_TICKS
|
||||
#define DISH_RPT_SPACE (DISH_RPT_SPACE_TICKS * DISH_TICK)
|
||||
const uint16_t kDishTick = 100;
|
||||
const uint16_t kDishHdrMarkTicks = 4;
|
||||
const uint16_t kDishHdrMark = kDishHdrMarkTicks * kDishTick;
|
||||
const uint16_t kDishHdrSpaceTicks = 61;
|
||||
const uint16_t kDishHdrSpace = kDishHdrSpaceTicks * kDishTick;
|
||||
const uint16_t kDishBitMarkTicks = 4;
|
||||
const uint16_t kDishBitMark = kDishBitMarkTicks * kDishTick;
|
||||
const uint16_t kDishOneSpaceTicks = 17;
|
||||
const uint16_t kDishOneSpace = kDishOneSpaceTicks * kDishTick;
|
||||
const uint16_t kDishZeroSpaceTicks = 28;
|
||||
const uint16_t kDishZeroSpace = kDishZeroSpaceTicks * kDishTick;
|
||||
const uint16_t kDishRptSpaceTicks = kDishHdrSpaceTicks;
|
||||
const uint16_t kDishRptSpace = kDishRptSpaceTicks * kDishTick;
|
||||
|
||||
#if SEND_DISH
|
||||
// Send an IR command to a DISH NETWORK device.
|
||||
@@ -57,14 +57,13 @@
|
||||
void IRsend::sendDISH(uint64_t data, uint16_t nbits, uint16_t repeat) {
|
||||
enableIROut(57600); // Set modulation freq. to 57.6kHz.
|
||||
// Header is only ever sent once.
|
||||
mark(DISH_HDR_MARK);
|
||||
space(DISH_HDR_SPACE);
|
||||
mark(kDishHdrMark);
|
||||
space(kDishHdrSpace);
|
||||
|
||||
sendGeneric(0, 0, // No headers from here on in.
|
||||
DISH_BIT_MARK, DISH_ONE_SPACE,
|
||||
DISH_BIT_MARK, DISH_ZERO_SPACE,
|
||||
DISH_BIT_MARK, DISH_RPT_SPACE,
|
||||
data, nbits, 57600, true, repeat, 50);
|
||||
kDishBitMark, kDishOneSpace, kDishBitMark, kDishZeroSpace,
|
||||
kDishBitMark, kDishRptSpace, data, nbits, 57600, true, repeat,
|
||||
50);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -73,7 +72,7 @@ void IRsend::sendDISH(uint64_t data, uint16_t nbits, uint16_t repeat) {
|
||||
//
|
||||
// Args:
|
||||
// results: Ptr to the data to decode and where to store the decode result.
|
||||
// nbits: Nr. of bits to expect in the data portion. Typically DISH_BITS.
|
||||
// nbits: Nr. of bits to expect in the data portion. Typically kDishBits.
|
||||
// strict: Flag to indicate if we strictly adhere to the specification.
|
||||
// Returns:
|
||||
// boolean: True if it can decode it, false if it can't.
|
||||
@@ -89,34 +88,32 @@ void IRsend::sendDISH(uint64_t data, uint16_t nbits, uint16_t repeat) {
|
||||
// http://lirc.sourceforge.net/remotes/echostar/301_501_3100_5100_58xx_59xx
|
||||
// https://github.com/marcosamarinho/IRremoteESP8266/blob/master/ir_Dish.cpp
|
||||
bool IRrecv::decodeDISH(decode_results *results, uint16_t nbits, bool strict) {
|
||||
if (results->rawlen < 2 * nbits + HEADER + FOOTER - 1)
|
||||
if (results->rawlen < 2 * nbits + kHeader + kFooter - 1)
|
||||
return false; // Not enough entries to be valid.
|
||||
if (strict && nbits != DISH_BITS)
|
||||
return false; // Not strictly compliant.
|
||||
if (strict && nbits != kDishBits) return false; // Not strictly compliant.
|
||||
|
||||
uint64_t data = 0;
|
||||
uint16_t offset = OFFSET_START;
|
||||
uint16_t offset = kStartOffset;
|
||||
|
||||
// Header
|
||||
if (!match(results->rawbuf[offset], DISH_HDR_MARK)) return false;
|
||||
if (!match(results->rawbuf[offset], kDishHdrMark)) return false;
|
||||
// Calculate how long the common tick time is based on the header mark.
|
||||
uint32_t m_tick = results->rawbuf[offset++] * RAWTICK / DISH_HDR_MARK_TICKS;
|
||||
if (!matchSpace(results->rawbuf[offset], DISH_HDR_SPACE)) return false;
|
||||
uint32_t m_tick = results->rawbuf[offset++] * kRawTick / kDishHdrMarkTicks;
|
||||
if (!matchSpace(results->rawbuf[offset], kDishHdrSpace)) return false;
|
||||
// Calculate how long the common tick time is based on the header space.
|
||||
uint32_t s_tick = results->rawbuf[offset++] * RAWTICK / DISH_HDR_SPACE_TICKS;
|
||||
uint32_t s_tick = results->rawbuf[offset++] * kRawTick / kDishHdrSpaceTicks;
|
||||
|
||||
// Data
|
||||
match_result_t data_result = matchData(&(results->rawbuf[offset]), nbits,
|
||||
DISH_BIT_MARK_TICKS * m_tick,
|
||||
DISH_ONE_SPACE_TICKS * s_tick,
|
||||
DISH_BIT_MARK_TICKS * m_tick,
|
||||
DISH_ZERO_SPACE_TICKS * s_tick);
|
||||
match_result_t data_result =
|
||||
matchData(&(results->rawbuf[offset]), nbits, kDishBitMarkTicks * m_tick,
|
||||
kDishOneSpaceTicks * s_tick, kDishBitMarkTicks * m_tick,
|
||||
kDishZeroSpaceTicks * s_tick);
|
||||
if (data_result.success == false) return false;
|
||||
data = data_result.data;
|
||||
offset += data_result.used;
|
||||
|
||||
// Footer
|
||||
if (!matchMark(results->rawbuf[offset++], DISH_BIT_MARK_TICKS * m_tick))
|
||||
if (!matchMark(results->rawbuf[offset++], kDishBitMarkTicks * m_tick))
|
||||
return false;
|
||||
|
||||
// Compliance
|
||||
@@ -124,7 +121,7 @@ bool IRrecv::decodeDISH(decode_results *results, uint16_t nbits, bool strict) {
|
||||
// The DISH protocol calls for a repeated message, so strictly speaking
|
||||
// there should be a code following this. Only require it if we are set to
|
||||
// strict matching.
|
||||
if (!matchSpace(results->rawbuf[offset], DISH_RPT_SPACE_TICKS * s_tick))
|
||||
if (!matchSpace(results->rawbuf[offset], kDishRptSpaceTicks * s_tick))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
// Copyright 2018 David Conran
|
||||
|
||||
#include "IRrecv.h"
|
||||
#include "IRsend.h"
|
||||
#include "IRutils.h"
|
||||
|
||||
// EEEEEEE LL EEEEEEE CCCCC TTTTTTT RRRRRR AAA
|
||||
// EE LL EE CC C TTT RR RR AAAAA
|
||||
// EEEEE LL EEEEE CC TTT RRRRRR AA AA
|
||||
// EE LL EE CC C TTT RR RR AAAAAAA
|
||||
// EEEEEEE LLLLLLL EEEEEEE CCCCC TTT RR RR AA AA
|
||||
|
||||
// Electra A/C added by crankyoldgit
|
||||
//
|
||||
// Equipment it seems compatible with:
|
||||
// * <Add models (A/C & remotes) you've gotten it working with here>
|
||||
|
||||
// Ref:
|
||||
// https://github.com/markszabo/IRremoteESP8266/issues/527
|
||||
|
||||
// Constants
|
||||
const uint16_t kElectraAcHdrMark = 9166;
|
||||
const uint16_t kElectraAcBitMark = 646;
|
||||
const uint16_t kElectraAcHdrSpace = 4470;
|
||||
const uint16_t kElectraAcOneSpace = 1647;
|
||||
const uint16_t kElectraAcZeroSpace = 547;
|
||||
const uint32_t kElectraAcMessageGap = 100000; // Completely made-up guess.
|
||||
|
||||
#if SEND_ELECTRA_AC
|
||||
// Send a Electra message
|
||||
//
|
||||
// Args:
|
||||
// data: Contents of the message to be sent. (Guessing MSBF order)
|
||||
// nbits: Nr. of bits of data to be sent. Typically kElectraAcBits.
|
||||
// repeat: Nr. of additional times the message is to be sent.
|
||||
//
|
||||
// Status: Alpha / Needs testing against a real device.
|
||||
//
|
||||
void IRsend::sendElectraAC(uint8_t data[], uint16_t nbytes, uint16_t repeat) {
|
||||
for (uint16_t r = 0; r <= repeat; r++)
|
||||
sendGeneric(kElectraAcHdrMark, kElectraAcHdrSpace, kElectraAcBitMark,
|
||||
kElectraAcOneSpace, kElectraAcBitMark, kElectraAcZeroSpace,
|
||||
kElectraAcBitMark, kElectraAcMessageGap, data, nbytes,
|
||||
38000, // Complete guess of the modulation frequency.
|
||||
true, 0, 50);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DECODE_ELECTRA_AC
|
||||
// Decode the supplied Electra A/C message.
|
||||
//
|
||||
// Args:
|
||||
// results: Ptr to the data to decode and where to store the decode result.
|
||||
// nbits: The number of data bits to expect. Typically kElectraAcBits.
|
||||
// strict: Flag indicating if we should perform strict matching.
|
||||
// Returns:
|
||||
// boolean: True if it can decode it, false if it can't.
|
||||
//
|
||||
// Status: Alpha / Needs testing against a real device.
|
||||
//
|
||||
bool IRrecv::decodeElectraAC(decode_results *results, uint16_t nbits,
|
||||
bool strict) {
|
||||
if (nbits % 8 != 0) // nbits has to be a multiple of nr. of bits in a byte.
|
||||
return false;
|
||||
|
||||
if (strict) {
|
||||
if (nbits != kElectraAcBits)
|
||||
return false; // Not strictly a ELECTRA_AC message.
|
||||
}
|
||||
|
||||
// The protocol sends the data normal + inverted, alternating on
|
||||
// each byte. Hence twice the number of expected data bits.
|
||||
if (results->rawlen < 2 * nbits + kHeader + kFooter - 1)
|
||||
return false; // Can't possibly be a valid ELECTRA_AC message.
|
||||
|
||||
uint16_t offset = kStartOffset;
|
||||
|
||||
// Message Header
|
||||
if (!matchMark(results->rawbuf[offset++], kElectraAcHdrMark)) return false;
|
||||
if (!matchSpace(results->rawbuf[offset++], kElectraAcHdrSpace)) return false;
|
||||
|
||||
// Data Section
|
||||
match_result_t data_result;
|
||||
uint16_t dataBitsSoFar = 0;
|
||||
// Keep reading bytes until we either run out of section or state to fill.
|
||||
for (uint16_t i = 0; offset <= results->rawlen - 16 && i < nbits / 8;
|
||||
i++, dataBitsSoFar += 8, offset += data_result.used) {
|
||||
data_result = matchData(&(results->rawbuf[offset]), 8, kElectraAcBitMark,
|
||||
kElectraAcOneSpace, kElectraAcBitMark,
|
||||
kElectraAcZeroSpace, kTolerance, 0, true);
|
||||
if (data_result.success == false) return false; // Fail
|
||||
results->state[i] = data_result.data;
|
||||
}
|
||||
|
||||
// Message Footer
|
||||
if (!matchMark(results->rawbuf[offset++], kElectraAcBitMark)) return false;
|
||||
if (offset <= results->rawlen &&
|
||||
!matchAtLeast(results->rawbuf[offset++], kElectraAcMessageGap))
|
||||
return false;
|
||||
|
||||
// Compliance
|
||||
if (strict && dataBitsSoFar != nbits) return false;
|
||||
|
||||
// Success
|
||||
results->decode_type = ELECTRA_AC;
|
||||
results->bits = dataBitsSoFar;
|
||||
// No need to record the state as we stored it as we decoded it.
|
||||
// As we use result->state, we don't record value, address, or command as it
|
||||
// is a union data type.
|
||||
return true;
|
||||
}
|
||||
#endif // DECODE_ELECTRA_AC
|
||||
@@ -7,7 +7,6 @@
|
||||
#include "IRsend.h"
|
||||
#include "IRutils.h"
|
||||
|
||||
|
||||
// Fujitsu A/C support added by Jonny Graham & David Conran
|
||||
|
||||
// Equipment it seems compatible with:
|
||||
@@ -17,12 +16,12 @@
|
||||
|
||||
// Ref:
|
||||
// These values are based on averages of measurements
|
||||
#define FUJITSU_AC_HDR_MARK 3324U
|
||||
#define FUJITSU_AC_HDR_SPACE 1574U
|
||||
#define FUJITSU_AC_BIT_MARK 448U
|
||||
#define FUJITSU_AC_ONE_SPACE 1182U
|
||||
#define FUJITSU_AC_ZERO_SPACE 390U
|
||||
#define FUJITSU_AC_MIN_GAP 8100U
|
||||
const uint16_t kFujitsuAcHdrMark = 3324;
|
||||
const uint16_t kFujitsuAcHdrSpace = 1574;
|
||||
const uint16_t kFujitsuAcBitMark = 448;
|
||||
const uint16_t kFujitsuAcOneSpace = 1182;
|
||||
const uint16_t kFujitsuAcZeroSpace = 390;
|
||||
const uint16_t kFujitsuAcMinGap = 8100;
|
||||
|
||||
#if SEND_FUJITSU_AC
|
||||
// Send a Fujitsu A/C message.
|
||||
@@ -30,22 +29,21 @@
|
||||
// Args:
|
||||
// data: An array of bytes containing the IR command.
|
||||
// nbytes: Nr. of bytes of data in the array. Typically one of:
|
||||
// FUJITSU_AC_STATE_LENGTH
|
||||
// FUJITSU_AC_STATE_LENGTH - 1
|
||||
// FUJITSU_AC_STATE_LENGTH_SHORT
|
||||
// FUJITSU_AC_STATE_LENGTH_SHORT - 1
|
||||
// kFujitsuAcStateLength
|
||||
// kFujitsuAcStateLength - 1
|
||||
// kFujitsuAcStateLengthShort
|
||||
// kFujitsuAcStateLengthShort - 1
|
||||
// repeat: Nr. of times the message is to be repeated.
|
||||
// (Default = FUJITSU_AC_MIN_REPEAT).
|
||||
// (Default = kFujitsuAcMinRepeat).
|
||||
//
|
||||
// Status: BETA / Appears to be working.
|
||||
//
|
||||
void IRsend::sendFujitsuAC(unsigned char data[], uint16_t nbytes,
|
||||
uint16_t repeat) {
|
||||
sendGeneric(FUJITSU_AC_HDR_MARK, FUJITSU_AC_HDR_SPACE,
|
||||
FUJITSU_AC_BIT_MARK, FUJITSU_AC_ONE_SPACE,
|
||||
FUJITSU_AC_BIT_MARK, FUJITSU_AC_ZERO_SPACE,
|
||||
FUJITSU_AC_BIT_MARK, FUJITSU_AC_MIN_GAP,
|
||||
data, nbytes, 38, false, repeat, 50);
|
||||
sendGeneric(kFujitsuAcHdrMark, kFujitsuAcHdrSpace, kFujitsuAcBitMark,
|
||||
kFujitsuAcOneSpace, kFujitsuAcBitMark, kFujitsuAcZeroSpace,
|
||||
kFujitsuAcBitMark, kFujitsuAcMinGap, data, nbytes, 38, false,
|
||||
repeat, 50);
|
||||
}
|
||||
#endif // SEND_FUJITSU_AC
|
||||
|
||||
@@ -62,29 +60,27 @@ void IRFujitsuAC::setModel(fujitsu_ac_remote_model_t model) {
|
||||
_model = model;
|
||||
switch (model) {
|
||||
case ARDB1:
|
||||
_state_length = FUJITSU_AC_STATE_LENGTH - 1;
|
||||
_state_length_short = FUJITSU_AC_STATE_LENGTH_SHORT - 1;
|
||||
_state_length = kFujitsuAcStateLength - 1;
|
||||
_state_length_short = kFujitsuAcStateLengthShort - 1;
|
||||
break;
|
||||
default:
|
||||
_state_length = FUJITSU_AC_STATE_LENGTH;
|
||||
_state_length_short = FUJITSU_AC_STATE_LENGTH_SHORT;
|
||||
_state_length = kFujitsuAcStateLength;
|
||||
_state_length_short = kFujitsuAcStateLengthShort;
|
||||
}
|
||||
}
|
||||
|
||||
// Reset the state of the remote to a known good state/sequence.
|
||||
void IRFujitsuAC::stateReset() {
|
||||
_temp = 24;
|
||||
_fanSpeed = FUJITSU_AC_FAN_HIGH;
|
||||
_mode = FUJITSU_AC_MODE_COOL;
|
||||
_swingMode = FUJITSU_AC_SWING_BOTH;
|
||||
_cmd = FUJITSU_AC_CMD_TURN_ON;
|
||||
_fanSpeed = kFujitsuAcFanHigh;
|
||||
_mode = kFujitsuAcModeCool;
|
||||
_swingMode = kFujitsuAcSwingBoth;
|
||||
_cmd = kFujitsuAcCmdTurnOn;
|
||||
buildState();
|
||||
}
|
||||
|
||||
// Configure the pin for output.
|
||||
void IRFujitsuAC::begin() {
|
||||
_irsend.begin();
|
||||
}
|
||||
void IRFujitsuAC::begin() { _irsend.begin(); }
|
||||
|
||||
#if SEND_FUJITSU_AC
|
||||
// Send the current desired state to the IR LED.
|
||||
@@ -102,13 +98,13 @@ void IRFujitsuAC::buildState() {
|
||||
remote_state[4] = 0x10;
|
||||
bool fullCmd = false;
|
||||
switch (_cmd) {
|
||||
case FUJITSU_AC_CMD_TURN_OFF:
|
||||
case kFujitsuAcCmdTurnOff:
|
||||
remote_state[5] = 0x02;
|
||||
break;
|
||||
case FUJITSU_AC_CMD_STEP_HORIZ:
|
||||
case kFujitsuAcCmdStepHoriz:
|
||||
remote_state[5] = 0x79;
|
||||
break;
|
||||
case FUJITSU_AC_CMD_STEP_VERT:
|
||||
case kFujitsuAcCmdStepVert:
|
||||
remote_state[5] = 0x6C;
|
||||
break;
|
||||
default:
|
||||
@@ -124,12 +120,12 @@ void IRFujitsuAC::buildState() {
|
||||
break;
|
||||
}
|
||||
if (fullCmd) { // long codes
|
||||
uint8_t tempByte = _temp - FUJITSU_AC_MIN_TEMP;
|
||||
uint8_t tempByte = _temp - kFujitsuAcMinTemp;
|
||||
// Nr. of bytes in the message after this byte.
|
||||
remote_state[6] = _state_length - 7;
|
||||
|
||||
remote_state[7] = 0x30;
|
||||
remote_state[8] = (_cmd == FUJITSU_AC_CMD_TURN_ON) | (tempByte << 4);
|
||||
remote_state[8] = (_cmd == kFujitsuAcCmdTurnOn) | (tempByte << 4);
|
||||
remote_state[9] = _mode | 0 << 4; // timer off
|
||||
remote_state[10] = _fanSpeed | _swingMode << 4;
|
||||
remote_state[11] = 0; // timerOff values
|
||||
@@ -154,12 +150,10 @@ void IRFujitsuAC::buildState() {
|
||||
} else { // short codes
|
||||
if (_model == ARRAH2E)
|
||||
// The last byte is the inverse of penultimate byte
|
||||
remote_state[_state_length_short - 1] = ~remote_state[_state_length_short
|
||||
- 2];
|
||||
remote_state[_state_length_short - 1] =
|
||||
~remote_state[_state_length_short - 2];
|
||||
// Zero the rest of the state.
|
||||
for (uint8_t i = _state_length_short;
|
||||
i < FUJITSU_AC_STATE_LENGTH;
|
||||
i++)
|
||||
for (uint8_t i = _state_length_short; i < kFujitsuAcStateLength; i++)
|
||||
remote_state[i] = 0;
|
||||
}
|
||||
}
|
||||
@@ -181,8 +175,8 @@ uint8_t* IRFujitsuAC::getRaw() {
|
||||
|
||||
void IRFujitsuAC::buildFromState(const uint16_t length) {
|
||||
switch (length) {
|
||||
case FUJITSU_AC_STATE_LENGTH - 1:
|
||||
case FUJITSU_AC_STATE_LENGTH_SHORT - 1:
|
||||
case kFujitsuAcStateLength - 1:
|
||||
case kFujitsuAcStateLengthShort - 1:
|
||||
setModel(ARDB1);
|
||||
break;
|
||||
default:
|
||||
@@ -196,26 +190,26 @@ void IRFujitsuAC::buildFromState(const uint16_t length) {
|
||||
setModel(ARRAH2E);
|
||||
break;
|
||||
}
|
||||
setTemp((remote_state[8] >> 4) + FUJITSU_AC_MIN_TEMP);
|
||||
setTemp((remote_state[8] >> 4) + kFujitsuAcMinTemp);
|
||||
if (remote_state[8] & 0x1)
|
||||
setCmd(FUJITSU_AC_CMD_TURN_ON);
|
||||
setCmd(kFujitsuAcCmdTurnOn);
|
||||
else
|
||||
setCmd(FUJITSU_AC_CMD_STAY_ON);
|
||||
setCmd(kFujitsuAcCmdStayOn);
|
||||
setMode(remote_state[9] & 0b111);
|
||||
setFanSpeed(remote_state[10] & 0b111);
|
||||
setSwing(remote_state[10] >> 4);
|
||||
switch (remote_state[5]) {
|
||||
case FUJITSU_AC_CMD_TURN_OFF:
|
||||
case FUJITSU_AC_CMD_STEP_HORIZ:
|
||||
case FUJITSU_AC_CMD_STEP_VERT:
|
||||
case kFujitsuAcCmdTurnOff:
|
||||
case kFujitsuAcCmdStepHoriz:
|
||||
case kFujitsuAcCmdStepVert:
|
||||
setCmd(remote_state[5]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool IRFujitsuAC::setRaw(const uint8_t newState[], const uint16_t length) {
|
||||
if (length > FUJITSU_AC_STATE_LENGTH) return false;
|
||||
for (uint16_t i = 0; i < FUJITSU_AC_STATE_LENGTH; i++) {
|
||||
if (length > kFujitsuAcStateLength) return false;
|
||||
for (uint16_t i = 0; i < kFujitsuAcStateLength; i++) {
|
||||
if (i < length)
|
||||
remote_state[i] = newState[i];
|
||||
else
|
||||
@@ -226,119 +220,103 @@ bool IRFujitsuAC::setRaw(const uint8_t newState[], const uint16_t length) {
|
||||
}
|
||||
|
||||
// Set the requested power state of the A/C to off.
|
||||
void IRFujitsuAC::off() {
|
||||
_cmd = FUJITSU_AC_CMD_TURN_OFF;
|
||||
}
|
||||
void IRFujitsuAC::off() { _cmd = kFujitsuAcCmdTurnOff; }
|
||||
|
||||
void IRFujitsuAC::stepHoriz() {
|
||||
switch (_model) {
|
||||
case ARDB1: break; // This remote doesn't have a horizontal option.
|
||||
case ARDB1:
|
||||
break; // This remote doesn't have a horizontal option.
|
||||
default:
|
||||
_cmd = FUJITSU_AC_CMD_STEP_HORIZ;
|
||||
_cmd = kFujitsuAcCmdStepHoriz;
|
||||
}
|
||||
}
|
||||
|
||||
void IRFujitsuAC::stepVert() {
|
||||
_cmd = FUJITSU_AC_CMD_STEP_VERT;
|
||||
}
|
||||
void IRFujitsuAC::stepVert() { _cmd = kFujitsuAcCmdStepVert; }
|
||||
|
||||
// Set the requested command of the A/C.
|
||||
void IRFujitsuAC::setCmd(uint8_t cmd) {
|
||||
switch (cmd) {
|
||||
case FUJITSU_AC_CMD_TURN_OFF:
|
||||
case FUJITSU_AC_CMD_TURN_ON:
|
||||
case FUJITSU_AC_CMD_STAY_ON:
|
||||
case FUJITSU_AC_CMD_STEP_VERT:
|
||||
case kFujitsuAcCmdTurnOff:
|
||||
case kFujitsuAcCmdTurnOn:
|
||||
case kFujitsuAcCmdStayOn:
|
||||
case kFujitsuAcCmdStepVert:
|
||||
_cmd = cmd;
|
||||
break;
|
||||
case FUJITSU_AC_CMD_STEP_HORIZ:
|
||||
case kFujitsuAcCmdStepHoriz:
|
||||
if (_model != ARDB1) // AR-DB1 remote doesn't have step horizontal.
|
||||
_cmd = cmd;
|
||||
// FALLTHRU
|
||||
default:
|
||||
_cmd = FUJITSU_AC_CMD_STAY_ON;
|
||||
_cmd = kFujitsuAcCmdStayOn;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t IRFujitsuAC::getCmd() {
|
||||
return _cmd;
|
||||
}
|
||||
uint8_t IRFujitsuAC::getCmd() { return _cmd; }
|
||||
|
||||
bool IRFujitsuAC::getPower() {
|
||||
return _cmd != FUJITSU_AC_CMD_TURN_OFF;
|
||||
}
|
||||
bool IRFujitsuAC::getPower() { return _cmd != kFujitsuAcCmdTurnOff; }
|
||||
|
||||
// Set the temp. in deg C
|
||||
void IRFujitsuAC::setTemp(uint8_t temp) {
|
||||
temp = std::max((uint8_t) FUJITSU_AC_MIN_TEMP, temp);
|
||||
temp = std::min((uint8_t) FUJITSU_AC_MAX_TEMP, temp);
|
||||
temp = std::max((uint8_t)kFujitsuAcMinTemp, temp);
|
||||
temp = std::min((uint8_t)kFujitsuAcMaxTemp, temp);
|
||||
_temp = temp;
|
||||
}
|
||||
|
||||
uint8_t IRFujitsuAC::getTemp() {
|
||||
return _temp;
|
||||
}
|
||||
uint8_t IRFujitsuAC::getTemp() { return _temp; }
|
||||
|
||||
// Set the speed of the fan
|
||||
void IRFujitsuAC::setFanSpeed(uint8_t fanSpeed) {
|
||||
if (fanSpeed > FUJITSU_AC_FAN_QUIET)
|
||||
fanSpeed = FUJITSU_AC_FAN_HIGH; // Set the fan to maximum if out of range.
|
||||
if (fanSpeed > kFujitsuAcFanQuiet)
|
||||
fanSpeed = kFujitsuAcFanHigh; // Set the fan to maximum if out of range.
|
||||
_fanSpeed = fanSpeed;
|
||||
}
|
||||
uint8_t IRFujitsuAC::getFanSpeed() {
|
||||
return _fanSpeed;
|
||||
}
|
||||
uint8_t IRFujitsuAC::getFanSpeed() { return _fanSpeed; }
|
||||
|
||||
// Set the requested climate operation mode of the a/c unit.
|
||||
void IRFujitsuAC::setMode(uint8_t mode) {
|
||||
if (mode > FUJITSU_AC_MODE_HEAT)
|
||||
mode = FUJITSU_AC_MODE_HEAT; // Set the mode to maximum if out of range.
|
||||
if (mode > kFujitsuAcModeHeat)
|
||||
mode = kFujitsuAcModeHeat; // Set the mode to maximum if out of range.
|
||||
_mode = mode;
|
||||
}
|
||||
|
||||
uint8_t IRFujitsuAC::getMode() {
|
||||
return _mode;
|
||||
}
|
||||
uint8_t IRFujitsuAC::getMode() { return _mode; }
|
||||
// Set the requested swing operation mode of the a/c unit.
|
||||
void IRFujitsuAC::setSwing(uint8_t swingMode) {
|
||||
switch (_model) {
|
||||
case ARDB1:
|
||||
// Set the mode to max if out of range
|
||||
if (swingMode > FUJITSU_AC_SWING_VERT)
|
||||
swingMode = FUJITSU_AC_SWING_VERT;
|
||||
if (swingMode > kFujitsuAcSwingVert) swingMode = kFujitsuAcSwingVert;
|
||||
break;
|
||||
case ARRAH2E:
|
||||
default:
|
||||
// Set the mode to max if out of range
|
||||
if (swingMode > FUJITSU_AC_SWING_BOTH)
|
||||
swingMode = FUJITSU_AC_SWING_BOTH;
|
||||
if (swingMode > kFujitsuAcSwingBoth) swingMode = kFujitsuAcSwingBoth;
|
||||
}
|
||||
_swingMode = swingMode;
|
||||
}
|
||||
|
||||
uint8_t IRFujitsuAC::getSwing() {
|
||||
return _swingMode;
|
||||
}
|
||||
uint8_t IRFujitsuAC::getSwing() { return _swingMode; }
|
||||
|
||||
bool IRFujitsuAC::validChecksum(uint8_t state[], uint16_t length) {
|
||||
uint8_t sum = 0;
|
||||
uint8_t sum_complement = 0;
|
||||
uint8_t checksum = 0;
|
||||
uint8_t checksum = state[length - 1];
|
||||
switch (length) {
|
||||
case FUJITSU_AC_STATE_LENGTH_SHORT: // ARRAH2E
|
||||
return state[length - 1] == (uint8_t) ~state[length - 2];
|
||||
case FUJITSU_AC_STATE_LENGTH - 1: // ARDB1
|
||||
case kFujitsuAcStateLengthShort: // ARRAH2E
|
||||
return state[length - 1] == (uint8_t)~state[length - 2];
|
||||
case kFujitsuAcStateLength - 1: // ARDB1
|
||||
sum = sumBytes(state, length - 1);
|
||||
sum_complement = 0x9B;
|
||||
checksum = state[length - 1];
|
||||
break;
|
||||
case FUJITSU_AC_STATE_LENGTH: // ARRAH2E
|
||||
sum = sumBytes(state + FUJITSU_AC_STATE_LENGTH_SHORT,
|
||||
length - 1 - FUJITSU_AC_STATE_LENGTH_SHORT);
|
||||
default: // Includes ARDB1 short.
|
||||
case kFujitsuAcStateLength: // ARRAH2E
|
||||
sum = sumBytes(state + kFujitsuAcStateLengthShort,
|
||||
length - 1 - kFujitsuAcStateLengthShort);
|
||||
break;
|
||||
default: // Includes ARDB1 short.
|
||||
return true; // Assume the checksum is valid for other lengths.
|
||||
}
|
||||
return checksum == (uint8_t) (sum_complement - sum); // Does it match?
|
||||
return checksum == (uint8_t)(sum_complement - sum); // Does it match?
|
||||
}
|
||||
|
||||
// Convert the internal state into a human readable string.
|
||||
@@ -356,19 +334,19 @@ std::string IRFujitsuAC::toString() {
|
||||
result += "Off";
|
||||
result += ", Mode: " + uint64ToString(getMode());
|
||||
switch (getMode()) {
|
||||
case FUJITSU_AC_MODE_AUTO:
|
||||
case kFujitsuAcModeAuto:
|
||||
result += " (AUTO)";
|
||||
break;
|
||||
case FUJITSU_AC_MODE_COOL:
|
||||
case kFujitsuAcModeCool:
|
||||
result += " (COOL)";
|
||||
break;
|
||||
case FUJITSU_AC_MODE_HEAT:
|
||||
case kFujitsuAcModeHeat:
|
||||
result += " (HEAT)";
|
||||
break;
|
||||
case FUJITSU_AC_MODE_DRY:
|
||||
case kFujitsuAcModeDry:
|
||||
result += " (DRY)";
|
||||
break;
|
||||
case FUJITSU_AC_MODE_FAN:
|
||||
case kFujitsuAcModeFan:
|
||||
result += " (FAN)";
|
||||
break;
|
||||
default:
|
||||
@@ -377,34 +355,34 @@ std::string IRFujitsuAC::toString() {
|
||||
result += ", Temp: " + uint64ToString(getTemp()) + "C";
|
||||
result += ", Fan: " + uint64ToString(getFanSpeed());
|
||||
switch (getFanSpeed()) {
|
||||
case FUJITSU_AC_FAN_AUTO:
|
||||
case kFujitsuAcFanAuto:
|
||||
result += " (AUTO)";
|
||||
break;
|
||||
case FUJITSU_AC_FAN_HIGH:
|
||||
case kFujitsuAcFanHigh:
|
||||
result += " (HIGH)";
|
||||
break;
|
||||
case FUJITSU_AC_FAN_MED:
|
||||
case kFujitsuAcFanMed:
|
||||
result += " (MED)";
|
||||
break;
|
||||
case FUJITSU_AC_FAN_LOW:
|
||||
case kFujitsuAcFanLow:
|
||||
result += " (LOW)";
|
||||
break;
|
||||
case FUJITSU_AC_FAN_QUIET:
|
||||
case kFujitsuAcFanQuiet:
|
||||
result += " (QUIET)";
|
||||
break;
|
||||
}
|
||||
result += ", Swing: ";
|
||||
switch (getSwing()) {
|
||||
case FUJITSU_AC_SWING_OFF:
|
||||
case kFujitsuAcSwingOff:
|
||||
result += "Off";
|
||||
break;
|
||||
case FUJITSU_AC_SWING_VERT:
|
||||
case kFujitsuAcSwingVert:
|
||||
result += "Vert";
|
||||
break;
|
||||
case FUJITSU_AC_SWING_HORIZ:
|
||||
case kFujitsuAcSwingHoriz:
|
||||
result += "Horiz";
|
||||
break;
|
||||
case FUJITSU_AC_SWING_BOTH:
|
||||
case kFujitsuAcSwingBoth:
|
||||
result += "Vert + Horiz";
|
||||
break;
|
||||
default:
|
||||
@@ -412,14 +390,14 @@ std::string IRFujitsuAC::toString() {
|
||||
}
|
||||
result += ", Command: ";
|
||||
switch (getCmd()) {
|
||||
case FUJITSU_AC_CMD_STEP_HORIZ:
|
||||
case kFujitsuAcCmdStepHoriz:
|
||||
result += "Step vane horizontally";
|
||||
break;
|
||||
case FUJITSU_AC_CMD_STEP_VERT:
|
||||
case kFujitsuAcCmdStepVert:
|
||||
result += "Step vane vertically";
|
||||
break;
|
||||
default:
|
||||
result += "N/A";
|
||||
result += "N/A";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -429,7 +407,7 @@ std::string IRFujitsuAC::toString() {
|
||||
// Places successful decode information in the results pointer.
|
||||
// Args:
|
||||
// results: Ptr to the data to decode and where to store the decode result.
|
||||
// nbits: The number of data bits to expect. Typically FUJITSU_AC_BITS.
|
||||
// nbits: The number of data bits to expect. Typically kFujitsuAcBits.
|
||||
// strict: Flag to indicate if we strictly adhere to the specification.
|
||||
// Returns:
|
||||
// boolean: True if it can decode it, false if it can't.
|
||||
@@ -438,23 +416,22 @@ std::string IRFujitsuAC::toString() {
|
||||
//
|
||||
// Ref:
|
||||
//
|
||||
bool IRrecv::decodeFujitsuAC(decode_results *results, uint16_t nbits,
|
||||
bool IRrecv::decodeFujitsuAC(decode_results* results, uint16_t nbits,
|
||||
bool strict) {
|
||||
uint16_t offset = OFFSET_START;
|
||||
uint16_t offset = kStartOffset;
|
||||
uint16_t dataBitsSoFar = 0;
|
||||
|
||||
// Have we got enough data to successfully decode?
|
||||
if (results->rawlen < (2 * FUJITSU_AC_MIN_BITS) + HEADER + FOOTER - 1)
|
||||
if (results->rawlen < (2 * kFujitsuAcMinBits) + kHeader + kFooter - 1)
|
||||
return false; // Can't possibly be a valid message.
|
||||
|
||||
|
||||
// Compliance
|
||||
if (strict) {
|
||||
switch (nbits) {
|
||||
case FUJITSU_AC_BITS:
|
||||
case FUJITSU_AC_BITS - 8:
|
||||
case FUJITSU_AC_MIN_BITS:
|
||||
case FUJITSU_AC_MIN_BITS + 8:
|
||||
case kFujitsuAcBits:
|
||||
case kFujitsuAcBits - 8:
|
||||
case kFujitsuAcMinBits:
|
||||
case kFujitsuAcMinBits + 8:
|
||||
break;
|
||||
default:
|
||||
return false; // Must be called with the correct nr. of bits.
|
||||
@@ -462,22 +439,17 @@ bool IRrecv::decodeFujitsuAC(decode_results *results, uint16_t nbits,
|
||||
}
|
||||
|
||||
// Header
|
||||
if (!matchMark(results->rawbuf[offset++], FUJITSU_AC_HDR_MARK))
|
||||
return false;
|
||||
if (!matchSpace(results->rawbuf[offset++], FUJITSU_AC_HDR_SPACE))
|
||||
return false;
|
||||
if (!matchMark(results->rawbuf[offset++], kFujitsuAcHdrMark)) return false;
|
||||
if (!matchSpace(results->rawbuf[offset++], kFujitsuAcHdrSpace)) return false;
|
||||
|
||||
// Data (Fixed signature)
|
||||
match_result_t data_result = matchData(&(results->rawbuf[offset]),
|
||||
FUJITSU_AC_MIN_BITS - 8,
|
||||
FUJITSU_AC_BIT_MARK,
|
||||
FUJITSU_AC_ONE_SPACE,
|
||||
FUJITSU_AC_BIT_MARK,
|
||||
FUJITSU_AC_ZERO_SPACE);
|
||||
if (data_result.success == false) return false; // Fail
|
||||
if (reverseBits(data_result.data, FUJITSU_AC_MIN_BITS - 8) != 0x1010006314)
|
||||
return false; // Signature failed.
|
||||
dataBitsSoFar += FUJITSU_AC_MIN_BITS - 8;
|
||||
match_result_t data_result =
|
||||
matchData(&(results->rawbuf[offset]), kFujitsuAcMinBits - 8,
|
||||
kFujitsuAcBitMark, kFujitsuAcOneSpace, kFujitsuAcBitMark,
|
||||
kFujitsuAcZeroSpace, kTolerance, kMarkExcess, false);
|
||||
if (data_result.success == false) return false; // Fail
|
||||
if (data_result.data != 0x1010006314) return false; // Signature failed.
|
||||
dataBitsSoFar += kFujitsuAcMinBits - 8;
|
||||
offset += data_result.used;
|
||||
results->state[0] = 0x14;
|
||||
results->state[1] = 0x63;
|
||||
@@ -487,27 +459,27 @@ bool IRrecv::decodeFujitsuAC(decode_results *results, uint16_t nbits,
|
||||
|
||||
// Keep reading bytes until we either run out of message or state to fill.
|
||||
for (uint16_t i = 5;
|
||||
offset <= results->rawlen - 16 && i < FUJITSU_AC_STATE_LENGTH;
|
||||
i++, dataBitsSoFar += 8, offset += data_result.used) {
|
||||
data_result = matchData(&(results->rawbuf[offset]), 8,
|
||||
FUJITSU_AC_BIT_MARK,
|
||||
FUJITSU_AC_ONE_SPACE,
|
||||
FUJITSU_AC_BIT_MARK,
|
||||
FUJITSU_AC_ZERO_SPACE);
|
||||
if (data_result.success == false) break; // Fail
|
||||
results->state[i] = (uint8_t) reverseBits(data_result.data, 8);
|
||||
offset <= results->rawlen - 16 && i < kFujitsuAcStateLength;
|
||||
i++, dataBitsSoFar += 8, offset += data_result.used) {
|
||||
data_result = matchData(
|
||||
&(results->rawbuf[offset]), 8, kFujitsuAcBitMark, kFujitsuAcOneSpace,
|
||||
kFujitsuAcBitMark, kFujitsuAcZeroSpace, kTolerance, kMarkExcess, false);
|
||||
if (data_result.success == false) break; // Fail
|
||||
results->state[i] = data_result.data;
|
||||
}
|
||||
|
||||
// Footer
|
||||
if (offset > results->rawlen ||
|
||||
!matchMark(results->rawbuf[offset++], FUJITSU_AC_BIT_MARK)) return false;
|
||||
!matchMark(results->rawbuf[offset++], kFujitsuAcBitMark))
|
||||
return false;
|
||||
// The space is optional if we are out of capture.
|
||||
if (offset < results->rawlen &&
|
||||
!matchAtLeast(results->rawbuf[offset], FUJITSU_AC_MIN_GAP)) return false;
|
||||
!matchAtLeast(results->rawbuf[offset], kFujitsuAcMinGap))
|
||||
return false;
|
||||
|
||||
// Compliance
|
||||
if (strict) {
|
||||
if (dataBitsSoFar != nbits) return false;
|
||||
if (dataBitsSoFar != nbits) return false;
|
||||
}
|
||||
|
||||
results->decode_type = FUJITSU_AC;
|
||||
@@ -515,25 +487,25 @@ bool IRrecv::decodeFujitsuAC(decode_results *results, uint16_t nbits,
|
||||
|
||||
// Compliance
|
||||
switch (dataBitsSoFar) {
|
||||
case FUJITSU_AC_MIN_BITS:
|
||||
case kFujitsuAcMinBits:
|
||||
// Check if this values indicate that this should have been a long state
|
||||
// message.
|
||||
if (results->state[5] == 0xFC) return false;
|
||||
if (results->state[5] == 0xFC) return false;
|
||||
return true; // Success
|
||||
case FUJITSU_AC_MIN_BITS + 8:
|
||||
case kFujitsuAcMinBits + 8:
|
||||
// Check if this values indicate that this should have been a long state
|
||||
// message.
|
||||
if (results->state[5] == 0xFE) return false;
|
||||
if (results->state[5] == 0xFE) return false;
|
||||
// The last byte needs to be the inverse of the penultimate byte.
|
||||
if (results->state[5] != (uint8_t) ~results->state[6]) return false;
|
||||
if (results->state[5] != (uint8_t)~results->state[6]) return false;
|
||||
return true; // Success
|
||||
case FUJITSU_AC_BITS - 8:
|
||||
case kFujitsuAcBits - 8:
|
||||
// Long messages of this size require this byte be correct.
|
||||
if (results->state[5] != 0xFC) return false;
|
||||
if (results->state[5] != 0xFC) return false;
|
||||
break;
|
||||
case FUJITSU_AC_BITS:
|
||||
case kFujitsuAcBits:
|
||||
// Long messages of this size require this byte be correct.
|
||||
if (results->state[5] != 0xFE) return false;
|
||||
if (results->state[5] != 0xFE) return false;
|
||||
break;
|
||||
default:
|
||||
return false; // Unexpected size.
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// Copyright 2017 Jonny Graham
|
||||
// Copyright 2018 David Conran
|
||||
#ifndef IR_FUJITSU_H_
|
||||
#define IR_FUJITSU_H_
|
||||
|
||||
@@ -9,41 +10,61 @@
|
||||
#else
|
||||
#include <string>
|
||||
#endif
|
||||
#include "IRremoteESP8266.h"
|
||||
#include "IRrecv.h"
|
||||
#include "IRremoteESP8266.h"
|
||||
#include "IRsend.h"
|
||||
|
||||
|
||||
// FUJITSU A/C support added by Jonny Graham
|
||||
|
||||
// Constants
|
||||
const uint8_t kFujitsuAcModeAuto = 0x00;
|
||||
const uint8_t kFujitsuAcModeCool = 0x01;
|
||||
const uint8_t kFujitsuAcModeDry = 0x02;
|
||||
const uint8_t kFujitsuAcModeFan = 0x03;
|
||||
const uint8_t kFujitsuAcModeHeat = 0x04;
|
||||
|
||||
#define FUJITSU_AC_MODE_AUTO 0x00U
|
||||
#define FUJITSU_AC_MODE_COOL 0x01U
|
||||
#define FUJITSU_AC_MODE_DRY 0x02U
|
||||
#define FUJITSU_AC_MODE_FAN 0x03U
|
||||
#define FUJITSU_AC_MODE_HEAT 0x04U
|
||||
const uint8_t kFujitsuAcCmdStayOn = 0x00;
|
||||
const uint8_t kFujitsuAcCmdTurnOn = 0x01;
|
||||
const uint8_t kFujitsuAcCmdTurnOff = 0x02;
|
||||
const uint8_t kFujitsuAcCmdStepHoriz = 0x79;
|
||||
const uint8_t kFujitsuAcCmdStepVert = 0x6C;
|
||||
|
||||
#define FUJITSU_AC_CMD_STAY_ON 0x00U
|
||||
#define FUJITSU_AC_CMD_TURN_ON 0x01U
|
||||
#define FUJITSU_AC_CMD_TURN_OFF 0x02U
|
||||
#define FUJITSU_AC_CMD_STEP_HORIZ 0x79U
|
||||
#define FUJITSU_AC_CMD_STEP_VERT 0x6CU
|
||||
const uint8_t kFujitsuAcFanAuto = 0x00;
|
||||
const uint8_t kFujitsuAcFanHigh = 0x01;
|
||||
const uint8_t kFujitsuAcFanMed = 0x02;
|
||||
const uint8_t kFujitsuAcFanLow = 0x03;
|
||||
const uint8_t kFujitsuAcFanQuiet = 0x04;
|
||||
|
||||
#define FUJITSU_AC_FAN_AUTO 0x00U
|
||||
#define FUJITSU_AC_FAN_HIGH 0x01U
|
||||
#define FUJITSU_AC_FAN_MED 0x02U
|
||||
#define FUJITSU_AC_FAN_LOW 0x03U
|
||||
#define FUJITSU_AC_FAN_QUIET 0x04U
|
||||
const uint8_t kFujitsuAcMinTemp = 16; // 16C
|
||||
const uint8_t kFujitsuAcMaxTemp = 30; // 30C
|
||||
|
||||
#define FUJITSU_AC_MIN_TEMP 16U // 16C
|
||||
#define FUJITSU_AC_MAX_TEMP 30U // 30C
|
||||
|
||||
#define FUJITSU_AC_SWING_OFF 0x00U
|
||||
#define FUJITSU_AC_SWING_VERT 0x01U
|
||||
#define FUJITSU_AC_SWING_HORIZ 0x02U
|
||||
#define FUJITSU_AC_SWING_BOTH 0x03U
|
||||
const uint8_t kFujitsuAcSwingOff = 0x00;
|
||||
const uint8_t kFujitsuAcSwingVert = 0x01;
|
||||
const uint8_t kFujitsuAcSwingHoriz = 0x02;
|
||||
const uint8_t kFujitsuAcSwingBoth = 0x03;
|
||||
|
||||
// Legacy defines.
|
||||
#define FUJITSU_AC_MODE_AUTO kFujitsuAcModeAuto
|
||||
#define FUJITSU_AC_MODE_COOL kFujitsuAcModeCool
|
||||
#define FUJITSU_AC_MODE_DRY kFujitsuAcModeDry
|
||||
#define FUJITSU_AC_MODE_FAN kFujitsuAcModeFan
|
||||
#define FUJITSU_AC_MODE_HEAT kFujitsuAcModeHeat
|
||||
#define FUJITSU_AC_CMD_STAY_ON kFujitsuAcCmdStayOn
|
||||
#define FUJITSU_AC_CMD_TURN_ON kFujitsuAcCmdTurnOn
|
||||
#define FUJITSU_AC_CMD_TURN_OFF kFujitsuAcCmdTurnOff
|
||||
#define FUJITSU_AC_CMD_STEP_HORIZ kFujitsuAcCmdStepHoriz
|
||||
#define FUJITSU_AC_CMD_STEP_VERT kFujitsuAcCmdStepVert
|
||||
#define FUJITSU_AC_FAN_AUTO kFujitsuAcFanAuto
|
||||
#define FUJITSU_AC_FAN_HIGH kFujitsuAcFanHigh
|
||||
#define FUJITSU_AC_FAN_MED kFujitsuAcFanMed
|
||||
#define FUJITSU_AC_FAN_LOW kFujitsuAcFanLow
|
||||
#define FUJITSU_AC_FAN_QUIET kFujitsuAcFanQuiet
|
||||
#define FUJITSU_AC_MIN_TEMP kFujitsuAcMinTemp
|
||||
#define FUJITSU_AC_MAX_TEMP kFujitsuAcMaxTemp
|
||||
#define FUJITSU_AC_SWING_OFF kFujitsuAcSwingOff
|
||||
#define FUJITSU_AC_SWING_VERT kFujitsuAcSwingVert
|
||||
#define FUJITSU_AC_SWING_HORIZ kFujitsuAcSwingHoriz
|
||||
#define FUJITSU_AC_SWING_BOTH kFujitsuAcSwingBoth
|
||||
|
||||
enum fujitsu_ac_remote_model_t {
|
||||
ARRAH2E = 1,
|
||||
@@ -76,16 +97,16 @@ class IRFujitsuAC {
|
||||
uint8_t* getRaw();
|
||||
bool setRaw(const uint8_t newState[], const uint16_t length);
|
||||
uint8_t getStateLength();
|
||||
static bool validChecksum(uint8_t *state, uint16_t length);
|
||||
static bool validChecksum(uint8_t* state, uint16_t length);
|
||||
bool getPower();
|
||||
#ifdef ARDUINO
|
||||
String toString();
|
||||
#else
|
||||
std::string toString();
|
||||
#endif
|
||||
#ifdef ARDUINO
|
||||
String toString();
|
||||
#else
|
||||
std::string toString();
|
||||
#endif
|
||||
|
||||
private:
|
||||
uint8_t remote_state[FUJITSU_AC_STATE_LENGTH];
|
||||
uint8_t remote_state[kFujitsuAcStateLength];
|
||||
IRsend _irsend;
|
||||
uint8_t _temp;
|
||||
uint8_t _fanSpeed;
|
||||
|
||||
@@ -18,17 +18,17 @@
|
||||
// https://github.com/markszabo/IRremoteESP8266/issues/447
|
||||
|
||||
// Constants
|
||||
#define GICABLE_HDR_MARK 9000U
|
||||
#define GICABLE_HDR_SPACE 4400U
|
||||
#define GICABLE_BIT_MARK 550U
|
||||
#define GICABLE_ONE_SPACE 4400U
|
||||
#define GICABLE_ZERO_SPACE 2200U
|
||||
#define GICABLE_RPT_SPACE 2200U
|
||||
#define GICABLE_MIN_COMMAND_LENGTH 99600U
|
||||
#define GICABLE_MIN_GAP (GICABLE_MIN_COMMAND_LENGTH - \
|
||||
(GICABLE_HDR_MARK + GICABLE_HDR_SPACE + \
|
||||
GICABLE_BITS * (GICABLE_BIT_MARK + GICABLE_ONE_SPACE) + GICABLE_BIT_MARK))
|
||||
|
||||
const uint16_t kGicableHdrMark = 9000;
|
||||
const uint16_t kGicableHdrSpace = 4400;
|
||||
const uint16_t kGicableBitMark = 550;
|
||||
const uint16_t kGicableOneSpace = 4400;
|
||||
const uint16_t kGicableZeroSpace = 2200;
|
||||
const uint16_t kGicableRptSpace = 2200;
|
||||
const uint32_t kGicableMinCommandLength = 99600;
|
||||
const uint32_t kGicableMinGap =
|
||||
kGicableMinCommandLength -
|
||||
(kGicableHdrMark + kGicableHdrSpace +
|
||||
kGicableBits * (kGicableBitMark + kGicableOneSpace) + kGicableBitMark);
|
||||
|
||||
#if SEND_GICABLE
|
||||
// Send a raw G.I. Cable formatted message.
|
||||
@@ -36,25 +36,24 @@
|
||||
// Args:
|
||||
// data: The message to be sent.
|
||||
// nbits: The number of bits of the message to be sent.
|
||||
// Typically GICABLE_BITS.
|
||||
// Typically kGicableBits.
|
||||
// repeat: The number of times the command is to be repeated.
|
||||
//
|
||||
// Status: Alpha / Untested.
|
||||
//
|
||||
// Ref:
|
||||
void IRsend::sendGICable(uint64_t data, uint16_t nbits, uint16_t repeat) {
|
||||
sendGeneric(GICABLE_HDR_MARK, GICABLE_HDR_SPACE,
|
||||
GICABLE_BIT_MARK, GICABLE_ONE_SPACE,
|
||||
GICABLE_BIT_MARK, GICABLE_ZERO_SPACE,
|
||||
GICABLE_BIT_MARK, GICABLE_MIN_GAP, GICABLE_MIN_COMMAND_LENGTH,
|
||||
data, nbits, 39, true, 0, // Repeats are handled later.
|
||||
sendGeneric(kGicableHdrMark, kGicableHdrSpace, kGicableBitMark,
|
||||
kGicableOneSpace, kGicableBitMark, kGicableZeroSpace,
|
||||
kGicableBitMark, kGicableMinGap, kGicableMinCommandLength, data,
|
||||
nbits, 39, true, 0, // Repeats are handled later.
|
||||
50);
|
||||
// Message repeat sequence.
|
||||
if (repeat)
|
||||
sendGeneric(GICABLE_HDR_MARK, GICABLE_RPT_SPACE,
|
||||
0, 0, 0, 0, // No actual data sent.
|
||||
GICABLE_BIT_MARK, GICABLE_MIN_GAP, GICABLE_MIN_COMMAND_LENGTH,
|
||||
0, 0, // No data to be sent.
|
||||
sendGeneric(kGicableHdrMark, kGicableRptSpace, 0, 0, 0,
|
||||
0, // No actual data sent.
|
||||
kGicableBitMark, kGicableMinGap, kGicableMinCommandLength, 0,
|
||||
0, // No data to be sent.
|
||||
39, true, repeat - 1, 50);
|
||||
}
|
||||
#endif // SEND_GICABLE
|
||||
@@ -64,7 +63,7 @@ void IRsend::sendGICable(uint64_t data, uint16_t nbits, uint16_t repeat) {
|
||||
//
|
||||
// Args:
|
||||
// results: Ptr to the data to decode and where to store the decode result.
|
||||
// nbits: The number of data bits to expect. Typically GICABLE_BITS.
|
||||
// nbits: The number of data bits to expect. Typically kGicableBits.
|
||||
// strict: Flag indicating if we should perform strict matching.
|
||||
// Returns:
|
||||
// boolean: True if it can decode it, false if it can't.
|
||||
@@ -72,40 +71,38 @@ void IRsend::sendGICable(uint64_t data, uint16_t nbits, uint16_t repeat) {
|
||||
// Status: Alpha / Not tested against a real device.
|
||||
bool IRrecv::decodeGICable(decode_results *results, uint16_t nbits,
|
||||
bool strict) {
|
||||
if (results->rawlen < 2 * (nbits + HEADER + FOOTER) - 1)
|
||||
if (results->rawlen < 2 * (nbits + kHeader + kFooter) - 1)
|
||||
return false; // Can't possibly be a valid GICABLE message.
|
||||
if (strict && nbits != GICABLE_BITS)
|
||||
if (strict && nbits != kGicableBits)
|
||||
return false; // Not strictly an GICABLE message.
|
||||
|
||||
uint64_t data = 0;
|
||||
uint16_t offset = OFFSET_START;
|
||||
uint16_t offset = kStartOffset;
|
||||
|
||||
// Header
|
||||
if (!matchMark(results->rawbuf[offset++], GICABLE_HDR_MARK)) return false;
|
||||
if (!matchSpace(results->rawbuf[offset++], GICABLE_HDR_SPACE)) return false;
|
||||
if (!matchMark(results->rawbuf[offset++], kGicableHdrMark)) return false;
|
||||
if (!matchSpace(results->rawbuf[offset++], kGicableHdrSpace)) return false;
|
||||
|
||||
// Data
|
||||
match_result_t data_result = matchData(&(results->rawbuf[offset]), nbits,
|
||||
GICABLE_BIT_MARK,
|
||||
GICABLE_ONE_SPACE,
|
||||
GICABLE_BIT_MARK,
|
||||
GICABLE_ZERO_SPACE);
|
||||
match_result_t data_result =
|
||||
matchData(&(results->rawbuf[offset]), nbits, kGicableBitMark,
|
||||
kGicableOneSpace, kGicableBitMark, kGicableZeroSpace);
|
||||
if (data_result.success == false) return false;
|
||||
data = data_result.data;
|
||||
offset += data_result.used;
|
||||
|
||||
// Footer
|
||||
if (!matchMark(results->rawbuf[offset++], GICABLE_BIT_MARK)) return false;
|
||||
if (!matchMark(results->rawbuf[offset++], kGicableBitMark)) return false;
|
||||
if (offset < results->rawlen &&
|
||||
!matchAtLeast(results->rawbuf[offset++], GICABLE_MIN_GAP))
|
||||
!matchAtLeast(results->rawbuf[offset++], kGicableMinGap))
|
||||
return false;
|
||||
|
||||
// Compliance
|
||||
if (strict) {
|
||||
// We expect a repeat frame.
|
||||
if (!matchMark(results->rawbuf[offset++], GICABLE_HDR_MARK)) return false;
|
||||
if (!matchSpace(results->rawbuf[offset++], GICABLE_RPT_SPACE)) return false;
|
||||
if (!matchMark(results->rawbuf[offset++], GICABLE_BIT_MARK)) return false;
|
||||
if (!matchMark(results->rawbuf[offset++], kGicableHdrMark)) return false;
|
||||
if (!matchSpace(results->rawbuf[offset++], kGicableRptSpace)) return false;
|
||||
if (!matchMark(results->rawbuf[offset++], kGicableBitMark)) return false;
|
||||
}
|
||||
|
||||
// Success
|
||||
|
||||
@@ -14,12 +14,12 @@
|
||||
// (http://www.hishamkhalifa.com)
|
||||
|
||||
// Constants
|
||||
#define GLOBALCACHE_MAX_REPEAT 50U
|
||||
#define GLOBALCACHE_MIN_USEC 80U
|
||||
#define GLOBALCACHE_FREQ_INDEX 0U
|
||||
#define GLOBALCACHE_RPT_INDEX GLOBALCACHE_FREQ_INDEX + 1U
|
||||
#define GLOBALCACHE_RPT_START_INDEX GLOBALCACHE_RPT_INDEX + 1U
|
||||
#define GLOBALCACHE_START_INDEX GLOBALCACHE_RPT_START_INDEX + 1U
|
||||
const uint16_t kGlobalCacheMaxRepeat = 50;
|
||||
const uint32_t kGlobalCacheMinUsec = 80;
|
||||
const uint8_t kGlobalCacheFreqIndex = 0;
|
||||
const uint8_t kGlobalCacheRptIndex = kGlobalCacheFreqIndex + 1;
|
||||
const uint8_t kGlobalCacheRptStartIndex = kGlobalCacheRptIndex + 1;
|
||||
const uint8_t kGlobalCacheStartIndex = kGlobalCacheRptStartIndex + 1;
|
||||
|
||||
#if SEND_GLOBALCACHE
|
||||
// Send a shortened GlobalCache (GC) IRdb/control tower formatted message.
|
||||
@@ -40,24 +40,23 @@
|
||||
// Ref:
|
||||
// https://irdb.globalcache.com/Home/Database
|
||||
void IRsend::sendGC(uint16_t buf[], uint16_t len) {
|
||||
uint16_t hz = buf[GLOBALCACHE_FREQ_INDEX]; // GC frequency is in Hz.
|
||||
uint16_t hz = buf[kGlobalCacheFreqIndex]; // GC frequency is in Hz.
|
||||
enableIROut(hz);
|
||||
uint32_t periodic_time = calcUSecPeriod(hz, false);
|
||||
uint8_t emits = std::min(buf[GLOBALCACHE_RPT_INDEX],
|
||||
(uint16_t) GLOBALCACHE_MAX_REPEAT);
|
||||
uint8_t emits =
|
||||
std::min(buf[kGlobalCacheRptIndex], (uint16_t)kGlobalCacheMaxRepeat);
|
||||
// Repeat
|
||||
for (uint8_t repeat = 0; repeat < emits; repeat++) {
|
||||
// First time through, start at the beginning (GLOBALCACHE_START_INDEX),
|
||||
// First time through, start at the beginning (kGlobalCacheStartIndex),
|
||||
// otherwise for repeats, we start a specified offset from that.
|
||||
uint16_t offset = GLOBALCACHE_START_INDEX;
|
||||
if (repeat)
|
||||
offset += buf[GLOBALCACHE_RPT_START_INDEX] - 1;
|
||||
uint16_t offset = kGlobalCacheStartIndex;
|
||||
if (repeat) offset += buf[kGlobalCacheRptStartIndex] - 1;
|
||||
// Data
|
||||
for (; offset < len; offset++) {
|
||||
// Convert periodic units to microseconds.
|
||||
// Minimum is GLOBALCACHE_MIN_USEC for actual GC units.
|
||||
uint32_t microseconds = std::max(buf[offset] * periodic_time,
|
||||
GLOBALCACHE_MIN_USEC);
|
||||
// Minimum is kGlobalCacheMinUsec for actual GC units.
|
||||
uint32_t microseconds =
|
||||
std::max(buf[offset] * periodic_time, kGlobalCacheMinUsec);
|
||||
// These codes start at an odd index (not even as with sendRaw).
|
||||
if (offset & 1) // Odd bit.
|
||||
mark(microseconds);
|
||||
|
||||
+119
-139
@@ -12,8 +12,8 @@
|
||||
#ifndef ARDUINO
|
||||
#include <string>
|
||||
#endif
|
||||
#include "IRremoteESP8266.h"
|
||||
#include "IRrecv.h"
|
||||
#include "IRremoteESP8266.h"
|
||||
#include "IRsend.h"
|
||||
#include "IRutils.h"
|
||||
#include "ir_Kelvinator.h"
|
||||
@@ -26,21 +26,21 @@
|
||||
|
||||
// Constants
|
||||
// Ref: https://github.com/ToniA/arduino-heatpumpir/blob/master/GreeHeatpumpIR.h
|
||||
#define GREE_HDR_MARK 9000U
|
||||
#define GREE_HDR_SPACE 4000U
|
||||
#define GREE_BIT_MARK 620U
|
||||
#define GREE_ONE_SPACE 1600U
|
||||
#define GREE_ZERO_SPACE 540U
|
||||
#define GREE_MSG_SPACE 19000U
|
||||
#define GREE_BLOCK_FOOTER 0b010U
|
||||
#define GREE_BLOCK_FOOTER_BITS 3U
|
||||
const uint16_t kGreeHdrMark = 9000;
|
||||
const uint16_t kGreeHdrSpace = 4000;
|
||||
const uint16_t kGreeBitMark = 620;
|
||||
const uint16_t kGreeOneSpace = 1600;
|
||||
const uint16_t kGreeZeroSpace = 540;
|
||||
const uint16_t kGreeMsgSpace = 19000;
|
||||
const uint8_t kGreeBlockFooter = 0b010;
|
||||
const uint8_t kGreeBlockFooterBits = 3;
|
||||
|
||||
#if SEND_GREE
|
||||
// Send a Gree Heat Pump message.
|
||||
//
|
||||
// Args:
|
||||
// data: An array of bytes containing the IR command.
|
||||
// nbytes: Nr. of bytes of data in the array. (>=GREE_STATE_LENGTH)
|
||||
// nbytes: Nr. of bytes of data in the array. (>=kGreeStateLength)
|
||||
// repeat: Nr. of times the message is to be repeated. (Default = 0).
|
||||
//
|
||||
// Status: ALPHA / Untested.
|
||||
@@ -48,29 +48,24 @@
|
||||
// Ref:
|
||||
// https://github.com/ToniA/arduino-heatpumpir/blob/master/GreeHeatpumpIR.cpp
|
||||
void IRsend::sendGree(unsigned char data[], uint16_t nbytes, uint16_t repeat) {
|
||||
if (nbytes < GREE_STATE_LENGTH)
|
||||
if (nbytes < kGreeStateLength)
|
||||
return; // Not enough bytes to send a proper message.
|
||||
|
||||
for (uint16_t r = 0; r <= repeat; r++) {
|
||||
// Block #1
|
||||
sendGeneric(GREE_HDR_MARK, GREE_HDR_SPACE,
|
||||
GREE_BIT_MARK, GREE_ONE_SPACE,
|
||||
GREE_BIT_MARK, GREE_ZERO_SPACE,
|
||||
0, 0, // No Footer.
|
||||
sendGeneric(kGreeHdrMark, kGreeHdrSpace, kGreeBitMark, kGreeOneSpace,
|
||||
kGreeBitMark, kGreeZeroSpace, 0, 0, // No Footer.
|
||||
data, 4, 38, false, 0, 50);
|
||||
// Footer #1
|
||||
sendGeneric(0, 0, // No Header
|
||||
GREE_BIT_MARK, GREE_ONE_SPACE,
|
||||
GREE_BIT_MARK, GREE_ZERO_SPACE,
|
||||
GREE_BIT_MARK, GREE_MSG_SPACE,
|
||||
0b010, 3, 38, true, 0, false);
|
||||
kGreeBitMark, kGreeOneSpace, kGreeBitMark, kGreeZeroSpace,
|
||||
kGreeBitMark, kGreeMsgSpace, 0b010, 3, 38, true, 0, false);
|
||||
|
||||
// Block #2
|
||||
sendGeneric(0, 0, // No Header for Block #2
|
||||
GREE_BIT_MARK, GREE_ONE_SPACE,
|
||||
GREE_BIT_MARK, GREE_ZERO_SPACE,
|
||||
GREE_BIT_MARK, GREE_MSG_SPACE,
|
||||
data + 4, nbytes - 4, 38, false, 0, 50);
|
||||
kGreeBitMark, kGreeOneSpace, kGreeBitMark, kGreeZeroSpace,
|
||||
kGreeBitMark, kGreeMsgSpace, data + 4, nbytes - 4, 38, false, 0,
|
||||
50);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,7 +73,7 @@ void IRsend::sendGree(unsigned char data[], uint16_t nbytes, uint16_t repeat) {
|
||||
//
|
||||
// Args:
|
||||
// data: The raw message to be sent.
|
||||
// nbits: Nr. of bits of data in the message. (Default is GREE_BITS)
|
||||
// nbits: Nr. of bits of data in the message. (Default is kGreeBits)
|
||||
// repeat: Nr. of times the message is to be repeated. (Default = 0).
|
||||
//
|
||||
// Status: ALPHA / Untested.
|
||||
@@ -86,43 +81,40 @@ void IRsend::sendGree(unsigned char data[], uint16_t nbytes, uint16_t repeat) {
|
||||
// Ref:
|
||||
// https://github.com/ToniA/arduino-heatpumpir/blob/master/GreeHeatpumpIR.cpp
|
||||
void IRsend::sendGree(uint64_t data, uint16_t nbits, uint16_t repeat) {
|
||||
if (nbits != GREE_BITS)
|
||||
if (nbits != kGreeBits)
|
||||
return; // Wrong nr. of bits to send a proper message.
|
||||
// Set IR carrier frequency
|
||||
enableIROut(38);
|
||||
|
||||
for (uint16_t r = 0; r <= repeat; r++) {
|
||||
// Header
|
||||
mark(GREE_HDR_MARK);
|
||||
space(GREE_HDR_SPACE);
|
||||
mark(kGreeHdrMark);
|
||||
space(kGreeHdrSpace);
|
||||
|
||||
// Data
|
||||
for (int16_t i = 8; i <= nbits; i += 8) {
|
||||
sendData(GREE_BIT_MARK, GREE_ONE_SPACE, GREE_BIT_MARK, GREE_ZERO_SPACE,
|
||||
sendData(kGreeBitMark, kGreeOneSpace, kGreeBitMark, kGreeZeroSpace,
|
||||
(data >> (nbits - i)) & 0xFF, 8, false);
|
||||
if (i == nbits / 2) {
|
||||
// Send the mid-message Footer.
|
||||
sendData(GREE_BIT_MARK, GREE_ONE_SPACE, GREE_BIT_MARK, GREE_ZERO_SPACE,
|
||||
sendData(kGreeBitMark, kGreeOneSpace, kGreeBitMark, kGreeZeroSpace,
|
||||
0b010, 3);
|
||||
mark(GREE_BIT_MARK);
|
||||
space(GREE_MSG_SPACE);
|
||||
mark(kGreeBitMark);
|
||||
space(kGreeMsgSpace);
|
||||
}
|
||||
}
|
||||
// Footer
|
||||
mark(GREE_BIT_MARK);
|
||||
space(GREE_MSG_SPACE);
|
||||
mark(kGreeBitMark);
|
||||
space(kGreeMsgSpace);
|
||||
}
|
||||
}
|
||||
#endif // SEND_GREE
|
||||
|
||||
IRGreeAC::IRGreeAC(uint16_t pin) : _irsend(pin) {
|
||||
stateReset();
|
||||
}
|
||||
IRGreeAC::IRGreeAC(uint16_t pin) : _irsend(pin) { stateReset(); }
|
||||
|
||||
void IRGreeAC::stateReset() {
|
||||
// This resets to a known-good state to Power Off, Fan Auto, Mode Auto, 25C.
|
||||
for (uint8_t i = 0; i < GREE_STATE_LENGTH; i++)
|
||||
remote_state[i] = 0x0;
|
||||
for (uint8_t i = 0; i < kGreeStateLength; i++) remote_state[i] = 0x0;
|
||||
remote_state[1] = 0x09;
|
||||
remote_state[2] = 0x20;
|
||||
remote_state[3] = 0x50;
|
||||
@@ -134,24 +126,22 @@ void IRGreeAC::fixup() {
|
||||
checksum(); // Calculate the checksums
|
||||
}
|
||||
|
||||
void IRGreeAC::begin() {
|
||||
_irsend.begin();
|
||||
}
|
||||
void IRGreeAC::begin() { _irsend.begin(); }
|
||||
|
||||
#if SEND_GREE
|
||||
void IRGreeAC::send() {
|
||||
fixup(); // Ensure correct settings before sending.
|
||||
fixup(); // Ensure correct settings before sending.
|
||||
_irsend.sendGree(remote_state);
|
||||
}
|
||||
#endif // SEND_GREE
|
||||
|
||||
uint8_t* IRGreeAC::getRaw() {
|
||||
fixup(); // Ensure correct settings before sending.
|
||||
fixup(); // Ensure correct settings before sending.
|
||||
return remote_state;
|
||||
}
|
||||
|
||||
void IRGreeAC::setRaw(uint8_t new_code[]) {
|
||||
for (uint8_t i = 0; i < GREE_STATE_LENGTH; i++) {
|
||||
for (uint8_t i = 0; i < kGreeStateLength; i++) {
|
||||
remote_state[i] = new_code[i];
|
||||
}
|
||||
}
|
||||
@@ -170,21 +160,21 @@ void IRGreeAC::checksum(const uint16_t length) {
|
||||
// A boolean.
|
||||
bool IRGreeAC::validChecksum(const uint8_t state[], const uint16_t length) {
|
||||
// Top 4 bits of the last byte in the state is the state's checksum.
|
||||
if (state[length - 1] >> 4 == IRKelvinatorAC::calcBlockChecksum(state,
|
||||
length))
|
||||
if (state[length - 1] >> 4 ==
|
||||
IRKelvinatorAC::calcBlockChecksum(state, length))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void IRGreeAC::on() {
|
||||
remote_state[0] |= GREE_POWER1_MASK;
|
||||
remote_state[2] |= GREE_POWER2_MASK;
|
||||
remote_state[0] |= kGreePower1Mask;
|
||||
remote_state[2] |= kGreePower2Mask;
|
||||
}
|
||||
|
||||
void IRGreeAC::off() {
|
||||
remote_state[0] &= ~GREE_POWER1_MASK;
|
||||
remote_state[2] &= ~GREE_POWER2_MASK;
|
||||
remote_state[0] &= ~kGreePower1Mask;
|
||||
remote_state[2] &= ~kGreePower2Mask;
|
||||
}
|
||||
|
||||
void IRGreeAC::setPower(const bool state) {
|
||||
@@ -195,136 +185,124 @@ void IRGreeAC::setPower(const bool state) {
|
||||
}
|
||||
|
||||
bool IRGreeAC::getPower() {
|
||||
return (remote_state[0] & GREE_POWER1_MASK) &&
|
||||
(remote_state[2] & GREE_POWER2_MASK);
|
||||
return (remote_state[0] & kGreePower1Mask) &&
|
||||
(remote_state[2] & kGreePower2Mask);
|
||||
}
|
||||
|
||||
// Set the temp. in deg C
|
||||
void IRGreeAC::setTemp(const uint8_t temp) {
|
||||
uint8_t new_temp = std::max((uint8_t) GREE_MIN_TEMP, temp);
|
||||
new_temp = std::min((uint8_t) GREE_MAX_TEMP, new_temp);
|
||||
if (getMode() == GREE_AUTO) new_temp = 25;
|
||||
remote_state[1] = (remote_state[1] & 0xF0U) | (new_temp - GREE_MIN_TEMP);
|
||||
uint8_t new_temp = std::max((uint8_t)kGreeMinTemp, temp);
|
||||
new_temp = std::min((uint8_t)kGreeMaxTemp, new_temp);
|
||||
if (getMode() == kGreeAuto) new_temp = 25;
|
||||
remote_state[1] = (remote_state[1] & 0xF0U) | (new_temp - kGreeMinTemp);
|
||||
}
|
||||
|
||||
// Return the set temp. in deg C
|
||||
uint8_t IRGreeAC::getTemp() {
|
||||
return ((remote_state[1] & 0xFU) + GREE_MIN_TEMP);
|
||||
return ((remote_state[1] & 0xFU) + kGreeMinTemp);
|
||||
}
|
||||
|
||||
// Set the speed of the fan, 0-3, 0 is auto, 1-3 is the speed
|
||||
void IRGreeAC::setFan(const uint8_t speed) {
|
||||
uint8_t fan = std::min((uint8_t) GREE_FAN_MAX, speed); // Bounds check
|
||||
uint8_t fan = std::min((uint8_t)kGreeFanMax, speed); // Bounds check
|
||||
|
||||
if (getMode() == GREE_DRY) fan = 1; // DRY mode is always locked to fan 1.
|
||||
if (getMode() == kGreeDry) fan = 1; // DRY mode is always locked to fan 1.
|
||||
// Set the basic fan values.
|
||||
remote_state[0] &= ~GREE_FAN_MASK;
|
||||
remote_state[0] &= ~kGreeFanMask;
|
||||
remote_state[0] |= (fan << 4);
|
||||
}
|
||||
|
||||
uint8_t IRGreeAC::getFan() {
|
||||
return ((remote_state[0] & GREE_FAN_MASK) >> 4);
|
||||
}
|
||||
uint8_t IRGreeAC::getFan() { return ((remote_state[0] & kGreeFanMask) >> 4); }
|
||||
|
||||
void IRGreeAC::setMode(const uint8_t new_mode) {
|
||||
uint8_t mode = new_mode;
|
||||
switch (mode) {
|
||||
case GREE_AUTO:
|
||||
case kGreeAuto:
|
||||
// AUTO is locked to 25C
|
||||
setTemp(25);
|
||||
break;
|
||||
case GREE_DRY:
|
||||
case kGreeDry:
|
||||
// DRY always sets the fan to 1.
|
||||
setFan(1);
|
||||
break;
|
||||
case GREE_COOL:
|
||||
case GREE_FAN:
|
||||
case GREE_HEAT:
|
||||
case kGreeCool:
|
||||
case kGreeFan:
|
||||
case kGreeHeat:
|
||||
break;
|
||||
default:
|
||||
// If we get an unexpected mode, default to AUTO.
|
||||
mode = GREE_AUTO;
|
||||
mode = kGreeAuto;
|
||||
}
|
||||
remote_state[0] &= ~GREE_MODE_MASK;
|
||||
remote_state[0] &= ~kGreeModeMask;
|
||||
remote_state[0] |= mode;
|
||||
}
|
||||
|
||||
uint8_t IRGreeAC::getMode() {
|
||||
return (remote_state[0] & GREE_MODE_MASK);
|
||||
}
|
||||
uint8_t IRGreeAC::getMode() { return (remote_state[0] & kGreeModeMask); }
|
||||
|
||||
void IRGreeAC::setLight(const bool state) {
|
||||
remote_state[2] &= ~GREE_LIGHT_MASK;
|
||||
remote_state[2] &= ~kGreeLightMask;
|
||||
remote_state[2] |= (state << 5);
|
||||
}
|
||||
|
||||
bool IRGreeAC::getLight() {
|
||||
return remote_state[2] & GREE_LIGHT_MASK;
|
||||
}
|
||||
bool IRGreeAC::getLight() { return remote_state[2] & kGreeLightMask; }
|
||||
|
||||
void IRGreeAC::setXFan(const bool state) {
|
||||
remote_state[2] &= ~GREE_XFAN_MASK;
|
||||
remote_state[2] &= ~kGreeXfanMask;
|
||||
remote_state[2] |= (state << 7);
|
||||
}
|
||||
|
||||
bool IRGreeAC::getXFan() {
|
||||
return remote_state[2] & GREE_XFAN_MASK;
|
||||
}
|
||||
bool IRGreeAC::getXFan() { return remote_state[2] & kGreeXfanMask; }
|
||||
|
||||
void IRGreeAC::setSleep(const bool state) {
|
||||
remote_state[0] &= ~GREE_SLEEP_MASK;
|
||||
remote_state[0] &= ~kGreeSleepMask;
|
||||
remote_state[0] |= (state << 7);
|
||||
}
|
||||
|
||||
bool IRGreeAC::getSleep() {
|
||||
return remote_state[0] & GREE_SLEEP_MASK;
|
||||
}
|
||||
bool IRGreeAC::getSleep() { return remote_state[0] & kGreeSleepMask; }
|
||||
|
||||
void IRGreeAC::setTurbo(const bool state) {
|
||||
remote_state[2] &= ~GREE_TURBO_MASK;
|
||||
remote_state[2] &= ~kGreeTurboMask;
|
||||
remote_state[2] |= (state << 4);
|
||||
}
|
||||
|
||||
bool IRGreeAC::getTurbo() {
|
||||
return remote_state[2] & GREE_TURBO_MASK;
|
||||
}
|
||||
bool IRGreeAC::getTurbo() { return remote_state[2] & kGreeTurboMask; }
|
||||
|
||||
void IRGreeAC::setSwingVertical(const bool automatic, const uint8_t position) {
|
||||
remote_state[0] &= ~GREE_SWING_AUTO_MASK;
|
||||
remote_state[0] &= ~kGreeSwingAutoMask;
|
||||
remote_state[0] |= (automatic << 6);
|
||||
uint8_t new_position = position;
|
||||
if (!automatic) {
|
||||
switch (position) {
|
||||
case GREE_SWING_UP:
|
||||
case GREE_SWING_MIDDLE_UP:
|
||||
case GREE_SWING_MIDDLE:
|
||||
case GREE_SWING_MIDDLE_DOWN:
|
||||
case GREE_SWING_DOWN:
|
||||
case kGreeSwingUp:
|
||||
case kGreeSwingMiddleUp:
|
||||
case kGreeSwingMiddle:
|
||||
case kGreeSwingMiddleDown:
|
||||
case kGreeSwingDown:
|
||||
break;
|
||||
default:
|
||||
new_position = GREE_SWING_LAST_POS;
|
||||
new_position = kGreeSwingLastPos;
|
||||
}
|
||||
} else {
|
||||
switch (position) {
|
||||
case GREE_SWING_AUTO:
|
||||
case GREE_SWING_DOWN_AUTO:
|
||||
case GREE_SWING_MIDDLE_AUTO:
|
||||
case GREE_SWING_UP_AUTO:
|
||||
case kGreeSwingAuto:
|
||||
case kGreeSwingDownAuto:
|
||||
case kGreeSwingMiddleAuto:
|
||||
case kGreeSwingUpAuto:
|
||||
break;
|
||||
default:
|
||||
new_position = GREE_SWING_AUTO;
|
||||
new_position = kGreeSwingAuto;
|
||||
}
|
||||
}
|
||||
remote_state[4] &= ~GREE_SWING_POS_MASK;
|
||||
remote_state[4] &= ~kGreeSwingPosMask;
|
||||
remote_state[4] |= new_position;
|
||||
}
|
||||
|
||||
bool IRGreeAC::getSwingVerticalAuto() {
|
||||
return remote_state[0] & GREE_SWING_AUTO_MASK;
|
||||
return remote_state[0] & kGreeSwingAutoMask;
|
||||
}
|
||||
|
||||
uint8_t IRGreeAC::getSwingVerticalPosition() {
|
||||
return remote_state[4] & GREE_SWING_POS_MASK;
|
||||
return remote_state[4] & kGreeSwingPosMask;
|
||||
}
|
||||
|
||||
// Convert the internal state into a human readable string.
|
||||
@@ -342,19 +320,19 @@ std::string IRGreeAC::toString() {
|
||||
result += "Off";
|
||||
result += ", Mode: " + uint64ToString(getMode());
|
||||
switch (getMode()) {
|
||||
case GREE_AUTO:
|
||||
case kGreeAuto:
|
||||
result += " (AUTO)";
|
||||
break;
|
||||
case GREE_COOL:
|
||||
case kGreeCool:
|
||||
result += " (COOL)";
|
||||
break;
|
||||
case GREE_HEAT:
|
||||
case kGreeHeat:
|
||||
result += " (HEAT)";
|
||||
break;
|
||||
case GREE_DRY:
|
||||
case kGreeDry:
|
||||
result += " (DRY)";
|
||||
break;
|
||||
case GREE_FAN:
|
||||
case kGreeFan:
|
||||
result += " (FAN)";
|
||||
break;
|
||||
default:
|
||||
@@ -366,7 +344,7 @@ std::string IRGreeAC::toString() {
|
||||
case 0:
|
||||
result += " (AUTO)";
|
||||
break;
|
||||
case GREE_FAN_MAX:
|
||||
case kGreeFanMax:
|
||||
result += " (MAX)";
|
||||
break;
|
||||
}
|
||||
@@ -395,13 +373,13 @@ std::string IRGreeAC::toString() {
|
||||
result += "Auto";
|
||||
else
|
||||
result += "Manual";
|
||||
result += ", Swing Vertical Pos: " +
|
||||
uint64ToString(getSwingVerticalPosition());
|
||||
result +=
|
||||
", Swing Vertical Pos: " + uint64ToString(getSwingVerticalPosition());
|
||||
switch (getSwingVerticalPosition()) {
|
||||
case GREE_SWING_LAST_POS:
|
||||
case kGreeSwingLastPos:
|
||||
result += " (Last Pos)";
|
||||
break;
|
||||
case GREE_SWING_AUTO:
|
||||
case kGreeSwingAuto:
|
||||
result += " (Auto)";
|
||||
break;
|
||||
}
|
||||
@@ -413,21 +391,21 @@ std::string IRGreeAC::toString() {
|
||||
//
|
||||
// Args:
|
||||
// results: Ptr to the data to decode and where to store the decode result.
|
||||
// nbits: The number of data bits to expect. Typically GREE_BITS.
|
||||
// nbits: The number of data bits to expect. Typically kGreeBits.
|
||||
// strict: Flag indicating if we should perform strict matching.
|
||||
// Returns:
|
||||
// boolean: True if it can decode it, false if it can't.
|
||||
//
|
||||
// Status: ALPHA / Untested.
|
||||
bool IRrecv::decodeGree(decode_results *results, uint16_t nbits, bool strict) {
|
||||
if (results->rawlen < 2 * (nbits + GREE_BLOCK_FOOTER_BITS) +
|
||||
(HEADER + FOOTER + 1))
|
||||
bool IRrecv::decodeGree(decode_results* results, uint16_t nbits, bool strict) {
|
||||
if (results->rawlen <
|
||||
2 * (nbits + kGreeBlockFooterBits) + (kHeader + kFooter + 1))
|
||||
return false; // Can't possibly be a valid Gree message.
|
||||
if (strict && nbits != GREE_BITS)
|
||||
if (strict && nbits != kGreeBits)
|
||||
return false; // Not strictly a Gree message.
|
||||
|
||||
uint32_t data;
|
||||
uint16_t offset = OFFSET_START;
|
||||
uint16_t offset = kStartOffset;
|
||||
|
||||
// There are two blocks back-to-back in a full Gree IR message
|
||||
// sequence.
|
||||
@@ -435,54 +413,56 @@ bool IRrecv::decodeGree(decode_results *results, uint16_t nbits, bool strict) {
|
||||
match_result_t data_result;
|
||||
|
||||
// Header
|
||||
if (!matchMark(results->rawbuf[offset++], GREE_HDR_MARK)) return false;
|
||||
if (!matchSpace(results->rawbuf[offset++], GREE_HDR_SPACE)) return false;
|
||||
if (!matchMark(results->rawbuf[offset++], kGreeHdrMark)) return false;
|
||||
if (!matchSpace(results->rawbuf[offset++], kGreeHdrSpace)) return false;
|
||||
// Data Block #1 (32 bits)
|
||||
data_result = matchData(&(results->rawbuf[offset]), 32, GREE_BIT_MARK,
|
||||
GREE_ONE_SPACE, GREE_BIT_MARK, GREE_ZERO_SPACE);
|
||||
data_result =
|
||||
matchData(&(results->rawbuf[offset]), 32, kGreeBitMark, kGreeOneSpace,
|
||||
kGreeBitMark, kGreeZeroSpace, kTolerance, kMarkExcess, false);
|
||||
if (data_result.success == false) return false;
|
||||
data = data_result.data;
|
||||
offset += data_result.used;
|
||||
|
||||
// Record Data Block #1 in the state.
|
||||
for (int i = state_pos + 3; i >= state_pos; i--, data >>= 8)
|
||||
results->state[i] = reverseBits(data & 0xFF, 8);
|
||||
for (uint16_t i = 0; i < 4; i++, data >>= 8)
|
||||
results->state[state_pos + i] = data & 0xFF;
|
||||
state_pos += 4;
|
||||
|
||||
// Block #1 footer (3 bits, B010)
|
||||
data_result = matchData(&(results->rawbuf[offset]), GREE_BLOCK_FOOTER_BITS,
|
||||
GREE_BIT_MARK, GREE_ONE_SPACE, GREE_BIT_MARK,
|
||||
GREE_ZERO_SPACE);
|
||||
data_result = matchData(&(results->rawbuf[offset]), kGreeBlockFooterBits,
|
||||
kGreeBitMark, kGreeOneSpace, kGreeBitMark,
|
||||
kGreeZeroSpace, kTolerance, kMarkExcess, false);
|
||||
if (data_result.success == false) return false;
|
||||
if (data_result.data != GREE_BLOCK_FOOTER) return false;
|
||||
if (data_result.data != kGreeBlockFooter) return false;
|
||||
offset += data_result.used;
|
||||
|
||||
// Inter-block gap.
|
||||
if (!matchMark(results->rawbuf[offset++], GREE_BIT_MARK)) return false;
|
||||
if (!matchSpace(results->rawbuf[offset++], GREE_MSG_SPACE)) return false;
|
||||
if (!matchMark(results->rawbuf[offset++], kGreeBitMark)) return false;
|
||||
if (!matchSpace(results->rawbuf[offset++], kGreeMsgSpace)) return false;
|
||||
|
||||
// Data Block #2 (32 bits)
|
||||
data_result = matchData(&(results->rawbuf[offset]), 32, GREE_BIT_MARK,
|
||||
GREE_ONE_SPACE, GREE_BIT_MARK, GREE_ZERO_SPACE);
|
||||
data_result =
|
||||
matchData(&(results->rawbuf[offset]), 32, kGreeBitMark, kGreeOneSpace,
|
||||
kGreeBitMark, kGreeZeroSpace, kTolerance, kMarkExcess, false);
|
||||
if (data_result.success == false) return false;
|
||||
data = data_result.data;
|
||||
offset += data_result.used;
|
||||
|
||||
// Record Data Block #2 in the state.
|
||||
for (int i = state_pos + 3; i >= state_pos; i--, data >>= 8)
|
||||
results->state[i] = reverseBits(data & 0xFF, 8);
|
||||
for (uint16_t i = 0; i < 4; i++, data >>= 8)
|
||||
results->state[state_pos + i] = data & 0xFF;
|
||||
state_pos += 4;
|
||||
|
||||
// Footer.
|
||||
if (!matchMark(results->rawbuf[offset++], GREE_BIT_MARK)) return false;
|
||||
if (!matchMark(results->rawbuf[offset++], kGreeBitMark)) return false;
|
||||
if (offset <= results->rawlen &&
|
||||
!matchAtLeast(results->rawbuf[offset], GREE_MSG_SPACE))
|
||||
!matchAtLeast(results->rawbuf[offset], kGreeMsgSpace))
|
||||
return false;
|
||||
|
||||
// Compliance
|
||||
if (strict) {
|
||||
// Correct size/length)
|
||||
if (state_pos != GREE_STATE_LENGTH) return false;
|
||||
if (state_pos != kGreeStateLength) return false;
|
||||
// Verify the message's checksum is correct.
|
||||
if (!IRGreeAC::validChecksum(results->state)) return false;
|
||||
}
|
||||
|
||||
@@ -22,40 +22,60 @@
|
||||
// GGGGGG RR RR EEEEEEE EEEEEEE
|
||||
|
||||
// Constants
|
||||
#define GREE_AUTO 0U
|
||||
#define GREE_COOL 1U
|
||||
#define GREE_DRY 2U
|
||||
#define GREE_FAN 3U
|
||||
#define GREE_HEAT 4U
|
||||
const uint8_t kGreeAuto = 0;
|
||||
const uint8_t kGreeCool = 1;
|
||||
const uint8_t kGreeDry = 2;
|
||||
const uint8_t kGreeFan = 3;
|
||||
const uint8_t kGreeHeat = 4;
|
||||
|
||||
// Byte 0
|
||||
#define GREE_MODE_MASK 0b00000111U
|
||||
#define GREE_POWER1_MASK 0b00001000U
|
||||
#define GREE_FAN_MASK 0b00110000U
|
||||
#define GREE_SWING_AUTO_MASK 0b01000000U
|
||||
#define GREE_SLEEP_MASK 0b10000000U
|
||||
const uint8_t kGreeModeMask = 0b00000111;
|
||||
const uint8_t kGreePower1Mask = 0b00001000;
|
||||
const uint8_t kGreeFanMask = 0b00110000;
|
||||
const uint8_t kGreeSwingAutoMask = 0b01000000;
|
||||
const uint8_t kGreeSleepMask = 0b10000000;
|
||||
// Byte 2
|
||||
#define GREE_TURBO_MASK 0b00010000U
|
||||
#define GREE_LIGHT_MASK 0b00100000U
|
||||
#define GREE_POWER2_MASK 0b01000000U
|
||||
#define GREE_XFAN_MASK 0b10000000U
|
||||
const uint8_t kGreeTurboMask = 0b00010000;
|
||||
const uint8_t kGreeLightMask = 0b00100000;
|
||||
const uint8_t kGreePower2Mask = 0b01000000;
|
||||
const uint8_t kGreeXfanMask = 0b10000000;
|
||||
// Byte 4
|
||||
#define GREE_SWING_POS_MASK 0b00001111U
|
||||
const uint8_t kGreeSwingPosMask = 0b00001111;
|
||||
|
||||
#define GREE_MIN_TEMP 16U // Celsius
|
||||
#define GREE_MAX_TEMP 30U // Celsius
|
||||
#define GREE_FAN_MAX 3U
|
||||
const uint8_t kGreeMinTemp = 16; // Celsius
|
||||
const uint8_t kGreeMaxTemp = 30; // Celsius
|
||||
const uint8_t kGreeFanMax = 3;
|
||||
|
||||
#define GREE_SWING_LAST_POS 0b00000000U
|
||||
#define GREE_SWING_AUTO 0b00000001U
|
||||
#define GREE_SWING_UP 0b00000010U
|
||||
#define GREE_SWING_MIDDLE_UP 0b00000011U
|
||||
#define GREE_SWING_MIDDLE 0b00000100U
|
||||
#define GREE_SWING_MIDDLE_DOWN 0b00000101U
|
||||
#define GREE_SWING_DOWN 0b00000110U
|
||||
#define GREE_SWING_DOWN_AUTO 0b00000111U
|
||||
#define GREE_SWING_MIDDLE_AUTO 0b00001001U
|
||||
#define GREE_SWING_UP_AUTO 0b00001011U
|
||||
const uint8_t kGreeSwingLastPos = 0b00000000;
|
||||
const uint8_t kGreeSwingAuto = 0b00000001;
|
||||
const uint8_t kGreeSwingUp = 0b00000010;
|
||||
const uint8_t kGreeSwingMiddleUp = 0b00000011;
|
||||
const uint8_t kGreeSwingMiddle = 0b00000100;
|
||||
const uint8_t kGreeSwingMiddleDown = 0b00000101;
|
||||
const uint8_t kGreeSwingDown = 0b00000110;
|
||||
const uint8_t kGreeSwingDownAuto = 0b00000111;
|
||||
const uint8_t kGreeSwingMiddleAuto = 0b00001001;
|
||||
const uint8_t kGreeSwingUpAuto = 0b00001011;
|
||||
|
||||
// Legacy defines.
|
||||
#define GREE_AUTO kGreeAuto
|
||||
#define GREE_COOL kGreeCool
|
||||
#define GREE_DRY kGreeDry
|
||||
#define GREE_FAN kGreeFan
|
||||
#define GREE_HEAT kGreeHeat
|
||||
#define GREE_MIN_TEMP kGreeMinTemp
|
||||
#define GREE_MAX_TEMP kGreeMaxTemp
|
||||
#define GREE_FAN_MAX kGreeFanMax
|
||||
#define GREE_SWING_LAST_POS kGreeSwingLastPos
|
||||
#define GREE_SWING_AUTO kGreeSwingAuto
|
||||
#define GREE_SWING_UP kGreeSwingUp
|
||||
#define GREE_SWING_MIDDLE_UP kGreeSwingMiddleUp
|
||||
#define GREE_SWING_MIDDLE kGreeSwingMiddle
|
||||
#define GREE_SWING_MIDDLE_DOWN kGreeSwingMiddleDown
|
||||
#define GREE_SWING_DOWN kGreeSwingDown
|
||||
#define GREE_SWING_DOWN_AUTO kGreeSwingDownAuto
|
||||
#define GREE_SWING_MIDDLE_AUTO kGreeSwingMiddleAuto
|
||||
#define GREE_SWING_UP_AUTO kGreeSwingUpAuto
|
||||
|
||||
// Classes
|
||||
class IRGreeAC {
|
||||
@@ -92,7 +112,7 @@ class IRGreeAC {
|
||||
uint8_t* getRaw();
|
||||
void setRaw(uint8_t new_code[]);
|
||||
static bool validChecksum(const uint8_t state[],
|
||||
const uint16_t length = GREE_STATE_LENGTH);
|
||||
const uint16_t length = kGreeStateLength);
|
||||
#ifdef ARDUINO
|
||||
String toString();
|
||||
#else
|
||||
@@ -101,8 +121,8 @@ class IRGreeAC {
|
||||
|
||||
private:
|
||||
// The state of the IR remote in IR code form.
|
||||
uint8_t remote_state[GREE_STATE_LENGTH];
|
||||
void checksum(const uint16_t length = GREE_STATE_LENGTH);
|
||||
uint8_t remote_state[kGreeStateLength];
|
||||
void checksum(const uint16_t length = kGreeStateLength);
|
||||
void fixup();
|
||||
IRsend _irsend;
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -28,104 +28,158 @@
|
||||
|
||||
// Haier HSU07-HEA03 remote
|
||||
// Byte 0
|
||||
#define HAIER_AC_PREFIX 0b10100101
|
||||
const uint8_t kHaierAcPrefix = 0b10100101;
|
||||
|
||||
// Byte 1
|
||||
#define HAIER_AC_MIN_TEMP 16
|
||||
#define HAIER_AC_MAX_TEMP 30
|
||||
#define HAIER_AC_DEF_TEMP 25
|
||||
|
||||
#define HAIER_AC_CMD_OFF 0b00000000
|
||||
#define HAIER_AC_CMD_ON 0b00000001
|
||||
#define HAIER_AC_CMD_MODE 0b00000010
|
||||
#define HAIER_AC_CMD_FAN 0b00000011
|
||||
#define HAIER_AC_CMD_TEMP_UP 0b00000110
|
||||
#define HAIER_AC_CMD_TEMP_DOWN 0b00000111
|
||||
#define HAIER_AC_CMD_SLEEP 0b00001000
|
||||
#define HAIER_AC_CMD_TIMER_SET 0b00001001
|
||||
#define HAIER_AC_CMD_TIMER_CANCEL 0b00001010
|
||||
#define HAIER_AC_CMD_HEALTH 0b00001100
|
||||
#define HAIER_AC_CMD_SWING 0b00001101
|
||||
const uint8_t kHaierAcMinTemp = 16;
|
||||
const uint8_t kHaierAcDefTemp = 25;
|
||||
const uint8_t kHaierAcMaxTemp = 30;
|
||||
const uint8_t kHaierAcCmdOff = 0b00000000;
|
||||
const uint8_t kHaierAcCmdOn = 0b00000001;
|
||||
const uint8_t kHaierAcCmdMode = 0b00000010;
|
||||
const uint8_t kHaierAcCmdFan = 0b00000011;
|
||||
const uint8_t kHaierAcCmdTempUp = 0b00000110;
|
||||
const uint8_t kHaierAcCmdTempDown = 0b00000111;
|
||||
const uint8_t kHaierAcCmdSleep = 0b00001000;
|
||||
const uint8_t kHaierAcCmdTimerSet = 0b00001001;
|
||||
const uint8_t kHaierAcCmdTimerCancel = 0b00001010;
|
||||
const uint8_t kHaierAcCmdHealth = 0b00001100;
|
||||
const uint8_t kHaierAcCmdSwing = 0b00001101;
|
||||
|
||||
// Byte 2
|
||||
#define HAIER_AC_SWING_OFF 0b00000000
|
||||
#define HAIER_AC_SWING_UP 0b00000001
|
||||
#define HAIER_AC_SWING_DOWN 0b00000010
|
||||
#define HAIER_AC_SWING_CHG 0b00000011
|
||||
const uint8_t kHaierAcSwingOff = 0b00000000;
|
||||
const uint8_t kHaierAcSwingUp = 0b00000001;
|
||||
const uint8_t kHaierAcSwingDown = 0b00000010;
|
||||
const uint8_t kHaierAcSwingChg = 0b00000011;
|
||||
|
||||
// Byte 6
|
||||
#define HAIER_AC_AUTO 0
|
||||
#define HAIER_AC_COOL 1
|
||||
#define HAIER_AC_DRY 2
|
||||
#define HAIER_AC_HEAT 3
|
||||
#define HAIER_AC_FAN 4
|
||||
const uint8_t kHaierAcAuto = 0;
|
||||
const uint8_t kHaierAcCool = 1;
|
||||
const uint8_t kHaierAcDry = 2;
|
||||
const uint8_t kHaierAcHeat = 3;
|
||||
const uint8_t kHaierAcFan = 4;
|
||||
|
||||
#define HAIER_AC_FAN_AUTO 0
|
||||
#define HAIER_AC_FAN_LOW 1
|
||||
#define HAIER_AC_FAN_MED 2
|
||||
#define HAIER_AC_FAN_HIGH 3
|
||||
const uint8_t kHaierAcFanAuto = 0;
|
||||
const uint8_t kHaierAcFanLow = 1;
|
||||
const uint8_t kHaierAcFanMed = 2;
|
||||
const uint8_t kHaierAcFanHigh = 3;
|
||||
|
||||
#define HAIER_AC_MAX_TIME (23 * 60 + 59)
|
||||
const uint16_t kHaierAcMaxTime = (23 * 60) + 59;
|
||||
|
||||
// Legacy Haier AC defines.
|
||||
#define HAIER_AC_MIN_TEMP kHaierAcMinTemp
|
||||
#define HAIER_AC_DEF_TEMP kHaierAcDefTemp
|
||||
#define HAIER_AC_MAX_TEMP kHaierAcMaxTemp
|
||||
#define HAIER_AC_CMD_OFF kHaierAcCmdOff
|
||||
#define HAIER_AC_CMD_ON kHaierAcCmdOn
|
||||
#define HAIER_AC_CMD_MODE kHaierAcCmdMode
|
||||
#define HAIER_AC_CMD_FAN kHaierAcCmdFan
|
||||
#define HAIER_AC_CMD_TEMP_UP kHaierAcCmdTempUp
|
||||
#define HAIER_AC_CMD_TEMP_DOWN kHaierAcCmdTempDown
|
||||
#define HAIER_AC_CMD_SLEEP kHaierAcCmdSleep
|
||||
#define HAIER_AC_CMD_TIMER_SET kHaierAcCmdTimerSet
|
||||
#define HAIER_AC_CMD_TIMER_CANCEL kHaierAcCmdTimerCancel
|
||||
#define HAIER_AC_CMD_HEALTH kHaierAcCmdHealth
|
||||
#define HAIER_AC_CMD_SWING kHaierAcCmdSwing
|
||||
#define HAIER_AC_SWING_OFF kHaierAcSwingOff
|
||||
#define HAIER_AC_SWING_UP kHaierAcSwingUp
|
||||
#define HAIER_AC_SWING_DOWN kHaierAcSwingDown
|
||||
#define HAIER_AC_SWING_CHG kHaierAcSwingChg
|
||||
#define HAIER_AC_AUTO kHaierAcAuto
|
||||
#define HAIER_AC_COOL kHaierAcCool
|
||||
#define HAIER_AC_DRY kHaierAcDry
|
||||
#define HAIER_AC_HEAT kHaierAcHeat
|
||||
#define HAIER_AC_FAN kHaierAcFan
|
||||
#define HAIER_AC_FAN_AUTO kHaierAcFanAuto
|
||||
#define HAIER_AC_FAN_LOW kHaierAcFanLow
|
||||
#define HAIER_AC_FAN_MED kHaierAcFanMed
|
||||
#define HAIER_AC_FAN_HIGH kHaierAcFanHigh
|
||||
|
||||
// Haier YRW02 remote
|
||||
// Byte 0
|
||||
#define HAIER_AC_YRW02_PREFIX 0xA6
|
||||
const uint8_t kHaierAcYrw02Prefix = 0xA6;
|
||||
|
||||
// Byte 1
|
||||
// Bits 0-3
|
||||
// 0x0 = 16DegC, ... 0xE = 30DegC
|
||||
// Bits 4-7 - Swing
|
||||
#define HAIER_AC_YRW02_SWING_OFF 0x0
|
||||
#define HAIER_AC_YRW02_SWING_TOP 0x1
|
||||
#define HAIER_AC_YRW02_SWING_MIDDLE 0x2 // Not available in heat mode.
|
||||
#define HAIER_AC_YRW02_SWING_BOTTOM 0x3 // Only available in heat mode.
|
||||
#define HAIER_AC_YRW02_SWING_DOWN 0xA
|
||||
#define HAIER_AC_YRW02_SWING_AUTO 0xC // Airflow
|
||||
|
||||
const uint8_t kHaierAcYrw02SwingOff = 0x0;
|
||||
const uint8_t kHaierAcYrw02SwingTop = 0x1;
|
||||
const uint8_t kHaierAcYrw02SwingMiddle = 0x2; // Not available in heat mode.
|
||||
const uint8_t kHaierAcYrw02SwingBottom = 0x3; // Only available in heat mode.
|
||||
const uint8_t kHaierAcYrw02SwingDown = 0xA;
|
||||
const uint8_t kHaierAcYrw02SwingAuto = 0xC; // Airflow
|
||||
|
||||
// Byte 3
|
||||
// Bit 7 - Health mode
|
||||
|
||||
// Byte 4
|
||||
#define HAIER_AC_YRW02_POWER 0b01000000
|
||||
const uint8_t kHaierAcYrw02Power = 0b01000000;
|
||||
|
||||
// Byte 5
|
||||
// Bits 0-3
|
||||
#define HAIER_AC_YRW02_FAN_HIGH 0x2
|
||||
#define HAIER_AC_YRW02_FAN_MED 0x4
|
||||
#define HAIER_AC_YRW02_FAN_LOW 0x6
|
||||
#define HAIER_AC_YRW02_FAN_AUTO 0xA
|
||||
|
||||
const uint8_t kHaierAcYrw02FanHigh = 0x2;
|
||||
const uint8_t kHaierAcYrw02FanMed = 0x4;
|
||||
const uint8_t kHaierAcYrw02FanLow = 0x6;
|
||||
const uint8_t kHaierAcYrw02FanAuto = 0xA;
|
||||
|
||||
// Byte 6
|
||||
// Bits 0-1
|
||||
#define HAIER_AC_YRW02_TURBO_OFF 0x0
|
||||
#define HAIER_AC_YRW02_TURBO_HIGH 0x1
|
||||
#define HAIER_AC_YRW02_TURBO_LOW 0x2
|
||||
const uint8_t kHaierAcYrw02TurboOff = 0x0;
|
||||
const uint8_t kHaierAcYrw02TurboHigh = 0x1;
|
||||
const uint8_t kHaierAcYrw02TurboLow = 0x2;
|
||||
|
||||
// Byte 7
|
||||
// Bits 0-3
|
||||
#define HAIER_AC_YRW02_AUTO 0x0
|
||||
#define HAIER_AC_YRW02_COOL 0x2
|
||||
#define HAIER_AC_YRW02_DRY 0x4
|
||||
#define HAIER_AC_YRW02_HEAT 0x8
|
||||
#define HAIER_AC_YRW02_FAN 0xC
|
||||
const uint8_t kHaierAcYrw02Auto = 0x0;
|
||||
const uint8_t kHaierAcYrw02Cool = 0x2;
|
||||
const uint8_t kHaierAcYrw02Dry = 0x4;
|
||||
const uint8_t kHaierAcYrw02Heat = 0x8;
|
||||
const uint8_t kHaierAcYrw02Fan = 0xC;
|
||||
|
||||
// Byte 8
|
||||
#define HAIER_AC_YRW02_SLEEP 0b10000000
|
||||
const uint8_t kHaierAcYrw02Sleep = 0b10000000;
|
||||
|
||||
// Byte 12
|
||||
// Bits 4-7
|
||||
#define HAIER_AC_YRW02_BUTTON_TEMP_UP 0x0
|
||||
#define HAIER_AC_YRW02_BUTTON_TEMP_DOWN 0x1
|
||||
#define HAIER_AC_YRW02_BUTTON_SWING 0x2
|
||||
#define HAIER_AC_YRW02_BUTTON_FAN 0x4
|
||||
#define HAIER_AC_YRW02_BUTTON_POWER 0x5
|
||||
#define HAIER_AC_YRW02_BUTTON_MODE 0x6
|
||||
#define HAIER_AC_YRW02_BUTTON_HEALTH 0x7
|
||||
#define HAIER_AC_YRW02_BUTTON_TURBO 0x8
|
||||
#define HAIER_AC_YRW02_BUTTON_SLEEP 0xB
|
||||
const uint8_t kHaierAcYrw02ButtonTempUp = 0x0;
|
||||
const uint8_t kHaierAcYrw02ButtonTempDown = 0x1;
|
||||
const uint8_t kHaierAcYrw02ButtonSwing = 0x2;
|
||||
const uint8_t kHaierAcYrw02ButtonFan = 0x4;
|
||||
const uint8_t kHaierAcYrw02ButtonPower = 0x5;
|
||||
const uint8_t kHaierAcYrw02ButtonMode = 0x6;
|
||||
const uint8_t kHaierAcYrw02ButtonHealth = 0x7;
|
||||
const uint8_t kHaierAcYrw02ButtonTurbo = 0x8;
|
||||
const uint8_t kHaierAcYrw02ButtonSleep = 0xB;
|
||||
|
||||
// Legacy Haier YRW02 remote defines.
|
||||
#define HAIER_AC_YRW02_SWING_OFF kHaierAcYrw02SwingOff
|
||||
#define HAIER_AC_YRW02_SWING_TOP kHaierAcYrw02SwingTop
|
||||
#define HAIER_AC_YRW02_SWING_MIDDLE kHaierAcYrw02SwingMiddle
|
||||
#define HAIER_AC_YRW02_SWING_BOTTOM kHaierAcYrw02SwingBottom
|
||||
#define HAIER_AC_YRW02_SWING_DOWN kHaierAcYrw02SwingDown
|
||||
#define HAIER_AC_YRW02_SWING_AUTO kHaierAcYrw02SwingAuto
|
||||
#define HAIER_AC_YRW02_FAN_HIGH kHaierAcYrw02FanHigh
|
||||
#define HAIER_AC_YRW02_FAN_MED kHaierAcYrw02FanMed
|
||||
#define HAIER_AC_YRW02_FAN_LOW kHaierAcYrw02FanLow
|
||||
#define HAIER_AC_YRW02_FAN_AUTO kHaierAcYrw02FanAuto
|
||||
#define HAIER_AC_YRW02_TURBO_OFF kHaierAcYrw02TurboOff
|
||||
#define HAIER_AC_YRW02_TURBO_HIGH kHaierAcYrw02TurboHigh
|
||||
#define HAIER_AC_YRW02_TURBO_LOW kHaierAcYrw02TurboLow
|
||||
#define HAIER_AC_YRW02_AUTO kHaierAcYrw02Auto
|
||||
#define HAIER_AC_YRW02_COOL kHaierAcYrw02Cool
|
||||
#define HAIER_AC_YRW02_DRY kHaierAcYrw02Dry
|
||||
#define HAIER_AC_YRW02_HEAT kHaierAcYrw02Heat
|
||||
#define HAIER_AC_YRW02_FAN kHaierAcYrw02Fan
|
||||
#define HAIER_AC_YRW02_BUTTON_TEMP_UP kHaierAcYrw02ButtonTempUp
|
||||
#define HAIER_AC_YRW02_BUTTON_TEMP_DOWN kHaierAcYrw02ButtonTempDown
|
||||
#define HAIER_AC_YRW02_BUTTON_SWING kHaierAcYrw02ButtonSwing
|
||||
#define HAIER_AC_YRW02_BUTTON_FAN kHaierAcYrw02ButtonFan
|
||||
#define HAIER_AC_YRW02_BUTTON_POWER kHaierAcYrw02ButtonPower
|
||||
#define HAIER_AC_YRW02_BUTTON_MODE kHaierAcYrw02ButtonMode
|
||||
#define HAIER_AC_YRW02_BUTTON_HEALTH kHaierAcYrw02ButtonHealth
|
||||
#define HAIER_AC_YRW02_BUTTON_TURBO kHaierAcYrw02ButtonTurbo
|
||||
#define HAIER_AC_YRW02_BUTTON_SLEEP kHaierAcYrw02ButtonSleep
|
||||
|
||||
class IRHaierAC {
|
||||
public:
|
||||
@@ -168,17 +222,17 @@ class IRHaierAC {
|
||||
uint8_t* getRaw();
|
||||
void setRaw(uint8_t new_code[]);
|
||||
static bool validChecksum(uint8_t state[],
|
||||
const uint16_t length = HAIER_AC_STATE_LENGTH);
|
||||
#ifdef ARDUINO
|
||||
String toString();
|
||||
static String timeToString(const uint16_t nr_mins);
|
||||
#else
|
||||
std::string toString();
|
||||
static std::string timeToString(const uint16_t nr_mins);
|
||||
#endif
|
||||
const uint16_t length = kHaierACStateLength);
|
||||
#ifdef ARDUINO
|
||||
String toString();
|
||||
static String timeToString(const uint16_t nr_mins);
|
||||
#else
|
||||
std::string toString();
|
||||
static std::string timeToString(const uint16_t nr_mins);
|
||||
#endif
|
||||
|
||||
private:
|
||||
uint8_t remote_state[HAIER_AC_STATE_LENGTH];
|
||||
uint8_t remote_state[kHaierACStateLength];
|
||||
void stateReset();
|
||||
void checksum();
|
||||
static uint16_t getTime(const uint8_t ptr[]);
|
||||
@@ -186,7 +240,6 @@ class IRHaierAC {
|
||||
IRsend _irsend;
|
||||
};
|
||||
|
||||
|
||||
class IRHaierACYRW02 {
|
||||
public:
|
||||
explicit IRHaierACYRW02(uint16_t pin);
|
||||
@@ -227,15 +280,15 @@ class IRHaierACYRW02 {
|
||||
uint8_t* getRaw();
|
||||
void setRaw(uint8_t new_code[]);
|
||||
static bool validChecksum(uint8_t state[],
|
||||
const uint16_t length = HAIER_AC_YRW02_STATE_LENGTH);
|
||||
#ifdef ARDUINO
|
||||
String toString();
|
||||
#else
|
||||
std::string toString();
|
||||
#endif
|
||||
const uint16_t length = kHaierACYRW02StateLength);
|
||||
#ifdef ARDUINO
|
||||
String toString();
|
||||
#else
|
||||
std::string toString();
|
||||
#endif
|
||||
|
||||
private:
|
||||
uint8_t remote_state[HAIER_AC_YRW02_STATE_LENGTH];
|
||||
uint8_t remote_state[kHaierACYRW02StateLength];
|
||||
void stateReset();
|
||||
void checksum();
|
||||
IRsend _irsend;
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
#ifndef ARDUINO
|
||||
#include <string>
|
||||
#endif
|
||||
#include "IRremoteESP8266.h"
|
||||
#include "IRrecv.h"
|
||||
#include "IRremoteESP8266.h"
|
||||
#include "IRsend.h"
|
||||
#include "IRutils.h"
|
||||
|
||||
@@ -22,21 +22,21 @@
|
||||
|
||||
// Constants
|
||||
// Ref: https://github.com/markszabo/IRremoteESP8266/issues/417
|
||||
#define HITACHI_AC_HDR_MARK 3300U
|
||||
#define HITACHI_AC_HDR_SPACE 1700U
|
||||
#define HITACHI_AC1_HDR_MARK 3400U
|
||||
#define HITACHI_AC1_HDR_SPACE 3400U
|
||||
#define HITACHI_AC_BIT_MARK 400U
|
||||
#define HITACHI_AC_ONE_SPACE 1250U
|
||||
#define HITACHI_AC_ZERO_SPACE 500U
|
||||
#define HITACHI_AC_MIN_GAP 100000U // Completely made up value.
|
||||
const uint16_t kHitachiAcHdrMark = 3300;
|
||||
const uint16_t kHitachiAcHdrSpace = 1700;
|
||||
const uint16_t kHitachiAc1HdrMark = 3400;
|
||||
const uint16_t kHitachiAc1HdrSpace = 3400;
|
||||
const uint16_t kHitachiAcBitMark = 400;
|
||||
const uint16_t kHitachiAcOneSpace = 1250;
|
||||
const uint16_t kHitachiAcZeroSpace = 500;
|
||||
const uint32_t kHitachiAcMinGap = 100000; // Completely made up value.
|
||||
|
||||
#if (SEND_HITACHI_AC || SEND_HITACHI_AC2)
|
||||
// Send a Hitachi A/C message.
|
||||
//
|
||||
// Args:
|
||||
// data: An array of bytes containing the IR command.
|
||||
// nbytes: Nr. of bytes of data in the array. (>=HITACHI_AC_STATE_LENGTH)
|
||||
// nbytes: Nr. of bytes of data in the array. (>=kHitachiAcStateLength)
|
||||
// repeat: Nr. of times the message is to be repeated. (Default = 0).
|
||||
//
|
||||
// Status: ALPHA / Untested.
|
||||
@@ -45,13 +45,12 @@
|
||||
// https://github.com/markszabo/IRremoteESP8266/issues/417
|
||||
void IRsend::sendHitachiAC(unsigned char data[], uint16_t nbytes,
|
||||
uint16_t repeat) {
|
||||
if (nbytes < HITACHI_AC_STATE_LENGTH)
|
||||
if (nbytes < kHitachiAcStateLength)
|
||||
return; // Not enough bytes to send a proper message.
|
||||
sendGeneric(HITACHI_AC_HDR_MARK, HITACHI_AC_HDR_SPACE,
|
||||
HITACHI_AC_BIT_MARK, HITACHI_AC_ONE_SPACE,
|
||||
HITACHI_AC_BIT_MARK, HITACHI_AC_ZERO_SPACE,
|
||||
HITACHI_AC_BIT_MARK, HITACHI_AC_MIN_GAP,
|
||||
data, nbytes, 38, true, repeat, 50);
|
||||
sendGeneric(kHitachiAcHdrMark, kHitachiAcHdrSpace, kHitachiAcBitMark,
|
||||
kHitachiAcOneSpace, kHitachiAcBitMark, kHitachiAcZeroSpace,
|
||||
kHitachiAcBitMark, kHitachiAcMinGap, data, nbytes, 38, true,
|
||||
repeat, 50);
|
||||
}
|
||||
#endif // (SEND_HITACHI_AC || SEND_HITACHI_AC2)
|
||||
|
||||
@@ -63,7 +62,7 @@ void IRsend::sendHitachiAC(unsigned char data[], uint16_t nbytes,
|
||||
//
|
||||
// Args:
|
||||
// data: An array of bytes containing the IR command.
|
||||
// nbytes: Nr. of bytes of data in the array. (>=HITACHI_AC1_STATE_LENGTH)
|
||||
// nbytes: Nr. of bytes of data in the array. (>=kHitachiAc1StateLength)
|
||||
// repeat: Nr. of times the message is to be repeated. (Default = 0).
|
||||
//
|
||||
// Status: BETA / Appears to work.
|
||||
@@ -73,13 +72,12 @@ void IRsend::sendHitachiAC(unsigned char data[], uint16_t nbytes,
|
||||
// Basically the same as sendHitatchiAC() except different size and header.
|
||||
void IRsend::sendHitachiAC1(unsigned char data[], uint16_t nbytes,
|
||||
uint16_t repeat) {
|
||||
if (nbytes < HITACHI_AC1_STATE_LENGTH)
|
||||
if (nbytes < kHitachiAc1StateLength)
|
||||
return; // Not enough bytes to send a proper message.
|
||||
sendGeneric(HITACHI_AC1_HDR_MARK, HITACHI_AC1_HDR_SPACE,
|
||||
HITACHI_AC_BIT_MARK, HITACHI_AC_ONE_SPACE,
|
||||
HITACHI_AC_BIT_MARK, HITACHI_AC_ZERO_SPACE,
|
||||
HITACHI_AC_BIT_MARK, HITACHI_AC_MIN_GAP,
|
||||
data, nbytes, 38, true, repeat, 50);
|
||||
sendGeneric(kHitachiAc1HdrMark, kHitachiAc1HdrSpace, kHitachiAcBitMark,
|
||||
kHitachiAcOneSpace, kHitachiAcBitMark, kHitachiAcZeroSpace,
|
||||
kHitachiAcBitMark, kHitachiAcMinGap, data, nbytes, 38, true,
|
||||
repeat, 50);
|
||||
}
|
||||
#endif // SEND_HITACHI_AC1
|
||||
|
||||
@@ -91,7 +89,7 @@ void IRsend::sendHitachiAC1(unsigned char data[], uint16_t nbytes,
|
||||
//
|
||||
// Args:
|
||||
// data: An array of bytes containing the IR command.
|
||||
// nbytes: Nr. of bytes of data in the array. (>=HITACHI_AC2_STATE_LENGTH)
|
||||
// nbytes: Nr. of bytes of data in the array. (>=kHitachiAc2StateLength)
|
||||
// repeat: Nr. of times the message is to be repeated. (Default = 0).
|
||||
//
|
||||
// Status: BETA / Appears to work.
|
||||
@@ -101,7 +99,7 @@ void IRsend::sendHitachiAC1(unsigned char data[], uint16_t nbytes,
|
||||
// Basically the same as sendHitatchiAC() except different size.
|
||||
void IRsend::sendHitachiAC2(unsigned char data[], uint16_t nbytes,
|
||||
uint16_t repeat) {
|
||||
if (nbytes < HITACHI_AC2_STATE_LENGTH)
|
||||
if (nbytes < kHitachiAc2StateLength)
|
||||
return; // Not enough bytes to send a proper message.
|
||||
sendHitachiAC(data, nbytes, repeat);
|
||||
}
|
||||
@@ -113,7 +111,7 @@ void IRsend::sendHitachiAC2(unsigned char data[], uint16_t nbytes,
|
||||
// Args:
|
||||
// results: Ptr to the data to decode and where to store the decode result.
|
||||
// nbits: The number of data bits to expect.
|
||||
// Typically HITACHI_AC_BITS, HITACHI_AC1_BITS, HITACHI_AC2_BITS
|
||||
// Typically kHitachiAcBits, kHitachiAc1Bits, kHitachiAc2Bits
|
||||
// strict: Flag indicating if we should perform strict matching.
|
||||
// Returns:
|
||||
// boolean: True if it can decode it, false if it can't.
|
||||
@@ -129,65 +127,59 @@ void IRsend::sendHitachiAC2(unsigned char data[], uint16_t nbytes,
|
||||
bool IRrecv::decodeHitachiAC(decode_results *results, uint16_t nbits,
|
||||
bool strict) {
|
||||
const uint8_t kTolerance = 30;
|
||||
if (results->rawlen < 2 * nbits + HEADER + FOOTER - 1)
|
||||
if (results->rawlen < 2 * nbits + kHeader + kFooter - 1)
|
||||
return false; // Can't possibly be a valid HitachiAC message.
|
||||
if (strict) {
|
||||
switch (nbits) {
|
||||
case HITACHI_AC_BITS:
|
||||
case HITACHI_AC1_BITS:
|
||||
case HITACHI_AC2_BITS:
|
||||
case kHitachiAcBits:
|
||||
case kHitachiAc1Bits:
|
||||
case kHitachiAc2Bits:
|
||||
break; // Okay to continue.
|
||||
default:
|
||||
return false; // Not strictly a Hitachi message.
|
||||
}
|
||||
}
|
||||
uint16_t offset = OFFSET_START;
|
||||
uint16_t offset = kStartOffset;
|
||||
uint16_t dataBitsSoFar = 0;
|
||||
match_result_t data_result;
|
||||
|
||||
// Header
|
||||
if (nbits == HITACHI_AC1_BITS) {
|
||||
if (!matchMark(results->rawbuf[offset++], HITACHI_AC1_HDR_MARK, kTolerance))
|
||||
if (nbits == kHitachiAc1Bits) {
|
||||
if (!matchMark(results->rawbuf[offset++], kHitachiAc1HdrMark, kTolerance))
|
||||
return false;
|
||||
if (!matchSpace(results->rawbuf[offset++], HITACHI_AC1_HDR_SPACE,
|
||||
kTolerance))
|
||||
if (!matchSpace(results->rawbuf[offset++], kHitachiAc1HdrSpace, kTolerance))
|
||||
return false;
|
||||
} else { // Everything else.
|
||||
if (!matchMark(results->rawbuf[offset++], HITACHI_AC_HDR_MARK, kTolerance))
|
||||
if (!matchMark(results->rawbuf[offset++], kHitachiAcHdrMark, kTolerance))
|
||||
return false;
|
||||
if (!matchSpace(results->rawbuf[offset++], HITACHI_AC_HDR_SPACE,
|
||||
kTolerance))
|
||||
if (!matchSpace(results->rawbuf[offset++], kHitachiAcHdrSpace, kTolerance))
|
||||
return false;
|
||||
}
|
||||
// Data
|
||||
// Keep reading bytes until we either run out of message or state to fill.
|
||||
for (uint16_t i = 0;
|
||||
offset <= results->rawlen - 16 && i < nbits / 8;
|
||||
i++, dataBitsSoFar += 8, offset += data_result.used) {
|
||||
data_result = matchData(&(results->rawbuf[offset]), 8,
|
||||
HITACHI_AC_BIT_MARK,
|
||||
HITACHI_AC_ONE_SPACE,
|
||||
HITACHI_AC_BIT_MARK,
|
||||
HITACHI_AC_ZERO_SPACE,
|
||||
kTolerance);
|
||||
if (data_result.success == false) break; // Fail
|
||||
results->state[i] = (uint8_t) data_result.data;
|
||||
for (uint16_t i = 0; offset <= results->rawlen - 16 && i < nbits / 8;
|
||||
i++, dataBitsSoFar += 8, offset += data_result.used) {
|
||||
data_result = matchData(&(results->rawbuf[offset]), 8, kHitachiAcBitMark,
|
||||
kHitachiAcOneSpace, kHitachiAcBitMark,
|
||||
kHitachiAcZeroSpace, kTolerance);
|
||||
if (data_result.success == false) break; // Fail
|
||||
results->state[i] = (uint8_t)data_result.data;
|
||||
}
|
||||
|
||||
// Footer
|
||||
if (!matchMark(results->rawbuf[offset++], HITACHI_AC_BIT_MARK, kTolerance))
|
||||
if (!matchMark(results->rawbuf[offset++], kHitachiAcBitMark, kTolerance))
|
||||
return false;
|
||||
if (offset <= results->rawlen &&
|
||||
!matchAtLeast(results->rawbuf[offset], HITACHI_AC_MIN_GAP, kTolerance))
|
||||
!matchAtLeast(results->rawbuf[offset], kHitachiAcMinGap, kTolerance))
|
||||
return false;
|
||||
|
||||
// Compliance
|
||||
if (strict) {
|
||||
// Re-check we got the correct size/length due to the way we read the data.
|
||||
switch (dataBitsSoFar / 8) {
|
||||
case HITACHI_AC_STATE_LENGTH:
|
||||
case HITACHI_AC1_STATE_LENGTH:
|
||||
case HITACHI_AC2_STATE_LENGTH:
|
||||
case kHitachiAcStateLength:
|
||||
case kHitachiAc1StateLength:
|
||||
case kHitachiAc2StateLength:
|
||||
break; // Continue
|
||||
default:
|
||||
return false;
|
||||
@@ -196,13 +188,13 @@ bool IRrecv::decodeHitachiAC(decode_results *results, uint16_t nbits,
|
||||
|
||||
// Success
|
||||
switch (dataBitsSoFar) {
|
||||
case HITACHI_AC1_BITS:
|
||||
case kHitachiAc1Bits:
|
||||
results->decode_type = HITACHI_AC1;
|
||||
break;
|
||||
case HITACHI_AC2_BITS:
|
||||
case kHitachiAc2Bits:
|
||||
results->decode_type = HITACHI_AC2;
|
||||
break;
|
||||
case HITACHI_AC_BITS:
|
||||
case kHitachiAcBits:
|
||||
default:
|
||||
results->decode_type = HITACHI_AC;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user