From 9dfa0c4c6d488d175866cf9917e6b1cec4ea7220 Mon Sep 17 00:00:00 2001 From: Khoi Hoang <57012152+khoih-prog@users.noreply.github.com> Date: Sun, 11 Dec 2022 01:30:05 -0500 Subject: [PATCH] v1.0.0 for ESP32 + LwIP ENC28J60 #### Releases v1.0.0 1. Initial coding to port [ESP_WiFiManager](https://github.com/khoih-prog/ESP_WiFiManager) to ESP32 boards using `LwIP ENC28J60 Ethernet`. 2. Use `allman astyle` --- .codespellrc | 7 + CONTRIBUTING.md | 79 + Images/Configuration_AIO_MQTT.png | Bin 0 -> 36319 bytes Images/Configuration_Standard.png | Bin 0 -> 17154 bytes Images/ENC28J60.png | Bin 0 -> 143496 bytes Images/Info.png | Bin 0 -> 70044 bytes Images/Main.png | Bin 0 -> 13218 bytes Images/Saved.png | Bin 0 -> 2478 bytes changelog.md | 33 + .../ConfigOnDoubleReset.ino | 724 ++++++++ .../ConfigOnDoubleReset_TZ.ino | 751 ++++++++ examples/ConfigOnSwitch/ConfigOnSwitch.ino | 908 ++++++++++ .../ConfigOnSwitchFS/ConfigOnSwitchFS.ino | 1116 ++++++++++++ .../ConfigPortalParamsOnSwitch.ino | 1012 +++++++++++ .../ESP32_FSWebServer/ESP32_FSWebServer.ino | 1059 ++++++++++++ examples/ESP32_FSWebServer/README.md | 69 + .../ESP32_FSWebServer/data/CanadaFlag_1.png | Bin 0 -> 41214 bytes .../ESP32_FSWebServer/data/CanadaFlag_2.png | Bin 0 -> 8311 bytes .../ESP32_FSWebServer/data/CanadaFlag_3.jpg | Bin 0 -> 11156 bytes examples/ESP32_FSWebServer/data/edit.htm.gz | Bin 0 -> 4116 bytes examples/ESP32_FSWebServer/data/favicon.ico | Bin 0 -> 1150 bytes examples/ESP32_FSWebServer/data/graphs.js.gz | Bin 0 -> 1971 bytes examples/ESP32_FSWebServer/data/index.htm | 97 ++ .../ESP32_FSWebServer/pics/esp32fs.local.png | Bin 0 -> 20520 bytes .../pics/esp32fs.local_edit.png | Bin 0 -> 76964 bytes .../ESP32_FSWebServer_DRD.ino | 1113 ++++++++++++ examples/ESP32_FSWebServer_DRD/README.md | 70 + .../data/CanadaFlag_1.png | Bin 0 -> 41214 bytes .../data/CanadaFlag_2.png | Bin 0 -> 8311 bytes .../data/CanadaFlag_3.jpg | Bin 0 -> 11156 bytes .../ESP32_FSWebServer_DRD/data/edit.htm.gz | Bin 0 -> 4116 bytes .../ESP32_FSWebServer_DRD/data/favicon.ico | Bin 0 -> 1150 bytes .../ESP32_FSWebServer_DRD/data/graphs.js.gz | Bin 0 -> 1971 bytes examples/ESP32_FSWebServer_DRD/data/index.htm | 97 ++ .../pics/esp32fs.local.png | Bin 0 -> 20520 bytes .../pics/esp32fs.local_edit.png | Bin 0 -> 76964 bytes keywords.txt | 92 + library.json | 44 + library.properties | 12 + platformio/platformio.ini | 92 + src/ESP32_ENC_Manager.h | 32 + src/ESP32_ENC_Manager.hpp | 630 +++++++ src/ESP32_ENC_Manager_Debug.h | 91 + src/ESP32_ENC_Manager_Impl.h | 1219 +++++++++++++ src/utils/TZ.h | 1526 +++++++++++++++++ travis/common.sh | 51 + utils/astyle_library.conf | 70 + utils/restyle.sh | 6 + 48 files changed, 11000 insertions(+) create mode 100644 .codespellrc create mode 100644 CONTRIBUTING.md create mode 100644 Images/Configuration_AIO_MQTT.png create mode 100644 Images/Configuration_Standard.png create mode 100644 Images/ENC28J60.png create mode 100644 Images/Info.png create mode 100644 Images/Main.png create mode 100644 Images/Saved.png create mode 100644 changelog.md create mode 100644 examples/ConfigOnDoubleReset/ConfigOnDoubleReset.ino create mode 100644 examples/ConfigOnDoubleReset_TZ/ConfigOnDoubleReset_TZ.ino create mode 100644 examples/ConfigOnSwitch/ConfigOnSwitch.ino create mode 100644 examples/ConfigOnSwitchFS/ConfigOnSwitchFS.ino create mode 100644 examples/ConfigPortalParamsOnSwitch/ConfigPortalParamsOnSwitch.ino create mode 100644 examples/ESP32_FSWebServer/ESP32_FSWebServer.ino create mode 100644 examples/ESP32_FSWebServer/README.md create mode 100644 examples/ESP32_FSWebServer/data/CanadaFlag_1.png create mode 100644 examples/ESP32_FSWebServer/data/CanadaFlag_2.png create mode 100644 examples/ESP32_FSWebServer/data/CanadaFlag_3.jpg create mode 100644 examples/ESP32_FSWebServer/data/edit.htm.gz create mode 100644 examples/ESP32_FSWebServer/data/favicon.ico create mode 100644 examples/ESP32_FSWebServer/data/graphs.js.gz create mode 100644 examples/ESP32_FSWebServer/data/index.htm create mode 100644 examples/ESP32_FSWebServer/pics/esp32fs.local.png create mode 100644 examples/ESP32_FSWebServer/pics/esp32fs.local_edit.png create mode 100644 examples/ESP32_FSWebServer_DRD/ESP32_FSWebServer_DRD.ino create mode 100644 examples/ESP32_FSWebServer_DRD/README.md create mode 100644 examples/ESP32_FSWebServer_DRD/data/CanadaFlag_1.png create mode 100644 examples/ESP32_FSWebServer_DRD/data/CanadaFlag_2.png create mode 100644 examples/ESP32_FSWebServer_DRD/data/CanadaFlag_3.jpg create mode 100644 examples/ESP32_FSWebServer_DRD/data/edit.htm.gz create mode 100644 examples/ESP32_FSWebServer_DRD/data/favicon.ico create mode 100644 examples/ESP32_FSWebServer_DRD/data/graphs.js.gz create mode 100644 examples/ESP32_FSWebServer_DRD/data/index.htm create mode 100644 examples/ESP32_FSWebServer_DRD/pics/esp32fs.local.png create mode 100644 examples/ESP32_FSWebServer_DRD/pics/esp32fs.local_edit.png create mode 100644 keywords.txt create mode 100644 library.json create mode 100644 library.properties create mode 100644 platformio/platformio.ini create mode 100644 src/ESP32_ENC_Manager.h create mode 100644 src/ESP32_ENC_Manager.hpp create mode 100644 src/ESP32_ENC_Manager_Debug.h create mode 100644 src/ESP32_ENC_Manager_Impl.h create mode 100644 src/utils/TZ.h create mode 100644 travis/common.sh create mode 100644 utils/astyle_library.conf create mode 100644 utils/restyle.sh diff --git a/.codespellrc b/.codespellrc new file mode 100644 index 0000000..00fe362 --- /dev/null +++ b/.codespellrc @@ -0,0 +1,7 @@ +# See: https://github.com/codespell-project/codespell#using-a-config-file +[codespell] +# In the event of a false positive, add the problematic word, in all lowercase, to a comma-separated list here: +ignore-words-list = , +check-filenames = +check-hidden = +skip = ./.git,./src,./examples,./Packages_Patches,./LibraryPatches diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..4c78964 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,79 @@ +## Contributing to ESP32_ENC_Manager + +### Reporting Bugs + +Please report bugs in ESP32_ENC_Manager if you find them. + +However, before reporting a bug please check through the following: + +* [Existing Open Issues](https://github.com/khoih-prog/ESP32_ENC_Manager/issues) - someone might have already encountered this. + +If you don't find anything, please [open a new issue](https://github.com/khoih-prog/ESP32_ENC_Manager/issues/new). + +### How to submit a bug report + +Please ensure to specify the following: + +* Arduino IDE version (e.g. 1.8.19) or Platform.io version +* Board Core Version (e.g. ESP32 core v2.0.5) +* Contextual information (e.g. what you were trying to achieve) +* Simplest possible steps to reproduce +* Anything that might be relevant in your opinion, such as: + * Operating system (Windows, Ubuntu, etc.) and the output of `uname -a` + * Network configuration + + +Please be educated, civilized and constructive. Disrespective posts against [GitHub Code of Conduct](https://docs.github.com/en/site-policy/github-terms/github-event-code-of-conduct) will be ignored and deleted. + + +### Example + +``` +Arduino IDE version: 1.8.19 +ESP32_DEV board +ESP32 core v2.0.5 +OS: Ubuntu 20.04 LTS +Linux xy-Inspiron-3593 5.15.0-56-generic #62~20.04.1-Ubuntu SMP Tue Nov 22 21:24:20 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux + +Context: +I encountered a crash while using this library +Steps to reproduce: +1. ... +2. ... +3. ... +4. ... +``` + +### Additional context + +Add any other context about the problem here. + +--- + +### Sending Feature Requests + +Feel free to post feature requests. It's helpful if you can explain exactly why the feature would be useful. + +There are usually some outstanding feature requests in the [existing issues list](https://github.com/khoih-prog/ESP32_ENC_Manager/issues?q=is%3Aopen+is%3Aissue+label%3Aenhancement), feel free to add comments to them. + +--- + +### Sending Pull Requests + +Pull Requests with changes and fixes are also welcome! + +Please use the `astyle` to reformat the updated library code as follows (demo for Ubuntu Linux) + +1. Change directory to the library GitHub + +``` +xy@xy-Inspiron-3593:~$ cd Arduino/xy/ESP32_ENC_Manager_GitHub/ +xy@xy-Inspiron-3593:~/Arduino/xy/ESP32_ENC_Manager_GitHub$ +``` + +2. Issue astyle command + +``` +xy@xy-Inspiron-3593:~/Arduino/xy/ESP32_ENC_Manager_GitHub$ bash utils/restyle.sh +``` + diff --git a/Images/Configuration_AIO_MQTT.png b/Images/Configuration_AIO_MQTT.png new file mode 100644 index 0000000000000000000000000000000000000000..75ad6cae61aee038fffedbb4181e0538c6f26ded GIT binary patch literal 36319 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 literal 0 HcmV?d00001 diff --git a/Images/ENC28J60.png b/Images/ENC28J60.png new file mode 100644 index 0000000000000000000000000000000000000000..dfaf18b92ab43cc71831124739ef2c30be7a32f1 GIT binary patch literal 143496 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 literal 0 HcmV?d00001 diff --git a/Images/Main.png b/Images/Main.png new file mode 100644 index 0000000000000000000000000000000000000000..6d570d3509eee5e005258bea12d8c076bfbcaf65 GIT binary patch literal 13218 zcma)jWmH_vwk;uqgg}4>fi}^oFE03?ZZW7vVYL1p}9wsgpC~DU3Zf+JXW&yu3P*C2Y z$N)d7d(Q1Ig5A`nTj`IMy`&L+N+bc)DWu@&rO%O;38i)kR?m@1>>pmJ6#o#h zZGdlgkc?(Uht&jXsJHCXt&J_~keyn{a&w0Yx7Hw=*gw5uRWT7`A;k;hHhyhN6+ou^ z)|kX@S6VRYO1!Qz;#JTLdgn#;iPZPp(;2J7!&z`fHnrq9H!2D-Mi>^4?6`Ck}d{SzV?aDg^tV!MeJ05q_zSqXN(*MS zJ6TP<~3OeF@rmee2$;>I*;cmfR8$!)3d*QG|et6E88B=XVa-dlfYsBMlRs8 z-tPYtN9d@XI!cHWskGQm4s>)p><%M}#zs*ajiHrGVAZPwUmPqgEn#3lKfe9R@N(>l zap*PN1E!{}eF^_?C@=j{I))pJw2R|xpRlN(7tj3t742(>F?-4|gXxz-(EaUIT3Q-D z9xi$BpX6ulahB}F1QH}SH&@Qf0YM|NwY_*5Zbc2jWX5>xSgdf9VxpZvO!qaIli$Ml zpT-MXa;`5j**0$LS;@8@Yw3VBpJMm@N;GWZc2*8RsblKX)mX*Xy%;MAKcG{5@F)IW z&%fyLPcpya`gCw(HArk0fazxb-z_z4?E12hmhPLL2aT`qJmcJ(y zy)!$n_BtsmKAN@F$cfCn_j$j+BN`ckOfdi2@7>#j-)balO-3cPCxmz36D9mBhgMj* zE?SvSBEoP`os7(DS5GOvXYbHALae4XMVnq(YZ!-Gw)7mT ziDU7l-@rV9MH2CaIx8$@q}$FGsxG02M5wEgdqQyn*JGb{WHlkU7pZSfBm_q2oljXZ z|CqEIDAh@zk94P>sKp|MHF?=4zcF(vjAk&;HNLg@3Z~@KtJYK}PP8YP`_3PEDXaz5z%9tT zV~ZiwR}q32zJk-OsS-4dh2OG656!cXU&r|PdUuhxXccdiVSCL2Kts-a0fxf1n) z8Pz#ll95?4q}RH$Ba0tC=~|#a(*={;uUBm`52sS6@Zd?9*$yV<)U%E* zeDjX_LY&RwcPqsyu&}*4TCz=G_xBsONGuCS=q7AQ!|#MI}QgL%n(<2#Apf(ini8;QV2) z6vFt|+A&cgDvZxLH*Z~bY$Dpjp z;wz6|d7pZ_e{?i$VwMRsu|oFTrH(47(YmyIh%Q_RgP;sPn%D;AaOp)`rx`i#vd`a4 z0;8b}w-%;y4BLkj(&lNdXJjlb5+j--rnr+!wfVvCb<2x=p+JT6T3S+gfyuYZWVgQz zlr{y#_HDe}wW$Rfuc!N&5%ZYGtHL4vtlW_`UW9T+g3^msh}f@uS+YXAEEA4ZC-Cm; zVkK2)=s_`!E}ts%|>iiAXDRV0fe0 zu#cC7G_C3`^7HiL(oz+dAeAu+{|zC5^*lpg7HMc@B9=AM6rbFfD~u=5Yl;zAg1szs7kPVMWs>~Z^w62}EOcTeYDQt1v}Jo_MpjZYus(DMCN6R92(#d?v4S^9m_ zkG^f-PjT$H9Q%xJVg)gKqid{#E#*t|p=1ArWi4f&{PiRJ?b=3~&7 zsLTXoJ=Q*$CYLhv;6_i~%CvZGy=52!ctovP5J?=P-HiJ~RUcesj?-iA=<(etv`V*P z#>N);!a0|^{Dwyx(Ws~%GS<>f6m->EgI8f_fN0k;cn{Vxyovhcd-T^lUZ2dI&2ago zf}0o6%B}K`s|r56u^u`2fNvu-chrlA`26vtb?kNE+04P|03*iEk=!Cunbt1O)rjRU zdwpv_s+iZy+r`x%Pty{5_hDTJFmzFKr6@TNPM0RRJocMB=Wy1H>aA3w)!~Qw%H|j+|P`7DyAP7&^=KXZOM_V$Wsz+qYu0M zogFEt)5)G7v?P#LYtHUPQX&vrYrY^q^GYN)Y5WGsO#DV*McjZ1Aje_`e@p5!%#ayW zzN9EYM!fL^b@lp}fo+^Nb+kb6Ynev)izGAo7QzstE34)6Z|e-KlH)Yrp!Cu2qOJRW z^=Flpg>?}aEo6Lve=#Y2S&T&gpyeUneo$9~=kN|nL`KFLO00}X()RT>!QCyIv zWDi*==D!AcIc}d{d`}I&_{WOP75h%ZH zn(1a8$esLku2GA^TjEtN-Btdv#dy$dH@Do(cSvA09w|U2(w{jJOC&7f#qKbdo=%h$L;daMNmbP@lQ_x`dA#U@P4Hq?dikzF^%ad={ z1NuSGEW~R3yW2=^R8v&FMAf^Sr6cj6WU;Bf?>2%)0(V7KvIP;PsvF0dIDyg(lMtv% zNP`KwS$g5Jh??jg^%9PmM(p|Gkurm3di0dBMMTnVUhtJdpe2Kk$*{@eV$3m|{c&{c zIcz7c@SfVzi7bJH7b`ijP$Z|sPrf3`dFrEzEjE4H@}!PuPwmW#u6&HkMzR=pvfa)G z^9c!Og(bzguZ@`6ol#**US(IcMYkzQ^x@OlWf7N8-;}!aQ!}@pEU{F)?hXoF&4k=> z!jN}=E_9v-5wEdkdSfGhEQe^+)7}wHNT92);(4%DLX}f&QB4uW>9z#hZkxSBS|GU`hzsQ z&pp^XY&p7UKAr)v-8flY28?XusY8B^nNy76IZnQiLlfuNEz>@C7Wkd}%FcF0J!@du zY%%euSH-vYd3MAVUndSZe}&K0$u7%*R-#ItT7b6smXGlZ&5xmk_jhMFl+v_4v|Htok%`B*^je8e$uaXqNNRT6CJ1G_P1FZzFzG|Q(o zLusiPnQqJ&7~9Fa7NrC;&J5_Ns#rN&>eUg+9m(Uw)zQqg&_m&OO=wgK_Lr`lUqSwl znA>1BPS)+Ta8_z1};ewM#rr1A#UFCoMFzK&hus7pU+@uX_aE5+Z)e zp*n%&fxBb~T1~czHU1|Hc>m}cz;t&MWqO~~V_Ncr-G(}hc6_G(&FjB8-qCT}WK)YW zAAsy7N-T~V`v2f)|82zoqHq6!%>8B9P64{jkeNO5szPc%vO-p z1dS@IZ`-q*{>0$8g+jsoaNl|Dw;48Sj~}_IjE^4W@4$xf`1d2$$(_FwV@!<3gruC< zR?^0`VYEFGF?HKXEy9y-lJMwJs>Dg*jP6By*{@K~x;;PNN%Ezb9%%CCIyD>Y?nRUH9mR;; zk47e&X%`in+&z5&M%^4O(4DNq3tCb(WOpjRoY0N-1368n!?oWgU6y*KG`ZG;o2~`j zClWsrC)alt`Ed#euI^irP*n zoH5qfV#mO8>FU$rTt&iMnqm?#2p9>KRz?5pq|R60HqB=BxGO)qJaZILsb3XHKl3e> zB?o0>7r$Q($6Biid7TdyUZnA5e9bG}wTp}kc^~u(vR&&}fTeEj+_ZG@!+09sMt236 zh0IwPQxKTd-`4ka2Y`mA>>tR2{D@9J8?> zb)e}^g7g@X!l`IG$@pdRb2o+OLGGhT6W+ds=h&?QZ%+suq69>~Qx`%q)O6M9YQp(A zOK9~@eP@~lCp-pT0oMsxTipS2sEDE59&9Qq&Mn>{vk+-PBBOJ|EC^1GvHUB^b==q` z^)6*W1b58CuZYhL4xb@yCIV0C7##t_7YI*C={`O`ZGI8RaPC}IL`ut#4WLp(t>Wc! zDGcZ^QymtdqEhoO6SBYbzUy6u`JZEhC_+^)WFUe$x+{sYMwm^hB?25d;*{62Avryy zHh1E9hM4K{ybwlkBwe|!NAg1|6#&rrql=8K)Ul#%xghn)6X&p#Pv=r)f*$V0R%%u* z6b8+Jq=O9>EP&0uTK|?brsJhpG!$xG0t!$c$96qmmNSpNzndB#xc>cD-4ckj-ufalJ%AjDZXdF9!@nyM+_iBxpdUf&EV$4BqchR zlDX#!$cvOXuD5R;G;qXj=-elMUu9#rijLA&GEt>r3J0omxO(4{B?#&@HgPhVz7m-{fVUP9pui8wkSDIV^=#W>zs{v>z15xaIN;B+TswZZ8736tbhQ}7e&8B=--tP8 zYsI zk2tG!gb_5FdpnGxF=qzK)EHC|SsXkBG7cDLx*pv^M0CD^1hogPOB!$JeTgOte|G`BG7t8px@pI?!+B8X?9D69NpFzZ zre2v23q&IKQK`&q6AE2HsO{^WaZgbGx19X%$A82N|EKQ!Ps6;XW5~LGC!&AOEJR6A zLqYr)Rh~a6vs=LKT{^siBMa=G0zteaCj$~4EN5eK zzJWvVxG&>C+!d<|EOIKX88qVJ^=j)s$e->qtnAwW(H+J;y6ZelBUn3Df&*McUWk<)R|EuxzC-`m_O)uG z69)fAn^A8<2@rnKz{6j+3Eoc0!;jv4sPK@m?lTh|!o(^a^rTiflj}b=o;DHHbrpswH|YzuwB+RaFD~ShG=3n#e6<*)<`?9Ya7BpL0LVJB;Up-Ks#` zg!Na*O3;V-C@!4e08vQ%-}M-XHT@`f!K6ZkcbS|k=n5GzjTLv=3E`duOOx6sv;Urp z9d~NX3WP$N9;FfA+26lgSGV|ueC1Q&^J*BQrPyvD7ECNyuqUPxfmUm2jG30wlA|{{ zBpf^f0-C?a^@-ZHUpSJ`*~GN4A=p<QNKuvDhi|QQdcxY)Svf&cvM-* zWq5I#tlzwpIk>I4P71I5SdhkC?l8R<_UeGd7gDtI<1F|p_qY}bD|qSF=bJ_pSk}{% z0%drw)k<~>yjda>NPFSd=O0tEUrn4XQ;^1nL&iYzjE+1(vn2y7Kf!gFq6jmRfLxhGv2 z4%|X=(eozg;%K?+<6np5oF1QOT4d>>_6n9>x0oafc=e=q3Y-dXDFJERX&3KG7rCVn zcu?pqBoZg5vmFV>>6TN-l2d{=3eFp?c65Yk5GYlMQb4!noIM_8Q`O;6eGhjQLsi|T z{&a<`bPhZTfUi7dNmiP_y4x&+eKONelY&2zBF$>&D(UU;#sSUKJJ}tSKZl zUFTM<{qzA3^%VZ0jId-kH?~K;l4{r+Ah4KL?7pT;}XA#rL&G+!3jkN!@a{CWNO3bMl%PBhr*rN5z2 zm$G|5rV$6-qTL(K7ji!;x^T^2(wC2C@fns!ODCF-*!(3yE?{@S@okC_o%e&Gt^GTi zOULYvoJX~v4F+NBJnzwftE2#NRHIh)3|Eyf_kjomy>S3nLW#o$#pflOqjRO4`N;0p z{CKArj^)lowh66GP9T9WQ8`w`zKEhm7#$Sa1wK!gSdUV>ESG_(BRzImlgwFgNfShS znCMVY@Hzjw3t&BI@51n@s~U+4+wt>FsuX?g*#p%L`tqZx8pEP{x=|$*nu9$I){Tdz zcCQ9)1A&=s(g$2xOSleE%~sCyn8ao<KUo>vp40NScAJODGJw=*GB^k&0|jgW>` zCLgNJRV)RZBTN5M23~anoV(q`LKfBUu! z{)?-u8-3a|CXRU;m^Esy#%2^f^4*_jm*M+IjZWM(MXOZCDLw6I=zIF&NCxrV#iEPO zhDYT!+_jQ_M|>5UmA{%B9P96(Kt&}%?SQIO(V;xl#H{J7kL_lok|dpJT~Ep%UvP4v zeL;K6=Q7;AOsWSK!^jt*0%i5#s^o~fv@lPmsfuwZj7gg_lBxv)8V{5mk3XooH{;P# z3D@-vg|HIUAauiwQ^K|1c2dl$Ntin{xQ|9aWBNsCm|(ua;64H`{x}cE@&pt}pwDs+kYyOcQTEgw-_vQZ{E= z@V36K7xXLe-jL6;wmb$&p%>*6EZDI&1y_nR=K2oZjA@#&HuWAYu>E=gP2pRcy-wV- z@@N7D9Q*6Oo;xTLZmh99g|J5rGVSeNwA{^KEZy&emxjw&I_fqfV37OMotrn>`+nCQ zsf_rz)dnEQ>NTM#rTxlXkH-fn6nQm@rY;uOeU6 z+g)1b`P0q9;_B!#C4amUN$M!IlRLiDMDY%f1++l6dEyq_*cwdS;x(+aIOVjMz$fnO z8=5wmt`x>xuSpm_9^F^PzfY?O4yj%jscuIQ2(QZCja$N|k!uQ|1d{xr=u|CT9RooR zazdJY$0b)ox=*-;gY|<%Nfm*+3*`LZ0(Wr#FvS2SYw0`Ph6!g{BSpRm`(_uWB=(+| zM3Cm@SZ<)Z<6Z=w#KrW~v!;TT*|`A=svzQ6xa!pioAz9t#v#9gTjmv{Wlr_X^lr`z zNMJv&a-J$YA~;^LH>#nRB3_sbxa<`JNti)cF>tW(10Jkdb?P^2tzOzst(M;8aFlrd zw&K&1o0_yYLNG9L&V*8skp=D#PmavGmQ!x$4y$k6fVo`COR^ckr|1QHvV404~I9e^-%BVk1kaX zH?2w@?RM`1mqbr+#cgjk=IDjS`@@{S+pb?S1d4!{6ek22p;#_t5ywp+wo zV{NHg=2Z^25{o_bnD$(+1}WK=of#@z*Fs~Sp%>R)cJn>;U5obgJlxb^E=AwnYl$CG z-{;4pU>M0tDz3ZtIUjf?Fz8p2t3WE)we|AA$E#bmxI>UDe?7!yI|Y;~!Ti zWz7oED#d}Zk*$;u+)nbmMDy~2cv7}E7U%Hdn>}iKrJ~?A2dg;f78INt!r0Wt^cFw5 z#=}4{n$dBMhe^h7R&F;ffPAU8me;eOu8dK>F_*1%Z-9zQpydIvF>(VP`XNHp7AR`Iy4bQ<#wBtI^AN=-B^RnsjWdQCRpOzzxO7d>2w z>Oi-A%(_og^j=Q!?1{`=U*kmF80nu6q;J(Kg(E(D&CBg9duJmZ6PKLEJh;KSiQb>z z9NrF}1{tt@nBv{A_sr*NXv?n? z!DjYGU2`yKEd`|9C8Tm?d&dd^__mYIR(>_4c{&BF3o0#M`=C{RM-M3?>3vxBy*bq= zf2ialJ`!=tvOKLr0gRFyhK)4MCr)s;yji-@v_Phx)bjYND8)Bc}tC z!dRAd&EGU3kKpd`h_svm}I+3ul{T@%4XRSTKbrjqS7D)tEjkm-y6IS5P+_si3BYVKu&?=6QzxRLY#$pLq)nke!Z@ zMX4L1{i_dCjui^@$*?AKmG}$b59sH+EE(;!WqnI(DyGuKGb^JjwiH8M9S(8aXZ}zs zFkji?r+CM^5;t^}iqY}9zSfI;i)TP?$MId&`IAH;aB-Rv0D$m3h_7m#1VibeKj>Qk+?=b7{d^@iWoO&Boc+W=%YQuEv6V_Rob&gjzgJNeB0xG9l#ub{E z6Q!NvO1SZpDD^f7pmQmt0a`CLZ#6TMpbU#Y6o8EhUb8?N%UrS$21pNXARMJP~;3K(6;;BGk<1x>SXsn&JFeyKQB znw&0|U*C(v_f4o`R-LmvLG02Jauhm&i7t*sh&OXOYRe+*BE7UNx?Nofw?hn zZ9G|7xjea2|Ae~0du$yR!#_i$a%n!wG(A#2U@Z3pWh2M%ZGoho! zWsa}T&Va{SRjsdoBLw<>zr4)nd=LL&tjcn!pz{sYF)0}d{eZ5<16lp)z=3Pf-mQv~ z0|-K9copsVAhLY#%foh`b+BEpTVF;#ZU?$K2%6#tT-6hD={=7q|4dO*8GmM<`4)Qz ze7bt%O%n^GVVOPZDK4&lUZyF}hwq+edHFSbv^>4e)^!*xJtP4 zI)rG!^`X1Hda*>zYr^y!i#1TK z0)2e+vhTL>;?#A*-gCL>ma4^OwuYekQ&2>{-WEr$6?nX3N%&Q%$*hBGHj*3*ve{_8eNwZ}4*O ztS)x8aze9Zi0&(y2SprON-@ntUKw=Jk$H7{>^`W~O7(Og;?R#trS5J3h{5M$*x3Z@ zxM53?t;$^?<7sBYMSc8`_Chz}TGMRIyaz}1!Q%c#>UIv{rMD(tPgJ5OsmPJu$xrvC z?mifnU73xn+eKZ4yh&75n+!XLA)WXes(0F^xDApW;5!&C$k-w?&5OLr9@qR%ia$K)yMb4b@`T3gU4din<`FUUH z?0AHjpVuTQW*X?s4zmk@yJjJobWu7S8Of(9dJbLd4zlhaxh+pfhB6e_ASd5!qVWo5 zc-INC4;nPO#JpD+@tnIs?v`D)X$qY~&#y9S;lAA$*Q8wEl9810@WXOHOB)jzXOsT1 zUop8;TAwBQtNuh7HDU%FAmmCm$S%y|dF&syd7ig!4)BrMhADxkgdKc~e!1R9U-S8C z3eMepv*0P8=KoOFs7aXefP9l&mG0>6K790LOK|Vp4kRexHb6HsG4p;rJbpuI9b0!U zG&CPE8nJ+DqJPEpu*=o}o7`Bgt)_Kg1aE7-0wD}UO{QV?)sKFf#aY^UPwm&`Mp=M|kiGV((ZQeuoafiC6$;&st+!N{MrW&<2Rd28_;N$fM z;%3|mWNUi=b^8U>W~H!5^z`9D>A{)zNjnWws^8s3iBX&1e4V|=3=M7j`c8-;>9J-Z zmRW)m(d(zEsK#hFe96qDQVr*2E8i}V4-+9@P#TI~mpgjj%tq5;SrRU5Y&?=>;!jgT z`M#8)PjJGY{8bsTYJN5uZQyo-XX~()Sr(c#($-n ze6qhN6VMWdW%i-um1(o|I4^uf1O8oh@mJNuZdVAtfPlbb)k7A8-*Gq5Uv12|FSJ<_ zFfd*;FT$M{qN$~n2Odi-GVagvM?@cP`{^@MzkiXIlS|>XpQ|+MeQXxZEP0ZrFL--B z-R8Gbm_If))^pD&IbK7iJKPcY+~aV`KwI0oejYKB;mA&`e1=kAs?G9wwJYS~+oLN) zhUoc(T9nX9-z(qSpr-*)Z!mb-3z4SGFflt@$nY}qNxOa6T0?3od06+!daTlt^75a} ozltXC8dP5Xe`qBQ0}s!?O^weA3ei4RSfHTDNGJl!#Eb*}7wgG*f&c&j literal 0 HcmV?d00001 diff --git a/Images/Saved.png b/Images/Saved.png new file mode 100644 index 0000000000000000000000000000000000000000..a4c89cb9d7076c3e3c9a8e06ba0bd14673eaf9b5 GIT binary patch literal 2478 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 Fe*ystmM8!K literal 0 HcmV?d00001 diff --git a/changelog.md b/changelog.md new file mode 100644 index 0000000..538c250 --- /dev/null +++ b/changelog.md @@ -0,0 +1,33 @@ +# ESP32_ENC_Manager Library + +[![arduino-library-badge](https://www.ardu-badge.com/badge/ESP32_ENC_Manager.svg?)](https://www.ardu-badge.com/ESP32_ENC_Manager) +[![GitHub release](https://img.shields.io/github/release/khoih-prog/ESP32_ENC_Manager.svg)](https://github.com/khoih-prog/ESP32_ENC_Manager/releases) +[![GitHub](https://img.shields.io/github/license/mashape/apistatus.svg)](https://github.com/khoih-prog/ESP32_ENC_Manager/blob/main/LICENSE) +[![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](#Contributing) +[![GitHub issues](https://img.shields.io/github/issues/khoih-prog/ESP32_ENC_Manager.svg)](http://github.com/khoih-prog/ESP32_ENC_Manager/issues) + +Donate to my libraries using BuyMeACoffee + + + +--- +--- + +## Table of contents + +* [Changelog](#changelog) + * [Releases v1.0.0](#releases-v100) + + + +--- +--- + +## Changelog + +#### Releases v1.0.0 + +1. Initial coding to port [ESP_WiFiManager](https://github.com/khoih-prog/ESP_WiFiManager) to ESP32 boards using `LwIP ENC28J60 Ethernet`. +2. Use `allman astyle` + + diff --git a/examples/ConfigOnDoubleReset/ConfigOnDoubleReset.ino b/examples/ConfigOnDoubleReset/ConfigOnDoubleReset.ino new file mode 100644 index 0000000..d09bc32 --- /dev/null +++ b/examples/ConfigOnDoubleReset/ConfigOnDoubleReset.ino @@ -0,0 +1,724 @@ +/**************************************************************************************************************************** + ConfigOnDoubleReset.ino + For Ethernet shields using ESP32_ENC (ESP32 + LwIP ENC28J60) + + WebServer_ESP32_ENC is a library for the ESP32 with Ethernet ENC28J60 to run WebServer + + Modified from + 1. Tzapu (https://github.com/tzapu/WiFiManager) + 2. Ken Taylor (https://github.com/kentaylor) + 3. Khoi Hoang (https://github.com/khoih-prog/ESP_WiFiManager) + + Built by Khoi Hoang https://github.com/khoih-prog/ESP32_ENC_Manager + Licensed under MIT license + *****************************************************************************************************************************/ +/**************************************************************************************************************************** + This example will open a configuration portal when the reset button is pressed twice. + This method works well on Wemos boards which have a single reset button on board. It avoids using a pin for launching the configuration portal. + + Settings + There are two values to be set in the sketch. + + DRD_TIMEOUT - Number of seconds to wait for the second reset. Set to 10 in the example. + DRD_ADDRESS - The address in ESP8266 RTC RAM to store the flag. This memory must not be used for other purposes in the same sketch. Set to 0 in the example. + + This example, originally relied on the Double Reset Detector library from https://github.com/datacute/DoubleResetDetector + To support ESP32, use ESP_DoubleResetDetector library from //https://github.com/khoih-prog/ESP_DoubleResetDetector + *****************************************************************************************************************************/ + +#if !( defined(ESP32) ) + #error This code is intended to run on the (ESP32 + LwIP W5500) platform! Please check your Tools->Board setting. +#endif + +// Use from 0 to 4. Higher number, more debugging messages and memory usage. +#define _ESP32_ETH_MGR_LOGLEVEL_ 4 + +// To not display stored SSIDs and PWDs on Config Portal, select false. Default is true +// Even the stored Credentials are not display, just leave them all blank to reconnect and reuse the stored Credentials +//#define DISPLAY_STORED_CREDENTIALS_IN_CP false + +////////////////////////////////////////////////////////////// + +// Enter a MAC address and IP address for your controller below. +#define NUMBER_OF_MAC 20 + +byte mac[][NUMBER_OF_MAC] = +{ + { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x01 }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xBE, 0x02 }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x03 }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xBE, 0x04 }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x05 }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xBE, 0x06 }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x07 }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xBE, 0x08 }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x09 }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xBE, 0x0A }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x0B }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xBE, 0x0C }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x0D }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xBE, 0x0E }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x0F }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xBE, 0x10 }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x11 }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xBE, 0x12 }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x13 }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xBE, 0x14 }, +}; + +////////////////////////////////////////////////////////// + +// Optional values to override default settings +// Don't change unless you know what you're doing +// Optional values to override default settings +//#define SPI_HOST 1 +//#define SPI_CLOCK_MHZ 8 + +// Must connect INT to GPIOxx or not working +//#define INT_GPIO 4 + +//#define MISO_GPIO 19 +//#define MOSI_GPIO 23 +//#define SCK_GPIO 18 +//#define CS_GPIO 5 + +////////////////////////////////////////////////////////// + +#include + +//Ported to ESP32 +#include + +// LittleFS has higher priority than SPIFFS +#if ( defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 2) ) + #define USE_LITTLEFS true + #define USE_SPIFFS false +#elif defined(ARDUINO_ESP32C3_DEV) + // For core v1.0.6-, ESP32-C3 only supporting SPIFFS and EEPROM. To use v2.0.0+ for LittleFS + #define USE_LITTLEFS false + #define USE_SPIFFS true +#endif + +#if USE_LITTLEFS + // Use LittleFS + #include "FS.h" + + // Check cores/esp32/esp_arduino_version.h and cores/esp32/core_version.h + //#if ( ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(2, 0, 0) ) //(ESP_ARDUINO_VERSION_MAJOR >= 2) + #if ( defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 2) ) + #if (_ESP32_ETH_MGR_LOGLEVEL_ > 3) + #warning Using ESP32 Core 1.0.6 or 2.0.0+ + #endif + + // The library has been merged into esp32 core from release 1.0.6 + #include // https://github.com/espressif/arduino-esp32/tree/master/libraries/LittleFS + + FS* filesystem = &LittleFS; + #define FileFS LittleFS + #define FS_Name "LittleFS" + #else + #if (_ESP32_ETH_MGR_LOGLEVEL_ > 3) + #warning Using ESP32 Core 1.0.5-. You must install LITTLEFS library + #endif + + // The library has been merged into esp32 core from release 1.0.6 + #include // https://github.com/lorol/LITTLEFS + + FS* filesystem = &LITTLEFS; + #define FileFS LITTLEFS + #define FS_Name "LittleFS" + #endif + +#elif USE_SPIFFS + #include + FS* filesystem = &SPIFFS; + #define FileFS SPIFFS + #define FS_Name "SPIFFS" +#else + // +Use FFat + #include + FS* filesystem = &FFat; + #define FileFS FFat + #define FS_Name "FFat" +#endif +////// + +#define LED_BUILTIN 2 +#define LED_ON HIGH +#define LED_OFF LOW + +// These defines must be put before #include +// to select where to store DoubleResetDetector's variable. +// For ESP32, You must select one to be true (EEPROM or SPIFFS) +// Otherwise, library will use default EEPROM storage + +// These defines must be put before #include +// to select where to store DoubleResetDetector's variable. +// For ESP32, You must select one to be true (EEPROM or SPIFFS) +// Otherwise, library will use default EEPROM storage +#if USE_LITTLEFS + #define ESP_DRD_USE_LITTLEFS true + #define ESP_DRD_USE_SPIFFS false + #define ESP_DRD_USE_EEPROM false +#elif USE_SPIFFS + #define ESP_DRD_USE_LITTLEFS false + #define ESP_DRD_USE_SPIFFS true + #define ESP_DRD_USE_EEPROM false +#else + #define ESP_DRD_USE_LITTLEFS false + #define ESP_DRD_USE_SPIFFS false + #define ESP_DRD_USE_EEPROM true +#endif + +#define DOUBLERESETDETECTOR_DEBUG true //false + +#include //https://github.com/khoih-prog/ESP_DoubleResetDetector + +// Number of seconds after reset during which a +// subseqent reset will be considered a double reset. +#define DRD_TIMEOUT 10 + +// RTC Memory Address for the DoubleResetDetector to use +#define DRD_ADDRESS 0 + +//DoubleResetDetector drd(DRD_TIMEOUT, DRD_ADDRESS); +DoubleResetDetector* drd;////// + +// Onboard LED I/O pin on NodeMCU board +const int PIN_LED = 2; // D4 on NodeMCU and WeMos. GPIO2/ADC12 of ESP32. Controls the onboard LED. + +// You only need to format the filesystem once +//#define FORMAT_FILESYSTEM true +#define FORMAT_FILESYSTEM false + +// Assuming max 49 chars +#define TZNAME_MAX_LEN 50 +#define TIMEZONE_MAX_LEN 50 + +typedef struct +{ + char TZ_Name[TZNAME_MAX_LEN]; // "America/Toronto" + char TZ[TIMEZONE_MAX_LEN]; // "EST5EDT,M3.2.0,M11.1.0" + uint16_t checksum; +} EthConfig; + +EthConfig Ethconfig; + +#define CONFIG_FILENAME F("/eth_cred.dat") +////// + +// Indicates whether ESP has credentials saved from previous session, or double reset detected +bool initialConfig = false; + +// Use false if you don't like to display Available Pages in Information Page of Config Portal +// Comment out or use true to display Available Pages in Information Page of Config Portal +// Must be placed before #include +#define USE_AVAILABLE_PAGES true //false + +// To permit disable/enable StaticIP configuration in Config Portal from sketch. Valid only if DHCP is used. +// You'll loose the feature of dynamically changing from DHCP to static IP, or vice versa +// You have to explicitly specify false to disable the feature. +//#define USE_STATIC_IP_CONFIG_IN_CP false + +// Use false to disable NTP config. Advisable when using Cellphone, Tablet to access Config Portal. +// See Issue 23: On Android phone ConfigPortal is unresponsive (https://github.com/khoih-prog/ESP_WiFiManager/issues/23) +#define USE_ESP_ETH_MANAGER_NTP true //false + +// Just use enough to save memory. On ESP8266, can cause blank ConfigPortal screen +// if using too much memory +#define USING_AFRICA false +#define USING_AMERICA true +#define USING_ANTARCTICA false +#define USING_ASIA false +#define USING_ATLANTIC false +#define USING_AUSTRALIA false +#define USING_EUROPE false +#define USING_INDIAN false +#define USING_PACIFIC false +#define USING_ETC_GMT false + +// Use true to enable CloudFlare NTP service. System can hang if you don't have Internet access while accessing CloudFlare +// See Issue #21: CloudFlare link in the default portal (https://github.com/khoih-prog/ESP_WiFiManager/issues/21) +#define USE_CLOUDFLARE_NTP false + +#define USING_CORS_FEATURE true + +//////////////////////////////////////////// + +// Use USE_DHCP_IP == true for dynamic DHCP IP, false to use static IP which you have to change accordingly to your network +#if (defined(USE_STATIC_IP_CONFIG_IN_CP) && !USE_STATIC_IP_CONFIG_IN_CP) + // Force DHCP to be true + #if defined(USE_DHCP_IP) + #undef USE_DHCP_IP + #endif + #define USE_DHCP_IP true +#else + // You can select DHCP or Static IP here + //#define USE_DHCP_IP true + #define USE_DHCP_IP false +#endif + +#if ( USE_DHCP_IP ) + // Use DHCP + + #if (_ESP32_ETH_MGR_LOGLEVEL_ > 3) + #warning Using DHCP IP + #endif + + IPAddress stationIP = IPAddress(0, 0, 0, 0); + IPAddress gatewayIP = IPAddress(192, 168, 2, 1); + IPAddress netMask = IPAddress(255, 255, 255, 0); + +#else + // Use static IP + + #if (_ESP32_ETH_MGR_LOGLEVEL_ > 3) + #warning Using static IP + #endif + + IPAddress stationIP = IPAddress(192, 168, 2, 232); + IPAddress gatewayIP = IPAddress(192, 168, 2, 1); + IPAddress netMask = IPAddress(255, 255, 255, 0); +#endif + +//////////////////////////////////////////// + + +#define USE_CONFIGURABLE_DNS true + +IPAddress dns1IP = gatewayIP; +IPAddress dns2IP = IPAddress(8, 8, 8, 8); + +#include //https://github.com/khoih-prog/ESP32_ENC_Manager + +#define HTTP_PORT 80 + +/////////////////////////////////////////// +/****************************************** + // Defined in ESP32_ENC_Manager.hpp + typedef struct + { + IPAddress _sta_static_ip; + IPAddress _sta_static_gw; + IPAddress _sta_static_sn; + #if USE_CONFIGURABLE_DNS + IPAddress _sta_static_dns1; + IPAddress _sta_static_dns2; + #endif + } ETH_STA_IPConfig; +******************************************/ + +ETH_STA_IPConfig EthSTA_IPconfig; + +void initSTAIPConfigStruct(ETH_STA_IPConfig &in_EthSTA_IPconfig) +{ + in_EthSTA_IPconfig._sta_static_ip = stationIP; + in_EthSTA_IPconfig._sta_static_gw = gatewayIP; + in_EthSTA_IPconfig._sta_static_sn = netMask; +#if USE_CONFIGURABLE_DNS + in_EthSTA_IPconfig._sta_static_dns1 = dns1IP; + in_EthSTA_IPconfig._sta_static_dns2 = dns2IP; +#endif +} + +void displayIPConfigStruct(ETH_STA_IPConfig in_EthSTA_IPconfig) +{ + LOGERROR3(F("stationIP ="), in_EthSTA_IPconfig._sta_static_ip, ", gatewayIP =", in_EthSTA_IPconfig._sta_static_gw); + LOGERROR1(F("netMask ="), in_EthSTA_IPconfig._sta_static_sn); +#if USE_CONFIGURABLE_DNS + LOGERROR3(F("dns1IP ="), in_EthSTA_IPconfig._sta_static_dns1, ", dns2IP =", in_EthSTA_IPconfig._sta_static_dns2); +#endif +} + +#if USE_ESP_ETH_MANAGER_NTP + +void printLocalTime() +{ + struct tm timeinfo; + + getLocalTime( &timeinfo ); + + // Valid only if year > 2000. + // You can get from timeinfo : tm_year, tm_mon, tm_mday, tm_hour, tm_min, tm_sec + if (timeinfo.tm_year > 100 ) + { + Serial.print("Local Date/Time: "); + Serial.print( asctime( &timeinfo ) ); + } +} + +#endif + +void heartBeatPrint() +{ +#if USE_ESP_ETH_MANAGER_NTP + printLocalTime(); +#else + static int num = 1; + + if (ESP32_ENC_isConnected()) + Serial.print(F("H")); // H means connected to Ethernet + else + Serial.print(F("F")); // F means not connected to Ethernet + + if (num == 80) + { + Serial.println(); + num = 1; + } + else if (num++ % 10 == 0) + { + Serial.print(F(" ")); + } + +#endif +} + +void check_status() +{ + static ulong checkstatus_timeout = 0; + + static ulong current_millis; + +#if USE_ESP_ETH_MANAGER_NTP +#define HEARTBEAT_INTERVAL 60000L +#else +#define HEARTBEAT_INTERVAL 10000L +#endif + + current_millis = millis(); + + // Print hearbeat every HEARTBEAT_INTERVAL (10) seconds. + if ((current_millis > checkstatus_timeout) || (checkstatus_timeout == 0)) + { + heartBeatPrint(); + checkstatus_timeout = current_millis + HEARTBEAT_INTERVAL; + } +} + +int calcChecksum(uint8_t* address, uint16_t sizeToCalc) +{ + uint16_t checkSum = 0; + + for (uint16_t index = 0; index < sizeToCalc; index++) + { + checkSum += * ( ( (byte*) address ) + index); + } + + return checkSum; +} + +bool loadConfigData() +{ + File file = FileFS.open(CONFIG_FILENAME, "r"); + LOGERROR(F("LoadCfgFile ")); + + memset((void *) &Ethconfig, 0, sizeof(Ethconfig)); + memset((void *) &EthSTA_IPconfig, 0, sizeof(EthSTA_IPconfig)); + + if (file) + { + file.readBytes((char *) &Ethconfig, sizeof(Ethconfig)); + file.readBytes((char *) &EthSTA_IPconfig, sizeof(EthSTA_IPconfig)); + file.close(); + + LOGERROR(F("OK")); + + if ( Ethconfig.checksum != calcChecksum( (uint8_t*) &Ethconfig, sizeof(Ethconfig) - sizeof(Ethconfig.checksum) ) ) + { + LOGERROR(F("Ethconfig checksum wrong")); + + return false; + } + + displayIPConfigStruct(EthSTA_IPconfig); + + return true; + } + else + { + LOGERROR(F("failed")); + + return false; + } +} + +void saveConfigData() +{ + File file = FileFS.open(CONFIG_FILENAME, "w"); + LOGERROR(F("SaveCfgFile ")); + + if (file) + { + Ethconfig.checksum = calcChecksum( (uint8_t*) &Ethconfig, sizeof(Ethconfig) - sizeof(Ethconfig.checksum) ); + + file.write((uint8_t*) &Ethconfig, sizeof(Ethconfig)); + + displayIPConfigStruct(EthSTA_IPconfig); + + file.write((uint8_t*) &EthSTA_IPconfig, sizeof(EthSTA_IPconfig)); + file.close(); + + LOGERROR(F("OK")); + } + else + { + LOGERROR(F("failed")); + } +} + +void beginEthernet() +{ + LOGWARN(F("Default SPI pinout:")); + LOGWARN1(F("MOSI:"), MOSI_GPIO); + LOGWARN1(F("MISO:"), MISO_GPIO); + LOGWARN1(F("SCK:"), SCK_GPIO); + LOGWARN1(F("CS:"), CS_GPIO); + LOGWARN1(F("INT:"), INT_GPIO); + LOGWARN1(F("SPI Clock (MHz):"), SPI_CLOCK_MHZ); + LOGWARN(F("=========================")); + + /////////////////////////////////// + + // To be called before ETH.begin() + ESP32_ENC_onEvent(); + + // start the ethernet connection and the server: + // Use DHCP dynamic IP and random mac + uint16_t index = millis() % NUMBER_OF_MAC; + + //bool begin(int MISO_GPIO, int MOSI_GPIO, int SCLK_GPIO, int CS_GPIO, int INT_GPIO, int SPI_CLOCK_MHZ, + // int SPI_HOST, uint8_t *ENC28J60_Mac = ENC28J60_Default_Mac); + //ETH.begin( MISO_GPIO, MOSI_GPIO, SCK_GPIO, CS_GPIO, INT_GPIO, SPI_CLOCK_MHZ, SPI_HOST ); + ETH.begin( MISO_GPIO, MOSI_GPIO, SCK_GPIO, CS_GPIO, INT_GPIO, SPI_CLOCK_MHZ, SPI_HOST, mac[index] ); +} + +////////////////////////////////////////////////////////////// + +void initEthernet() +{ +#if !( USE_DHCP_IP ) + displayIPConfigStruct(EthSTA_IPconfig); + + // Static IP, leave without this line to get IP via DHCP + //bool config(IPAddress local_ip, IPAddress gateway, IPAddress subnet, IPAddress dns1 = 0, IPAddress dns2 = 0); + //ETH.config(stationIP, gatewayIP, netMask, dns1IP, dns2IP); + ETH.config(EthSTA_IPconfig._sta_static_ip, EthSTA_IPconfig._sta_static_gw, EthSTA_IPconfig._sta_static_sn, + EthSTA_IPconfig._sta_static_dns1); +#endif + + ESP32_ENC_waitForConnect(); +} + +void setup() +{ + // put your setup code here, to run once: + // initialize the LED digital pin as an output. + pinMode(PIN_LED, OUTPUT); + + Serial.begin(115200); + + while (!Serial && millis() < 5000); + + delay(200); + + Serial.print(F("\nStarting ConfigOnDoubleReset using ")); + Serial.print(FS_Name); + Serial.print(F(" on ")); + Serial.print(ARDUINO_BOARD); + Serial.print(F(" with ")); + Serial.println(SHIELD_TYPE); + Serial.println(ESP32_ENC_MANAGER_VERSION); + Serial.println(ESP_DOUBLE_RESET_DETECTOR_VERSION); + + Serial.setDebugOutput(false); + + if (FORMAT_FILESYSTEM) + FileFS.format(); + + // Format FileFS if not yet + if (!FileFS.begin(true)) + { + Serial.println(F("SPIFFS/LittleFS failed! Already tried formatting.")); + + if (!FileFS.begin()) + { + // prevents debug info from the library to hide err message. + delay(100); + +#if USE_LITTLEFS + Serial.println(F("LittleFS failed!. Please use SPIFFS or EEPROM. Stay forever")); +#else + Serial.println(F("SPIFFS failed!. Please use LittleFS or EEPROM. Stay forever")); +#endif + + while (true) + { + delay(1); + } + } + } + + drd = new DoubleResetDetector(DRD_TIMEOUT, DRD_ADDRESS); + + unsigned long startedAt = millis(); + + beginEthernet(); + + initSTAIPConfigStruct(EthSTA_IPconfig); + + //Local intialization. Once its business is done, there is no need to keep it around + // Use this to default DHCP hostname to ESP32-XXXXXX + //ESP32_ENC_Manager ESP32_ENC_manager; + // Use this to personalize DHCP hostname (RFC952 conformed) + ESP32_ENC_Manager ESP32_ENC_manager("ConfigOnDoubleReset"); + +#if !USE_DHCP_IP + // Set (static IP, Gateway, Subnetmask, DNS1 and DNS2) or (IP, Gateway, Subnetmask) + ESP32_ENC_manager.setSTAStaticIPConfig(EthSTA_IPconfig); +#endif + +#if USING_CORS_FEATURE + ESP32_ENC_manager.setCORSHeader("Your Access-Control-Allow-Origin"); +#endif + + bool configDataLoaded = false; + + if (loadConfigData()) + { + configDataLoaded = true; + + //If no access point name has been previously entered disable timeout. + ESP32_ENC_manager.setConfigPortalTimeout(120); + + Serial.println(F("Got stored Credentials. Timeout 120s for Config Portal")); + +#if USE_ESP_ETH_MANAGER_NTP + + if ( strlen(Ethconfig.TZ_Name) > 0 ) + { + LOGERROR3(F("Current TZ_Name ="), Ethconfig.TZ_Name, F(", TZ = "), Ethconfig.TZ); + + //configTzTime(Ethconfig.TZ, "pool.ntp.org" ); + configTzTime(Ethconfig.TZ, "time.nist.gov", "0.pool.ntp.org", "1.pool.ntp.org"); + } + else + { + Serial.println(F("Current Timezone is not set. Enter Config Portal to set.")); + } + +#endif + } + + ////////////////////////////////// + + // Connect ETH now if using STA + initEthernet(); + + ////////////////////////////////// + + if (drd->detectDoubleReset()) + { + // DRD, disable timeout. + ESP32_ENC_manager.setConfigPortalTimeout(0); + + Serial.println(F("Open Config Portal without Timeout: Double Reset Detected")); + initialConfig = true; + } + + if (initialConfig) + { + Serial.print(F("Starting configuration portal @ ")); + Serial.println(ETH.localIP()); + + digitalWrite(PIN_LED, LED_ON); // turn the LED on by making the voltage LOW to tell us we are in configuration mode. + + //sets timeout in seconds until configuration portal gets turned off. + //If not specified device will remain in configuration mode until + //switched off via webserver or device is restarted. + //ESP32_ENC_manager.setConfigPortalTimeout(600); + + // Starts an access point + if (!ESP32_ENC_manager.startConfigPortal()) + Serial.println(F("Not connected to ETH network but continuing anyway.")); + else + { + Serial.println(F("ETH network connected...yeey :)")); + } + +#if USE_ESP_ETH_MANAGER_NTP + String tempTZ = ESP32_ENC_manager.getTimezoneName(); + + if (strlen(tempTZ.c_str()) < sizeof(Ethconfig.TZ_Name) - 1) + strcpy(Ethconfig.TZ_Name, tempTZ.c_str()); + else + strncpy(Ethconfig.TZ_Name, tempTZ.c_str(), sizeof(Ethconfig.TZ_Name) - 1); + + const char * TZ_Result = ESP32_ENC_manager.getTZ(Ethconfig.TZ_Name); + + if (strlen(TZ_Result) < sizeof(Ethconfig.TZ) - 1) + strcpy(Ethconfig.TZ, TZ_Result); + else + strncpy(Ethconfig.TZ, TZ_Result, sizeof(Ethconfig.TZ_Name) - 1); + + if ( strlen(Ethconfig.TZ_Name) > 0 ) + { + LOGERROR3(F("Saving current TZ_Name ="), Ethconfig.TZ_Name, F(", TZ = "), Ethconfig.TZ); + + //configTzTime(Ethconfig.TZ, "pool.ntp.org" ); + configTzTime(Ethconfig.TZ, "time.nist.gov", "0.pool.ntp.org", "1.pool.ntp.org"); + } + else + { + LOGERROR(F("Current Timezone Name is not set. Enter Config Portal to set.")); + } + +#endif + + ESP32_ENC_manager.getSTAStaticIPConfig(EthSTA_IPconfig); + + saveConfigData(); + +#if !USE_DHCP_IP + + // Reset to use new Static IP, if different from current ETH.localIP() + if (ETH.localIP() != EthSTA_IPconfig._sta_static_ip) + { + Serial.print(F("Current IP = ")); + Serial.print(ETH.localIP()); + Serial.print(F(". Reset to take new IP = ")); + Serial.println(EthSTA_IPconfig._sta_static_ip); + + ESP.restart(); + delay(2000); + } + +#endif + } + + digitalWrite(PIN_LED, LED_OFF); // Turn led off as we are not in configuration mode. + + startedAt = millis(); + + Serial.print(F("After waiting ")); + Serial.print((float) (millis() - startedAt) / 1000); + Serial.print(F(" secs more in setup(), connection result is ")); + + if (ESP32_ENC_isConnected()) + { + Serial.print(F("connected. Local IP: ")); + Serial.println(ETH.localIP()); + } +} + +void loop() +{ + // Call the double reset detector loop method every so often, + // so that it can recognise when the timeout expires. + // You can also call drd.stop() when you wish to no longer + // consider the next reset as a double reset. + drd->loop(); + + // put your main code here, to run repeatedly + check_status(); +} diff --git a/examples/ConfigOnDoubleReset_TZ/ConfigOnDoubleReset_TZ.ino b/examples/ConfigOnDoubleReset_TZ/ConfigOnDoubleReset_TZ.ino new file mode 100644 index 0000000..8e3afbe --- /dev/null +++ b/examples/ConfigOnDoubleReset_TZ/ConfigOnDoubleReset_TZ.ino @@ -0,0 +1,751 @@ +/**************************************************************************************************************************** + ConfigOnDoubleReset_TZ.ino + For Ethernet shields using ESP32_ENC (ESP32 + LwIP ENC28J60) + + WebServer_ESP32_ENC is a library for the ESP32 with Ethernet ENC28J60 to run WebServer + + Modified from + 1. Tzapu (https://github.com/tzapu/WiFiManager) + 2. Ken Taylor (https://github.com/kentaylor) + 3. Khoi Hoang (https://github.com/khoih-prog/ESP_WiFiManager) + + Built by Khoi Hoang https://github.com/khoih-prog/ESP32_ENC_Manager + Licensed under MIT license + *****************************************************************************************************************************/ +/**************************************************************************************************************************** + This example will open a configuration portal when the reset button is pressed twice. + This method works well on Wemos boards which have a single reset button on board. It avoids using a pin for launching the configuration portal. + + Settings + There are two values to be set in the sketch. + + DRD_TIMEOUT - Number of seconds to wait for the second reset. Set to 10 in the example. + DRD_ADDRESS - The address in ESP8266 RTC RAM to store the flag. This memory must not be used for other purposes in the same sketch. Set to 0 in the example. + + This example, originally relied on the Double Reset Detector library from https://github.com/datacute/DoubleResetDetector + To support ESP32, use ESP_DoubleResetDetector library from //https://github.com/khoih-prog/ESP_DoubleResetDetector + *****************************************************************************************************************************/ + +#if !( defined(ESP32) ) + #error This code is intended to run on the (ESP32 + LwIP W5500) platform! Please check your Tools->Board setting. +#endif + +// Use from 0 to 4. Higher number, more debugging messages and memory usage. +#define _ESP32_ETH_MGR_LOGLEVEL_ 4 + +// To not display stored SSIDs and PWDs on Config Portal, select false. Default is true +// Even the stored Credentials are not display, just leave them all blank to reconnect and reuse the stored Credentials +//#define DISPLAY_STORED_CREDENTIALS_IN_CP false + +////////////////////////////////////////////////////////////// + +// Enter a MAC address and IP address for your controller below. +#define NUMBER_OF_MAC 20 + +byte mac[][NUMBER_OF_MAC] = +{ + { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x01 }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xBE, 0x02 }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x03 }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xBE, 0x04 }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x05 }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xBE, 0x06 }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x07 }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xBE, 0x08 }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x09 }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xBE, 0x0A }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x0B }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xBE, 0x0C }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x0D }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xBE, 0x0E }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x0F }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xBE, 0x10 }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x11 }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xBE, 0x12 }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x13 }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xBE, 0x14 }, +}; + +////////////////////////////////////////////////////////// + +// Optional values to override default settings +// Don't change unless you know what you're doing +// Optional values to override default settings +//#define SPI_HOST 1 +//#define SPI_CLOCK_MHZ 8 + +// Must connect INT to GPIOxx or not working +//#define INT_GPIO 4 + +//#define MISO_GPIO 19 +//#define MOSI_GPIO 23 +//#define SCK_GPIO 18 +//#define CS_GPIO 5 + +////////////////////////////////////////////////////////// + +#include + +//Ported to ESP32 +#include + +// LittleFS has higher priority than SPIFFS +#if ( defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 2) ) + #define USE_LITTLEFS true + #define USE_SPIFFS false +#elif defined(ARDUINO_ESP32C3_DEV) + // For core v1.0.6-, ESP32-C3 only supporting SPIFFS and EEPROM. To use v2.0.0+ for LittleFS + #define USE_LITTLEFS false + #define USE_SPIFFS true +#endif + +#if USE_LITTLEFS + // Use LittleFS + #include "FS.h" + + // Check cores/esp32/esp_arduino_version.h and cores/esp32/core_version.h + //#if ( ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(2, 0, 0) ) //(ESP_ARDUINO_VERSION_MAJOR >= 2) + #if ( defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 2) ) + #if (_ESP32_ETH_MGR_LOGLEVEL_ > 3) + #warning Using ESP32 Core 1.0.6 or 2.0.0+ + #endif + + // The library has been merged into esp32 core from release 1.0.6 + #include // https://github.com/espressif/arduino-esp32/tree/master/libraries/LittleFS + + FS* filesystem = &LittleFS; + #define FileFS LittleFS + #define FS_Name "LittleFS" + #else + #if (_ESP32_ETH_MGR_LOGLEVEL_ > 3) + #warning Using ESP32 Core 1.0.5-. You must install LITTLEFS library + #endif + + // The library has been merged into esp32 core from release 1.0.6 + #include // https://github.com/lorol/LITTLEFS + + FS* filesystem = &LITTLEFS; + #define FileFS LITTLEFS + #define FS_Name "LittleFS" + #endif + +#elif USE_SPIFFS + #include + FS* filesystem = &SPIFFS; + #define FileFS SPIFFS + #define FS_Name "SPIFFS" +#else + // +Use FFat + #include + FS* filesystem = &FFat; + #define FileFS FFat + #define FS_Name "FFat" +#endif + +////////////////////////////////////////////////////////////// + +#define LED_BUILTIN 2 +#define LED_ON HIGH +#define LED_OFF LOW + +////////////////////////////////////////////////////////////// + +// These defines must be put before #include +// to select where to store DoubleResetDetector's variable. +// For ESP32, You must select one to be true (EEPROM or SPIFFS) +// For ESP8266, You must select one to be true (RTC, EEPROM, SPIFFS or LITTLEFS) +// Otherwise, library will use default EEPROM storage + +// These defines must be put before #include +// to select where to store DoubleResetDetector's variable. +// For ESP32, You must select one to be true (EEPROM or SPIFFS) +// Otherwise, library will use default EEPROM storage +#if USE_LITTLEFS + #define ESP_DRD_USE_LITTLEFS true + #define ESP_DRD_USE_SPIFFS false + #define ESP_DRD_USE_EEPROM false +#elif USE_SPIFFS + #define ESP_DRD_USE_LITTLEFS false + #define ESP_DRD_USE_SPIFFS true + #define ESP_DRD_USE_EEPROM false +#else + #define ESP_DRD_USE_LITTLEFS false + #define ESP_DRD_USE_SPIFFS false + #define ESP_DRD_USE_EEPROM true +#endif + +#define DOUBLERESETDETECTOR_DEBUG true //false + +#include //https://github.com/khoih-prog/ESP_DoubleResetDetector + +// Number of seconds after reset during which a +// subseqent reset will be considered a double reset. +#define DRD_TIMEOUT 10 + +// RTC Memory Address for the DoubleResetDetector to use +#define DRD_ADDRESS 0 + +//DoubleResetDetector drd(DRD_TIMEOUT, DRD_ADDRESS); +DoubleResetDetector* drd;////// + +// Onboard LED I/O pin on NodeMCU board +const int PIN_LED = 2; // D4 on NodeMCU and WeMos. GPIO2/ADC12 of ESP32. Controls the onboard LED. + +// You only need to format the filesystem once +//#define FORMAT_FILESYSTEM true +#define FORMAT_FILESYSTEM false + +////////////////////////////////////////////////////////////// + +// Assuming max 49 chars +#define TZNAME_MAX_LEN 50 +#define TIMEZONE_MAX_LEN 50 + +typedef struct +{ + char TZ_Name[TZNAME_MAX_LEN]; // "America/Toronto" + char TZ[TIMEZONE_MAX_LEN]; // "EST5EDT,M3.2.0,M11.1.0" + uint16_t checksum; +} EthConfig; + +EthConfig Ethconfig; + +#define CONFIG_FILENAME F("/eth_cred.dat") + +////////////////////////////////////////////////////////////// + +// Indicates whether ESP has credentials saved from previous session, or double reset detected +bool initialConfig = false; + +// Use false if you don't like to display Available Pages in Information Page of Config Portal +// Comment out or use true to display Available Pages in Information Page of Config Portal +// Must be placed before #include +#define USE_AVAILABLE_PAGES true //false + +// From v1.0.10 to permit disable/enable StaticIP configuration in Config Portal from sketch. Valid only if DHCP is used. +// You'll loose the feature of dynamically changing from DHCP to static IP, or vice versa +// You have to explicitly specify false to disable the feature. +//#define USE_STATIC_IP_CONFIG_IN_CP false + +// Use false to disable NTP config. Advisable when using Cellphone, Tablet to access Config Portal. +// See Issue 23: On Android phone ConfigPortal is unresponsive (https://github.com/khoih-prog/ESP_WiFiManager/issues/23) +#define USE_ESP_ETH_MANAGER_NTP true + +// Just use enough to save memory. On ESP8266, can cause blank ConfigPortal screen +// if using too much memory +#define USING_AFRICA false +#define USING_AMERICA true +#define USING_ANTARCTICA false +#define USING_ASIA false +#define USING_ATLANTIC false +#define USING_AUSTRALIA false +#define USING_EUROPE false +#define USING_INDIAN false +#define USING_PACIFIC false +#define USING_ETC_GMT false + +// Use true to enable CloudFlare NTP service. System can hang if you don't have Internet access while accessing CloudFlare +// See Issue #21: CloudFlare link in the default portal (https://github.com/khoih-prog/ESP_WiFiManager/issues/21) +#define USE_CLOUDFLARE_NTP false + +// New in v1.0.11 +#define USING_CORS_FEATURE true + +////////////////////////////////////////////////////////////// + +// Use USE_DHCP_IP == true for dynamic DHCP IP, false to use static IP which you have to change accordingly to your network +#if (defined(USE_STATIC_IP_CONFIG_IN_CP) && !USE_STATIC_IP_CONFIG_IN_CP) + // Force DHCP to be true + #if defined(USE_DHCP_IP) + #undef USE_DHCP_IP + #endif + #define USE_DHCP_IP true +#else + // You can select DHCP or Static IP here + #define USE_DHCP_IP true + //#define USE_DHCP_IP false +#endif + +#if ( USE_DHCP_IP ) + // Use DHCP + + #if (_ESP32_ETH_MGR_LOGLEVEL_ > 3) + #warning Using DHCP IP + #endif + + IPAddress stationIP = IPAddress(0, 0, 0, 0); + IPAddress gatewayIP = IPAddress(192, 168, 2, 1); + IPAddress netMask = IPAddress(255, 255, 255, 0); + +#else + // Use static IP + + #if (_ESP32_ETH_MGR_LOGLEVEL_ > 3) + #warning Using static IP + #endif + + IPAddress stationIP = IPAddress(192, 168, 2, 232); + IPAddress gatewayIP = IPAddress(192, 168, 2, 1); + IPAddress netMask = IPAddress(255, 255, 255, 0); +#endif + +////////////////////////////////////////////////////////////// + +#define USE_CONFIGURABLE_DNS true + +IPAddress dns1IP = gatewayIP; +IPAddress dns2IP = IPAddress(8, 8, 8, 8); + +#include //https://github.com/khoih-prog/ESP32_ENC_Manager + +#define HTTP_PORT 80 + +////////////////////////////////////////////////////////////// + +/****************************************** + // Defined in ESP32_ENC_Manager.hpp + typedef struct + { + IPAddress _sta_static_ip; + IPAddress _sta_static_gw; + IPAddress _sta_static_sn; + #if USE_CONFIGURABLE_DNS + IPAddress _sta_static_dns1; + IPAddress _sta_static_dns2; + #endif + } ETH_STA_IPConfig; +******************************************/ + +ETH_STA_IPConfig EthSTA_IPconfig; + +////////////////////////////////////////////////////////////// + +void initSTAIPConfigStruct(ETH_STA_IPConfig &in_EthSTA_IPconfig) +{ + in_EthSTA_IPconfig._sta_static_ip = stationIP; + in_EthSTA_IPconfig._sta_static_gw = gatewayIP; + in_EthSTA_IPconfig._sta_static_sn = netMask; +#if USE_CONFIGURABLE_DNS + in_EthSTA_IPconfig._sta_static_dns1 = dns1IP; + in_EthSTA_IPconfig._sta_static_dns2 = dns2IP; +#endif +} + +////////////////////////////////////////////////////////////// + +void displayIPConfigStruct(ETH_STA_IPConfig in_EthSTA_IPconfig) +{ + LOGERROR3(F("stationIP ="), in_EthSTA_IPconfig._sta_static_ip, ", gatewayIP =", in_EthSTA_IPconfig._sta_static_gw); + LOGERROR1(F("netMask ="), in_EthSTA_IPconfig._sta_static_sn); +#if USE_CONFIGURABLE_DNS + LOGERROR3(F("dns1IP ="), in_EthSTA_IPconfig._sta_static_dns1, ", dns2IP =", in_EthSTA_IPconfig._sta_static_dns2); +#endif +} + +////////////////////////////////////////////////////////////// + +#if USE_ESP_ETH_MANAGER_NTP +void printLocalTime() +{ + struct tm timeinfo; + + getLocalTime( &timeinfo ); + + // Valid only if year > 2000. + // You can get from timeinfo : tm_year, tm_mon, tm_mday, tm_hour, tm_min, tm_sec + if (timeinfo.tm_year > 100 ) + { + Serial.print("Local Date/Time: "); + Serial.print( asctime( &timeinfo ) ); + } +} +#endif + +////////////////////////////////////////////////////////////// + +void heartBeatPrint() +{ +#if USE_ESP_ETH_MANAGER_NTP + printLocalTime(); +#else + static int num = 1; + + if (ESP32_ENC_isConnected()) + Serial.print(F("H")); // H means connected to Ethernet + else + Serial.print(F("F")); // F means not connected to Ethernet + + if (num == 80) + { + Serial.println(); + num = 1; + } + else if (num++ % 10 == 0) + { + Serial.print(F(" ")); + } + +#endif +} + +////////////////////////////////////////////////////////////// + +void check_status() +{ + static ulong checkstatus_timeout = 0; + + static ulong current_millis; + +#if USE_ESP_ETH_MANAGER_NTP +#define HEARTBEAT_INTERVAL 60000L +#else +#define HEARTBEAT_INTERVAL 10000L +#endif + + current_millis = millis(); + + // Print hearbeat every HEARTBEAT_INTERVAL (10) seconds. + if ((current_millis > checkstatus_timeout) || (checkstatus_timeout == 0)) + { + heartBeatPrint(); + checkstatus_timeout = current_millis + HEARTBEAT_INTERVAL; + } +} + +////////////////////////////////////////////////////////////// + +int calcChecksum(uint8_t* address, uint16_t sizeToCalc) +{ + uint16_t checkSum = 0; + + for (uint16_t index = 0; index < sizeToCalc; index++) + { + checkSum += * ( ( (byte*) address ) + index); + } + + return checkSum; +} + +////////////////////////////////////////////////////////////// + +bool loadConfigData() +{ + File file = FileFS.open(CONFIG_FILENAME, "r"); + LOGERROR(F("LoadCfgFile ")); + + memset((void *) &Ethconfig, 0, sizeof(Ethconfig)); + memset((void *) &EthSTA_IPconfig, 0, sizeof(EthSTA_IPconfig)); + + if (file) + { + file.readBytes((char *) &Ethconfig, sizeof(Ethconfig)); + file.readBytes((char *) &EthSTA_IPconfig, sizeof(EthSTA_IPconfig)); + file.close(); + + LOGERROR(F("OK")); + + if ( Ethconfig.checksum != calcChecksum( (uint8_t*) &Ethconfig, sizeof(Ethconfig) - sizeof(Ethconfig.checksum) ) ) + { + LOGERROR(F("Ethconfig checksum wrong")); + + return false; + } + + displayIPConfigStruct(EthSTA_IPconfig); + + return true; + } + else + { + LOGERROR(F("failed")); + + return false; + } +} + +////////////////////////////////////////////////////////////// + +void saveConfigData() +{ + File file = FileFS.open(CONFIG_FILENAME, "w"); + LOGERROR(F("SaveCfgFile ")); + + if (file) + { + Ethconfig.checksum = calcChecksum( (uint8_t*) &Ethconfig, sizeof(Ethconfig) - sizeof(Ethconfig.checksum) ); + + file.write((uint8_t*) &Ethconfig, sizeof(Ethconfig)); + + displayIPConfigStruct(EthSTA_IPconfig); + + file.write((uint8_t*) &EthSTA_IPconfig, sizeof(EthSTA_IPconfig)); + file.close(); + + LOGERROR(F("OK")); + } + else + { + LOGERROR(F("failed")); + } +} + +////////////////////////////////////////////////////////////// + +void beginEthernet() +{ + LOGWARN(F("Default SPI pinout:")); + LOGWARN1(F("MOSI:"), MOSI_GPIO); + LOGWARN1(F("MISO:"), MISO_GPIO); + LOGWARN1(F("SCK:"), SCK_GPIO); + LOGWARN1(F("CS:"), CS_GPIO); + LOGWARN1(F("INT:"), INT_GPIO); + LOGWARN1(F("SPI Clock (MHz):"), SPI_CLOCK_MHZ); + LOGWARN(F("=========================")); + + /////////////////////////////////// + + // To be called before ETH.begin() + ESP32_ENC_onEvent(); + + // start the ethernet connection and the server: + // Use DHCP dynamic IP and random mac + uint16_t index = millis() % NUMBER_OF_MAC; + + //bool begin(int MISO_GPIO, int MOSI_GPIO, int SCLK_GPIO, int CS_GPIO, int INT_GPIO, int SPI_CLOCK_MHZ, + // int SPI_HOST, uint8_t *ENC28J60_Mac = ENC28J60_Default_Mac); + //ETH.begin( MISO_GPIO, MOSI_GPIO, SCK_GPIO, CS_GPIO, INT_GPIO, SPI_CLOCK_MHZ, SPI_HOST ); + ETH.begin( MISO_GPIO, MOSI_GPIO, SCK_GPIO, CS_GPIO, INT_GPIO, SPI_CLOCK_MHZ, SPI_HOST, mac[index] ); +} + +////////////////////////////////////////////////////////////// + +void initEthernet() +{ +#if !( USE_DHCP_IP ) + displayIPConfigStruct(EthSTA_IPconfig); + + // Static IP, leave without this line to get IP via DHCP + //bool config(IPAddress local_ip, IPAddress gateway, IPAddress subnet, IPAddress dns1 = 0, IPAddress dns2 = 0); + //ETH.config(stationIP, gatewayIP, netMask, dns1IP, dns2IP); + ETH.config(EthSTA_IPconfig._sta_static_ip, EthSTA_IPconfig._sta_static_gw, EthSTA_IPconfig._sta_static_sn, + EthSTA_IPconfig._sta_static_dns1); +#endif + + ESP32_ENC_waitForConnect(); +} + +////////////////////////////////////////////////////////////// + +void setup() +{ + // put your setup code here, to run once: + // initialize the LED digital pin as an output. + pinMode(PIN_LED, OUTPUT); + + Serial.begin(115200); + + while (!Serial && millis() < 5000); + + delay(200); + + Serial.print(F("\nStarting ConfigOnDoubleReset_TZ using ")); + Serial.print(FS_Name); + Serial.print(F(" on ")); + Serial.print(ARDUINO_BOARD); + Serial.print(F(" with ")); + Serial.println(SHIELD_TYPE); + Serial.println(ESP32_ENC_MANAGER_VERSION); + Serial.println(ESP_DOUBLE_RESET_DETECTOR_VERSION); + + Serial.setDebugOutput(false); + + if (FORMAT_FILESYSTEM) + FileFS.format(); + + // Format FileFS if not yet +#ifdef ESP32 + + if (!FileFS.begin(true)) +#else + if (!FileFS.begin()) +#endif + { +#ifdef ESP8266 + FileFS.format(); +#endif + + Serial.println(F("SPIFFS/LittleFS failed! Already tried formatting.")); + + if (!FileFS.begin()) + { + // prevents debug info from the library to hide err message. + delay(100); + +#if USE_LITTLEFS + Serial.println(F("LittleFS failed!. Please use SPIFFS or EEPROM. Stay forever")); +#else + Serial.println(F("SPIFFS failed!. Please use LittleFS or EEPROM. Stay forever")); +#endif + + while (true) + { + delay(1); + } + } + } + + drd = new DoubleResetDetector(DRD_TIMEOUT, DRD_ADDRESS); + + unsigned long startedAt = millis(); + + beginEthernet(); + + initSTAIPConfigStruct(EthSTA_IPconfig); + + //Local intialization. Once its business is done, there is no need to keep it around + // Use this to default DHCP hostname to ESP32-XXXXXX + //ESP32_ENC_Manager ESP32_ENC_manager; + // Use this to personalize DHCP hostname (RFC952 conformed) + ESP32_ENC_Manager ESP32_ENC_manager("ConfigOnDoubleReset_TZ"); + +#if !USE_DHCP_IP + // Set (static IP, Gateway, Subnetmask, DNS1 and DNS2) or (IP, Gateway, Subnetmask) + ESP32_ENC_manager.setSTAStaticIPConfig(EthSTA_IPconfig); +#endif + +#if USING_CORS_FEATURE + ESP32_ENC_manager.setCORSHeader("Your Access-Control-Allow-Origin"); +#endif + + bool configDataLoaded = false; + + if (loadConfigData()) + { + configDataLoaded = true; + + //If no access point name has been previously entered disable timeout. + ESP32_ENC_manager.setConfigPortalTimeout(120); + + Serial.println(F("Got stored Credentials. Timeout 120s for Config Portal")); + +#if USE_ESP_ETH_MANAGER_NTP + + if ( strlen(Ethconfig.TZ_Name) > 0 ) + { + LOGERROR3(F("Current TZ_Name ="), Ethconfig.TZ_Name, F(", TZ = "), Ethconfig.TZ); + + //configTzTime(Ethconfig.TZ, "pool.ntp.org" ); + configTzTime(Ethconfig.TZ, "time.nist.gov", "0.pool.ntp.org", "1.pool.ntp.org"); + } + else + { + Serial.println(F("Current Timezone is not set. Enter Config Portal to set.")); + } + +#endif + } + else + { + // Enter CP only if no stored Credentials on flash and file + Serial.println(F("Open Config Portal without Timeout: No stored Credentials.")); + initialConfig = true; + } + + ////////////////////////////////// + + // Connect ETH now if using STA + initEthernet(); + + ////////////////////////////////// + + if (drd->detectDoubleReset()) + { + // DRD, disable timeout. + ESP32_ENC_manager.setConfigPortalTimeout(0); + + Serial.println(F("Open Config Portal without Timeout: Double Reset Detected")); + initialConfig = true; + } + + if (initialConfig) + { + Serial.print(F("Starting configuration portal @ ")); + Serial.println(ETH.localIP()); + + digitalWrite(LED_BUILTIN, LED_ON); // Turn led on as we are in configuration mode. + + //sets timeout in seconds until configuration portal gets turned off. + //If not specified device will remain in configuration mode until + //switched off via webserver or device is restarted. + //ESP32_ENC_manager.setConfigPortalTimeout(600); + + // Starts an access point + if (!ESP32_ENC_manager.startConfigPortal()) + Serial.println(F("Not connected to ETH network but continuing anyway.")); + else + { + Serial.println(F("ETH network connected...yeey :)")); + } + +#if USE_ESP_ETH_MANAGER_NTP + String tempTZ = ESP32_ENC_manager.getTimezoneName(); + + if (strlen(tempTZ.c_str()) < sizeof(Ethconfig.TZ_Name) - 1) + strcpy(Ethconfig.TZ_Name, tempTZ.c_str()); + else + strncpy(Ethconfig.TZ_Name, tempTZ.c_str(), sizeof(Ethconfig.TZ_Name) - 1); + + const char * TZ_Result = ESP32_ENC_manager.getTZ(Ethconfig.TZ_Name); + + if (strlen(TZ_Result) < sizeof(Ethconfig.TZ) - 1) + strcpy(Ethconfig.TZ, TZ_Result); + else + strncpy(Ethconfig.TZ, TZ_Result, sizeof(Ethconfig.TZ_Name) - 1); + + if ( strlen(Ethconfig.TZ_Name) > 0 ) + { + LOGERROR3(F("Saving current TZ_Name ="), Ethconfig.TZ_Name, F(", TZ = "), Ethconfig.TZ); + + //configTzTime(Ethconfig.TZ, "pool.ntp.org" ); + configTzTime(Ethconfig.TZ, "time.nist.gov", "0.pool.ntp.org", "1.pool.ntp.org"); + } + else + { + LOGERROR(F("Current Timezone Name is not set. Enter Config Portal to set.")); + } + +#endif + + ESP32_ENC_manager.getSTAStaticIPConfig(EthSTA_IPconfig); + + saveConfigData(); + } + + digitalWrite(PIN_LED, LED_OFF); // Turn led off as we are not in configuration mode. + + startedAt = millis(); + + Serial.print(F("After waiting ")); + Serial.print((float) (millis() - startedAt) / 1000); + Serial.print(F(" secs more in setup(), connection result is ")); + + if (ESP32_ENC_isConnected()) + { + Serial.print(F("connected. Local IP: ")); + Serial.println(ETH.localIP()); + } +} + +////////////////////////////////////////////////////////////// + +void loop() +{ + // Call the double reset detector loop method every so often, + // so that it can recognise when the timeout expires. + // You can also call drd.stop() when you wish to no longer + // consider the next reset as a double reset. + drd->loop(); + + // put your main code here, to run repeatedly + check_status(); +} diff --git a/examples/ConfigOnSwitch/ConfigOnSwitch.ino b/examples/ConfigOnSwitch/ConfigOnSwitch.ino new file mode 100644 index 0000000..d592a50 --- /dev/null +++ b/examples/ConfigOnSwitch/ConfigOnSwitch.ino @@ -0,0 +1,908 @@ +/**************************************************************************************************************************** + ConfigOnSwitch.ino + For Ethernet shields using ESP32_ENC (ESP32 + LwIP ENC28J60) + + WebServer_ESP32_ENC is a library for the ESP32 with Ethernet ENC28J60 to run WebServer + + Modified from + 1. Tzapu (https://github.com/tzapu/WiFiManager) + 2. Ken Taylor (https://github.com/kentaylor) + 3. Khoi Hoang (https://github.com/khoih-prog/ESP_WiFiManager) + + Built by Khoi Hoang https://github.com/khoih-prog/ESP32_ENC_Manager + Licensed under MIT license + *****************************************************************************************************************************/ +/**************************************************************************************************************************** + This example will open a configuration portal when no configuration has been previously entered or when a button is pushed. + It is the easiest scenario for configuration but requires a pin and a button on the ESP8266 device. + The Flash button is convenient for this on NodeMCU devices. + + Also in this example a password is required to connect to the configuration portal + network. This is inconvenient but means that only those who know the password or those + already connected to the target network can access the configuration portal and + the network credentials will be sent from the browser over an encrypted connection and + can not be read by observers. + *****************************************************************************************************************************/ + +#if !( defined(ESP32) ) + #error This code is intended to run on the (ESP32 + LwIP W5500) platform! Please check your Tools->Board setting. +#endif + +////////////////////////////////////////////////////////////// + +// Use from 0 to 4. Higher number, more debugging messages and memory usage. +#define _ESP32_ETH_MGR_LOGLEVEL_ 4 + +// To not display stored SSIDs and PWDs on Config Portal, select false. Default is true +// Even the stored Credentials are not display, just leave them all blank to reconnect and reuse the stored Credentials +//#define DISPLAY_STORED_CREDENTIALS_IN_CP false + +////////////////////////////////////////////////////////////// + +// Enter a MAC address and IP address for your controller below. +#define NUMBER_OF_MAC 20 + +byte mac[][NUMBER_OF_MAC] = +{ + { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x01 }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xBE, 0x02 }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x03 }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xBE, 0x04 }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x05 }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xBE, 0x06 }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x07 }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xBE, 0x08 }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x09 }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xBE, 0x0A }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x0B }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xBE, 0x0C }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x0D }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xBE, 0x0E }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x0F }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xBE, 0x10 }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x11 }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xBE, 0x12 }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x13 }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xBE, 0x14 }, +}; + +////////////////////////////////////////////////////////// + +// Optional values to override default settings +// Don't change unless you know what you're doing +// Optional values to override default settings +//#define SPI_HOST 1 +//#define SPI_CLOCK_MHZ 8 + +// Must connect INT to GPIOxx or not working +//#define INT_GPIO 4 + +//#define MISO_GPIO 19 +//#define MOSI_GPIO 23 +//#define SCK_GPIO 18 +//#define CS_GPIO 5 + +////////////////////////////////////////////////////////// + +//For ESP32, To use ESP32 Dev Module, QIO, Flash 4MB/80MHz, Upload 921600 + +//Ported to ESP32 +#include + +////////////////////////////////////////////////////////////// + +// LittleFS has higher priority than SPIFFS +#if ( defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 2) ) + #define USE_LITTLEFS true + #define USE_SPIFFS false +#elif defined(ARDUINO_ESP32C3_DEV) + // For core v1.0.6-, ESP32-C3 only supporting SPIFFS and EEPROM. To use v2.0.0+ for LittleFS + #define USE_LITTLEFS false + #define USE_SPIFFS true +#endif + +#if USE_LITTLEFS + // Use LittleFS + #include "FS.h" + + // Check cores/esp32/esp_arduino_version.h and cores/esp32/core_version.h + //#if ( ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(2, 0, 0) ) //(ESP_ARDUINO_VERSION_MAJOR >= 2) + #if ( defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 2) ) + #if (_ESP32_ETH_MGR_LOGLEVEL_ > 3) + #warning Using ESP32 Core 1.0.6 or 2.0.0+ + #endif + + // The library has been merged into esp32 core from release 1.0.6 + #include // https://github.com/espressif/arduino-esp32/tree/master/libraries/LittleFS + + FS* filesystem = &LittleFS; + #define FileFS LittleFS + #define FS_Name "LittleFS" + #else + #if (_ESP32_ETH_MGR_LOGLEVEL_ > 3) + #warning Using ESP32 Core 1.0.5-. You must install LITTLEFS library + #endif + + // The library has been merged into esp32 core from release 1.0.6 + #include // https://github.com/lorol/LITTLEFS + + FS* filesystem = &LITTLEFS; + #define FileFS LITTLEFS + #define FS_Name "LittleFS" + #endif + +#elif USE_SPIFFS + #include + FS* filesystem = &SPIFFS; + #define FileFS SPIFFS + #define FS_Name "SPIFFS" +#else + // Use FFat + #include + FS* filesystem = &FFat; + #define FileFS FFat + #define FS_Name "FFat" +#endif + +////////////////////////////////////////////////////////////// + +#define LED_BUILTIN 2 +#define LED_ON HIGH +#define LED_OFF LOW + +//See file .../hardware/espressif/esp32/variants/(esp32|doitESP32devkitV1)/pins_arduino.h +#define LED_BUILTIN 2 // Pin D2 mapped to pin GPIO2/ADC12 of ESP32, control on-board LED +#define LED_BUILTIN 2 // Pin D2 mapped to pin GPIO2/ADC12 of ESP32, control on-board LED + +#define PIN_D0 0 // Pin D0 mapped to pin GPIO0/BOOT/ADC11/TOUCH1 of ESP32 +#define PIN_D1 1 // Pin D1 mapped to pin GPIO1/TX0 of ESP32 +#define PIN_D2 2 // Pin D2 mapped to pin GPIO2/ADC12/TOUCH2 of ESP32 +#define PIN_D3 3 // Pin D3 mapped to pin GPIO3/RX0 of ESP32 +#define PIN_D4 4 // Pin D4 mapped to pin GPIO4/ADC10/TOUCH0 of ESP32 +#define PIN_D5 5 // Pin D5 mapped to pin GPIO5/SPISS/VSPI_SS of ESP32 +#define PIN_D6 6 // Pin D6 mapped to pin GPIO6/FLASH_SCK of ESP32 +#define PIN_D7 7 // Pin D7 mapped to pin GPIO7/FLASH_D0 of ESP32 +#define PIN_D8 8 // Pin D8 mapped to pin GPIO8/FLASH_D1 of ESP32 +#define PIN_D9 9 // Pin D9 mapped to pin GPIO9/FLASH_D2 of ESP32 + +#define PIN_D10 10 // Pin D10 mapped to pin GPIO10/FLASH_D3 of ESP32 +#define PIN_D11 11 // Pin D11 mapped to pin GPIO11/FLASH_CMD of ESP32 +#define PIN_D12 12 // Pin D12 mapped to pin GPIO12/HSPI_MISO/ADC15/TOUCH5/TDI of ESP32 +#define PIN_D13 13 // Pin D13 mapped to pin GPIO13/HSPI_MOSI/ADC14/TOUCH4/TCK of ESP32 +#define PIN_D14 14 // Pin D14 mapped to pin GPIO14/HSPI_SCK/ADC16/TOUCH6/TMS of ESP32 +#define PIN_D15 15 // Pin D15 mapped to pin GPIO15/HSPI_SS/ADC13/TOUCH3/TDO of ESP32 +#define PIN_D16 16 // Pin D16 mapped to pin GPIO16/TX2 of ESP32 +#define PIN_D17 17 // Pin D17 mapped to pin GPIO17/RX2 of ESP32 +#define PIN_D18 18 // Pin D18 mapped to pin GPIO18/VSPI_SCK of ESP32 +#define PIN_D19 19 // Pin D19 mapped to pin GPIO19/VSPI_MISO of ESP32 + +#define PIN_D21 21 // Pin D21 mapped to pin GPIO21/SDA of ESP32 +#define PIN_D22 22 // Pin D22 mapped to pin GPIO22/SCL of ESP32 +#define PIN_D23 23 // Pin D23 mapped to pin GPIO23/VSPI_MOSI of ESP32 +#define PIN_D24 24 // Pin D24 mapped to pin GPIO24 of ESP32 +#define PIN_D25 25 // Pin D25 mapped to pin GPIO25/ADC18/DAC1 of ESP32 +#define PIN_D26 26 // Pin D26 mapped to pin GPIO26/ADC19/DAC2 of ESP32 +#define PIN_D27 27 // Pin D27 mapped to pin GPIO27/ADC17/TOUCH7 of ESP32 + +#define PIN_D32 32 // Pin D32 mapped to pin GPIO32/ADC4/TOUCH9 of ESP32 +#define PIN_D33 33 // Pin D33 mapped to pin GPIO33/ADC5/TOUCH8 of ESP32 +#define PIN_D34 34 // Pin D34 mapped to pin GPIO34/ADC6 of ESP32 + +//Only GPIO pin < 34 can be used as output. Pins >= 34 can be only inputs +//See .../cores/esp32/esp32-hal-gpio.h/c +//#define digitalPinIsValid(pin) ((pin) < 40 && esp32_gpioMux[(pin)].reg) +//#define digitalPinCanOutput(pin) ((pin) < 34 && esp32_gpioMux[(pin)].reg) +//#define digitalPinToRtcPin(pin) (((pin) < 40)?esp32_gpioMux[(pin)].rtc:-1) +//#define digitalPinToAnalogChannel(pin) (((pin) < 40)?esp32_gpioMux[(pin)].adc:-1) +//#define digitalPinToTouchChannel(pin) (((pin) < 40)?esp32_gpioMux[(pin)].touch:-1) +//#define digitalPinToDacChannel(pin) (((pin) == 25)?0:((pin) == 26)?1:-1) + +#define PIN_D35 35 // Pin D35 mapped to pin GPIO35/ADC7 of ESP32 +#define PIN_D36 36 // Pin D36 mapped to pin GPIO36/ADC0/SVP of ESP32 +#define PIN_D39 39 // Pin D39 mapped to pin GPIO39/ADC3/SVN of ESP32 + +#define PIN_RX0 3 // Pin RX0 mapped to pin GPIO3/RX0 of ESP32 +#define PIN_TX0 1 // Pin TX0 mapped to pin GPIO1/TX0 of ESP32 + +#define PIN_SCL 22 // Pin SCL mapped to pin GPIO22/SCL of ESP32 +#define PIN_SDA 21 // Pin SDA mapped to pin GPIO21/SDA of ESP32 + +////////////////////////////////////////////////////////////// + +/* Trigger for inititating config mode is Pin D3 and also flash button on NodeMCU + Flash button is convenient to use but if it is pressed it will stuff up the serial port device driver + until the computer is rebooted on windows machines. +*/ +#if ( USING_ESP32_S2 || USING_ESP32_C3 ) + + const int TRIGGER_PIN = PIN_D3; // Pin D3 mapped to pin GPIO03/ADC1-2/TOUCH3 of ESP32-S2 + /* + Alternative trigger pin. Needs to be connected to a button to use this pin. It must be a momentary connection + not connected permanently to ground. Either trigger pin will work. + */ + const int TRIGGER_PIN2 = PIN_D4; // Pin D4 mapped to pin GPIO04/ADC1_3/TOUCH4 of ESP32-S2 + +#else + const int TRIGGER_PIN = PIN_D0; // Pin D0 mapped to pin GPIO0/BOOT/ADC11/TOUCH1 of ESP32 + /* + Alternative trigger pin. Needs to be connected to a button to use this pin. It must be a momentary connection + not connected permanently to ground. Either trigger pin will work. + */ + const int TRIGGER_PIN2 = PIN_D25; // Pin D25 mapped to pin GPIO25/ADC18/DAC1 of ESP32 +#endif + +////////////////////////////////////////////////////////////// + +// You only need to format the filesystem once +//#define FORMAT_FILESYSTEM true +#define FORMAT_FILESYSTEM false + +////////////////////////////////////////////////////////////// + +// Assuming max 49 chars +#define TZNAME_MAX_LEN 50 +#define TIMEZONE_MAX_LEN 50 + +typedef struct +{ + char TZ_Name[TZNAME_MAX_LEN]; // "America/Toronto" + char TZ[TIMEZONE_MAX_LEN]; // "EST5EDT,M3.2.0,M11.1.0" + uint16_t checksum; +} EthConfig; + +EthConfig Ethconfig; + +////////////////////////////////////////////////////////////// + +#define CONFIG_FILENAME F("/eth_cred.dat") + +////////////////////////////////////////////////////////////// + +// Indicates whether ESP has credentials saved from previous session, or double reset detected +bool initialConfig = false; + +// Use false if you don't like to display Available Pages in Information Page of Config Portal +// Comment out or use true to display Available Pages in Information Page of Config Portal +// Must be placed before #include +#define USE_AVAILABLE_PAGES true + +// From v1.0.10 to permit disable/enable StaticIP configuration in Config Portal from sketch. Valid only if DHCP is used. +// You'll loose the feature of dynamically changing from DHCP to static IP, or vice versa +// You have to explicitly specify false to disable the feature. +//#define USE_STATIC_IP_CONFIG_IN_CP false + +// Use false to disable NTP config. Advisable when using Cellphone, Tablet to access Config Portal. +// See Issue 23: On Android phone ConfigPortal is unresponsive (https://github.com/khoih-prog/ESP_WiFiManager/issues/23) +#define USE_ESP_ETH_MANAGER_NTP true + +// Just use enough to save memory. On ESP8266, can cause blank ConfigPortal screen +// if using too much memory +#define USING_AFRICA false +#define USING_AMERICA true +#define USING_ANTARCTICA false +#define USING_ASIA false +#define USING_ATLANTIC false +#define USING_AUSTRALIA false +#define USING_EUROPE false +#define USING_INDIAN false +#define USING_PACIFIC false +#define USING_ETC_GMT false + +// Use true to enable CloudFlare NTP service. System can hang if you don't have Internet access while accessing CloudFlare +// See Issue #21: CloudFlare link in the default portal (https://github.com/khoih-prog/ESP_WiFiManager/issues/21) +#define USE_CLOUDFLARE_NTP false + +// New in v1.0.11 +#define USING_CORS_FEATURE true + +////////////////////////////////////////////////////////////// + +// Use USE_DHCP_IP == true for dynamic DHCP IP, false to use static IP which you have to change accordingly to your network +#if (defined(USE_STATIC_IP_CONFIG_IN_CP) && !USE_STATIC_IP_CONFIG_IN_CP) + // Force DHCP to be true + #if defined(USE_DHCP_IP) + #undef USE_DHCP_IP + #endif + #define USE_DHCP_IP true +#else + // You can select DHCP or Static IP here + //#define USE_DHCP_IP true + #define USE_DHCP_IP false +#endif + +#if ( USE_DHCP_IP ) + // Use DHCP + + #if (_ESP32_ETH_MGR_LOGLEVEL_ > 3) + #warning Using DHCP IP + #endif + + IPAddress stationIP = IPAddress(0, 0, 0, 0); + IPAddress gatewayIP = IPAddress(192, 168, 2, 1); + IPAddress netMask = IPAddress(255, 255, 255, 0); + +#else + // Use static IP + + #if (_ESP32_ETH_MGR_LOGLEVEL_ > 3) + #warning Using static IP + #endif + + IPAddress stationIP = IPAddress(192, 168, 2, 232); + IPAddress gatewayIP = IPAddress(192, 168, 2, 1); + IPAddress netMask = IPAddress(255, 255, 255, 0); +#endif + +////////////////////////////////////////////////////////////// + +#define USE_CONFIGURABLE_DNS true + +IPAddress dns1IP = gatewayIP; +IPAddress dns2IP = IPAddress(8, 8, 8, 8); + +#include //https://github.com/khoih-prog/ESP32_ENC_Manager + +#define HTTP_PORT 80 + +////////////////////////////////////////////////////////////// + +/****************************************** + // Defined in ESP32_ENC_Manager.hpp + typedef struct + { + IPAddress _sta_static_ip; + IPAddress _sta_static_gw; + IPAddress _sta_static_sn; + #if USE_CONFIGURABLE_DNS + IPAddress _sta_static_dns1; + IPAddress _sta_static_dns2; + #endif + } ETH_STA_IPConfig; +******************************************/ + +ETH_STA_IPConfig EthSTA_IPconfig; + +////////////////////////////////////////////////////////////// + +void initSTAIPConfigStruct(ETH_STA_IPConfig &in_EthSTA_IPconfig) +{ + in_EthSTA_IPconfig._sta_static_ip = stationIP; + in_EthSTA_IPconfig._sta_static_gw = gatewayIP; + in_EthSTA_IPconfig._sta_static_sn = netMask; +#if USE_CONFIGURABLE_DNS + in_EthSTA_IPconfig._sta_static_dns1 = dns1IP; + in_EthSTA_IPconfig._sta_static_dns2 = dns2IP; +#endif +} + +////////////////////////////////////////////////////////////// + +void displayIPConfigStruct(ETH_STA_IPConfig in_EthSTA_IPconfig) +{ + LOGERROR3(F("stationIP ="), in_EthSTA_IPconfig._sta_static_ip, ", gatewayIP =", in_EthSTA_IPconfig._sta_static_gw); + LOGERROR1(F("netMask ="), in_EthSTA_IPconfig._sta_static_sn); +#if USE_CONFIGURABLE_DNS + LOGERROR3(F("dns1IP ="), in_EthSTA_IPconfig._sta_static_dns1, ", dns2IP =", in_EthSTA_IPconfig._sta_static_dns2); +#endif +} + +////////////////////////////////////////////////////////////// + +void toggleLED() +{ + //toggle state + digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); +} + +////////////////////////////////////////////////////////////// + +#if USE_ESP_ETH_MANAGER_NTP +void printLocalTime() +{ + struct tm timeinfo; + + getLocalTime( &timeinfo ); + + // Valid only if year > 2000. + // You can get from timeinfo : tm_year, tm_mon, tm_mday, tm_hour, tm_min, tm_sec + if (timeinfo.tm_year > 100 ) + { + Serial.print("Local Date/Time: "); + Serial.print( asctime( &timeinfo ) ); + } +} +#endif + +////////////////////////////////////////////////////////////// + +void heartBeatPrint() +{ +#if USE_ESP_ETH_MANAGER_NTP + printLocalTime(); +#else + static int num = 1; + + if (ESP32_ENC_isConnected()) + Serial.print(F("H")); // H means connected to Ethernet + else + Serial.print(F("F")); // F means not connected to Ethernet + + if (num == 80) + { + Serial.println(); + num = 1; + } + else if (num++ % 10 == 0) + { + Serial.print(F(" ")); + } + +#endif +} + +////////////////////////////////////////////////////////////// + +void check_status() +{ + static ulong checkstatus_timeout = 0; + static ulong LEDstatus_timeout = 0; + + static ulong current_millis; + +#if USE_ESP_ETH_MANAGER_NTP +#define HEARTBEAT_INTERVAL 60000L +#else +#define HEARTBEAT_INTERVAL 10000L +#endif + +#define LED_INTERVAL 2000L + + current_millis = millis(); + + if ((current_millis > LEDstatus_timeout) || (LEDstatus_timeout == 0)) + { + // Toggle LED at LED_INTERVAL = 2s + toggleLED(); + LEDstatus_timeout = current_millis + LED_INTERVAL; + } + + // Print hearbeat every HEARTBEAT_INTERVAL (10) seconds. + if ((current_millis > checkstatus_timeout) || (checkstatus_timeout == 0)) + { + heartBeatPrint(); + checkstatus_timeout = current_millis + HEARTBEAT_INTERVAL; + } +} + +////////////////////////////////////////////////////////////// + +int calcChecksum(uint8_t* address, uint16_t sizeToCalc) +{ + uint16_t checkSum = 0; + + for (uint16_t index = 0; index < sizeToCalc; index++) + { + checkSum += * ( ( (byte*) address ) + index); + } + + return checkSum; +} + +////////////////////////////////////////////////////////////// + +bool loadConfigData() +{ + File file = FileFS.open(CONFIG_FILENAME, "r"); + LOGERROR(F("LoadCfgFile ")); + + memset((void *) &Ethconfig, 0, sizeof(Ethconfig)); + memset((void *) &EthSTA_IPconfig, 0, sizeof(EthSTA_IPconfig)); + + if (file) + { + file.readBytes((char *) &Ethconfig, sizeof(Ethconfig)); + file.readBytes((char *) &EthSTA_IPconfig, sizeof(EthSTA_IPconfig)); + file.close(); + + LOGERROR(F("OK")); + + if ( Ethconfig.checksum != calcChecksum( (uint8_t*) &Ethconfig, sizeof(Ethconfig) - sizeof(Ethconfig.checksum) ) ) + { + LOGERROR(F("Ethconfig checksum wrong")); + + return false; + } + + displayIPConfigStruct(EthSTA_IPconfig); + + return true; + } + else + { + LOGERROR(F("failed")); + + return false; + } +} + +////////////////////////////////////////////////////////////// + +void saveConfigData() +{ + File file = FileFS.open(CONFIG_FILENAME, "w"); + LOGERROR(F("SaveCfgFile ")); + + if (file) + { + Ethconfig.checksum = calcChecksum( (uint8_t*) &Ethconfig, sizeof(Ethconfig) - sizeof(Ethconfig.checksum) ); + + file.write((uint8_t*) &Ethconfig, sizeof(Ethconfig)); + + displayIPConfigStruct(EthSTA_IPconfig); + + file.write((uint8_t*) &EthSTA_IPconfig, sizeof(EthSTA_IPconfig)); + file.close(); + + LOGERROR(F("OK")); + } + else + { + LOGERROR(F("failed")); + } +} + +////////////////////////////////////////////////////////////// + +void beginEthernet() +{ + LOGWARN(F("Default SPI pinout:")); + LOGWARN1(F("MOSI:"), MOSI_GPIO); + LOGWARN1(F("MISO:"), MISO_GPIO); + LOGWARN1(F("SCK:"), SCK_GPIO); + LOGWARN1(F("CS:"), CS_GPIO); + LOGWARN1(F("INT:"), INT_GPIO); + LOGWARN1(F("SPI Clock (MHz):"), SPI_CLOCK_MHZ); + LOGWARN(F("=========================")); + + /////////////////////////////////// + + // To be called before ETH.begin() + ESP32_ENC_onEvent(); + + // start the ethernet connection and the server: + // Use DHCP dynamic IP and random mac + uint16_t index = millis() % NUMBER_OF_MAC; + + //bool begin(int MISO_GPIO, int MOSI_GPIO, int SCLK_GPIO, int CS_GPIO, int INT_GPIO, int SPI_CLOCK_MHZ, + // int SPI_HOST, uint8_t *ENC28J60_Mac = ENC28J60_Default_Mac); + //ETH.begin( MISO_GPIO, MOSI_GPIO, SCK_GPIO, CS_GPIO, INT_GPIO, SPI_CLOCK_MHZ, SPI_HOST ); + ETH.begin( MISO_GPIO, MOSI_GPIO, SCK_GPIO, CS_GPIO, INT_GPIO, SPI_CLOCK_MHZ, SPI_HOST, mac[index] ); +} + +////////////////////////////////////////////////////////////// + +void initEthernet() +{ +#if !( USE_DHCP_IP ) + displayIPConfigStruct(EthSTA_IPconfig); + + // Static IP, leave without this line to get IP via DHCP + //bool config(IPAddress local_ip, IPAddress gateway, IPAddress subnet, IPAddress dns1 = 0, IPAddress dns2 = 0); + //ETH.config(stationIP, gatewayIP, netMask, dns1IP, dns2IP); + ETH.config(EthSTA_IPconfig._sta_static_ip, EthSTA_IPconfig._sta_static_gw, EthSTA_IPconfig._sta_static_sn, + EthSTA_IPconfig._sta_static_dns1); +#endif + + ESP32_ENC_waitForConnect(); +} + +////////////////////////////////////////////////////////////// + +void setup() +{ + //set led pin as output + pinMode(LED_BUILTIN, OUTPUT); + + pinMode(TRIGGER_PIN, INPUT_PULLUP); + pinMode(TRIGGER_PIN2, INPUT_PULLUP); + + Serial.begin(115200); + + while (!Serial && millis() < 5000); + + delay(200); + + Serial.print(F("\nStarting ConfigOnSwitch using ")); + Serial.print(FS_Name); + Serial.print(F(" on ")); + Serial.print(ARDUINO_BOARD); + Serial.print(F(" with ")); + Serial.println(SHIELD_TYPE); + Serial.println(ESP32_ENC_MANAGER_VERSION); + + Serial.setDebugOutput(false); + + if (FORMAT_FILESYSTEM) + FileFS.format(); + + // Format FileFS if not yet +#ifdef ESP32 + + if (!FileFS.begin(true)) +#else + if (!FileFS.begin()) +#endif + { +#ifdef ESP8266 + FileFS.format(); +#endif + + Serial.println(F("SPIFFS/LittleFS failed! Already tried formatting.")); + + if (!FileFS.begin()) + { + // prevents debug info from the library to hide err message. + delay(100); + +#if USE_LITTLEFS + Serial.println(F("LittleFS failed!. Please use SPIFFS or EEPROM. Stay forever")); +#else + Serial.println(F("SPIFFS failed!. Please use LittleFS or EEPROM. Stay forever")); +#endif + + while (true) + { + delay(1); + } + } + } + + unsigned long startedAt = millis(); + + beginEthernet(); + + initSTAIPConfigStruct(EthSTA_IPconfig); + + digitalWrite(LED_BUILTIN, LED_ON); // turn the LED on by making the voltage LOW to tell us we are in configuration mode. + + //Local intialization. Once its business is done, there is no need to keep it around + // Use this to default DHCP hostname to ESP32-XXXXXX + //ESP32_ENC_Manager ESP32_ENC_manager; + // Use this to personalize DHCP hostname (RFC952 conformed) + ESP32_ENC_Manager ESP32_ENC_manager("ConfigOnSwitch"); + + ESP32_ENC_manager.setDebugOutput(true); + +#if !USE_DHCP_IP + // Set (static IP, Gateway, Subnetmask, DNS1 and DNS2) or (IP, Gateway, Subnetmask) + ESP32_ENC_manager.setSTAStaticIPConfig(EthSTA_IPconfig); +#endif + +#if USING_CORS_FEATURE + ESP32_ENC_manager.setCORSHeader("Your Access-Control-Allow-Origin"); +#endif + + bool configDataLoaded = false; + + if (loadConfigData()) + { + configDataLoaded = true; + + //If no access point name has been previously entered disable timeout. + ESP32_ENC_manager.setConfigPortalTimeout(120); + + Serial.println(F("Got stored Credentials. Timeout 120s for Config Portal")); + +#if USE_ESP_ETH_MANAGER_NTP + + if ( strlen(Ethconfig.TZ_Name) > 0 ) + { + LOGERROR3(F("Current TZ_Name ="), Ethconfig.TZ_Name, F(", TZ = "), Ethconfig.TZ); + + //configTzTime(Ethconfig.TZ, "pool.ntp.org" ); + configTzTime(Ethconfig.TZ, "time.nist.gov", "0.pool.ntp.org", "1.pool.ntp.org"); + } + else + { + Serial.println(F("Current Timezone is not set. Enter Config Portal to set.")); + } + +#endif + } + else + { + // Enter CP only if no stored SSID on flash and file + Serial.println(F("Open Config Portal without Timeout: No stored Credentials.")); + initialConfig = true; + } + + ////////////////////////////////// + + // Connect ETH now if using STA + initEthernet(); + + ////////////////////////////////// + + if (initialConfig) + { + Serial.print(F("Starting configuration portal @ ")); + Serial.println(ETH.localIP()); + + digitalWrite(LED_BUILTIN, LED_ON); // Turn led on as we are in configuration mode. + + //sets timeout in seconds until configuration portal gets turned off. + //If not specified device will remain in configuration mode until + //switched off via webserver or device is restarted. + //ESP32_ENC_manager.setConfigPortalTimeout(600); + + // Starts an access point + if (!ESP32_ENC_manager.startConfigPortal()) + Serial.println(F("Not connected to ETH network but continuing anyway.")); + else + { + Serial.println(F("ETH network connected...yeey :)")); + } + +#if USE_ESP_ETH_MANAGER_NTP + String tempTZ = ESP32_ENC_manager.getTimezoneName(); + + if (strlen(tempTZ.c_str()) < sizeof(Ethconfig.TZ_Name) - 1) + strcpy(Ethconfig.TZ_Name, tempTZ.c_str()); + else + strncpy(Ethconfig.TZ_Name, tempTZ.c_str(), sizeof(Ethconfig.TZ_Name) - 1); + + const char * TZ_Result = ESP32_ENC_manager.getTZ(Ethconfig.TZ_Name); + + if (strlen(TZ_Result) < sizeof(Ethconfig.TZ) - 1) + strcpy(Ethconfig.TZ, TZ_Result); + else + strncpy(Ethconfig.TZ, TZ_Result, sizeof(Ethconfig.TZ_Name) - 1); + + if ( strlen(Ethconfig.TZ_Name) > 0 ) + { + LOGERROR3(F("Saving current TZ_Name ="), Ethconfig.TZ_Name, F(", TZ = "), Ethconfig.TZ); + + //configTzTime(Ethconfig.TZ, "pool.ntp.org" ); + configTzTime(Ethconfig.TZ, "time.nist.gov", "0.pool.ntp.org", "1.pool.ntp.org"); + } + else + { + LOGERROR(F("Current Timezone Name is not set. Enter Config Portal to set.")); + } + +#endif + + ESP32_ENC_manager.getSTAStaticIPConfig(EthSTA_IPconfig); + + saveConfigData(); + } + + digitalWrite(LED_BUILTIN, LED_OFF); // Turn led off as we are not in configuration mode. + + startedAt = millis(); + + Serial.print(F("After waiting ")); + Serial.print((float) (millis() - startedAt) / 1000); + Serial.print(F(" secs more in setup(), connection result is ")); + + if (ESP32_ENC_isConnected()) + { + Serial.print(F("connected. Local IP: ")); + Serial.println(ETH.localIP()); + } +} + +////////////////////////////////////////////////////////////// + +void loop() +{ + // is configuration portal requested? + if ((digitalRead(TRIGGER_PIN) == LOW) || (digitalRead(TRIGGER_PIN2) == LOW)) + { + Serial.println(F("\nConfiguration portal requested.")); + digitalWrite(LED_BUILTIN, LED_ON); // turn the LED on by making the voltage LOW to tell us we are in configuration mode. + + //Local intialization. Once its business is done, there is no need to keep it around + // Use this to default DHCP hostname to ESP32-XXXXXX + //ESP32_ENC_Manager ESP32_ENC_manager; + // Use this to personalize DHCP hostname (RFC952 conformed) + ESP32_ENC_Manager ESP32_ENC_manager("ConfigOnSwitch"); + +#if !USE_DHCP_IP +#if USE_CONFIGURABLE_DNS + // Set static IP, Gateway, Subnetmask, DNS1 and DNS2 + ESP32_ENC_manager.setSTAStaticIPConfig(stationIP, gatewayIP, netMask, dns1IP, dns2IP); +#else + // Set static IP, Gateway, Subnetmask, Use auto DNS1 and DNS2. + ESP32_ENC_manager.setSTAStaticIPConfig(stationIP, gatewayIP, netMask); +#endif +#endif + +#if USING_CORS_FEATURE + ESP32_ENC_manager.setCORSHeader("Your Access-Control-Allow-Origin"); +#endif + + //Check if there is stored credentials. + //If not found, device will remain in configuration mode until switched off via webserver. + Serial.println(F("Opening configuration portal. ")); + + if (loadConfigData()) + { + ESP32_ENC_manager.setConfigPortalTimeout( + 120); //If no access point name has been previously entered disable timeout. + Serial.println(F("Got stored Credentials. Timeout 120s for Config Portal")); + } + else + { + // Enter CP only if no stored SSID on flash and file + ESP32_ENC_manager.setConfigPortalTimeout(0); + Serial.println(F("Open Config Portal without Timeout: No stored Credentials.")); + initialConfig = true; + } + + //Starts an access point + //and goes into a blocking loop awaiting configuration + if (!ESP32_ENC_manager.startConfigPortal()) + Serial.println(F("Not connected to ETH network but continuing anyway.")); + else + { + Serial.println(F("ETH network connected...yeey :)")); + Serial.print(F("Local IP: ")); + Serial.println(ETH.localIP()); + } + +#if USE_ESP_ETH_MANAGER_NTP + String tempTZ = ESP32_ENC_manager.getTimezoneName(); + + if (strlen(tempTZ.c_str()) < sizeof(Ethconfig.TZ_Name) - 1) + strcpy(Ethconfig.TZ_Name, tempTZ.c_str()); + else + strncpy(Ethconfig.TZ_Name, tempTZ.c_str(), sizeof(Ethconfig.TZ_Name) - 1); + + const char * TZ_Result = ESP32_ENC_manager.getTZ(Ethconfig.TZ_Name); + + if (strlen(TZ_Result) < sizeof(Ethconfig.TZ) - 1) + strcpy(Ethconfig.TZ, TZ_Result); + else + strncpy(Ethconfig.TZ, TZ_Result, sizeof(Ethconfig.TZ_Name) - 1); + + if ( strlen(Ethconfig.TZ_Name) > 0 ) + { + LOGERROR3(F("Saving current TZ_Name ="), Ethconfig.TZ_Name, F(", TZ = "), Ethconfig.TZ); + + //configTzTime(Ethconfig.TZ, "pool.ntp.org" ); + configTzTime(Ethconfig.TZ, "time.nist.gov", "0.pool.ntp.org", "1.pool.ntp.org"); + } + else + { + LOGERROR(F("Current Timezone Name is not set. Enter Config Portal to set.")); + } + +#endif + + ESP32_ENC_manager.getSTAStaticIPConfig(EthSTA_IPconfig); + + saveConfigData(); + +#if !USE_DHCP_IP + + // Reset to use new Static IP, if different from current ETH.localIP() + if (ETH.localIP() != EthSTA_IPconfig._sta_static_ip) + { + Serial.print(F("Current IP = ")); + Serial.print(ETH.localIP()); + Serial.print(F(". Reset to take new IP = ")); + Serial.println(EthSTA_IPconfig._sta_static_ip); + + ESP.restart(); + delay(2000); + } + +#endif + + digitalWrite(LED_BUILTIN, LED_OFF); // Turn led off as we are not in configuration mode. + } + + // put your main code here, to run repeatedly + check_status(); +} diff --git a/examples/ConfigOnSwitchFS/ConfigOnSwitchFS.ino b/examples/ConfigOnSwitchFS/ConfigOnSwitchFS.ino new file mode 100644 index 0000000..18fd2d9 --- /dev/null +++ b/examples/ConfigOnSwitchFS/ConfigOnSwitchFS.ino @@ -0,0 +1,1116 @@ +/**************************************************************************************************************************** + ConfigOnSwitchFS.ino + For Ethernet shields using ESP32_ENC (ESP32 + LwIP ENC28J60) + + WebServer_ESP32_ENC is a library for the ESP32 with Ethernet ENC28J60 to run WebServer + + Modified from + 1. Tzapu (https://github.com/tzapu/WiFiManager) + 2. Ken Taylor (https://github.com/kentaylor) + 3. Khoi Hoang (https://github.com/khoih-prog/ESP_WiFiManager) + + Built by Khoi Hoang https://github.com/khoih-prog/ESP32_ENC_Manager + Licensed under MIT license + *****************************************************************************************************************************/ +/**************************************************************************************************************************** + This example will open a configuration portal when the reset button is pressed twice. + This method works well on Wemos boards which have a single reset button on board. It avoids using a pin for launching the configuration portal. + + Settings + There are two values to be set in the sketch. + + DRD_TIMEOUT - Number of seconds to wait for the second reset. Set to 10 in the example. + DRD_ADDRESS - The address in ESP8266 RTC RAM to store the flag. This memory must not be used for other purposes in the same sketch. Set to 0 in the example. + + This example, originally relied on the Double Reset Detector library from https://github.com/datacute/DoubleResetDetector + To support ESP32, use ESP_DoubleResetDetector library from //https://github.com/khoih-prog/ESP_DoubleResetDetector + *****************************************************************************************************************************/ +/**************************************************************************************************************************** + This example will open a configuration portal when no configuration has been previously entered or when a button is pushed. + It is the easiest scenario for configuration but requires a pin and a button on the ESP8266 device. + The Flash button is convenient for this on NodeMCU devices. + + Also in this example a password is required to connect to the configuration portal + network. This is inconvenient but means that only those who know the password or those + already connected to the target network can access the configuration portal and + the network credentials will be sent from the browser over an encrypted connection and + can not be read by observers. + *****************************************************************************************************************************/ + +#if !( defined(ESP32) ) + #error This code is intended to run on the (ESP32 + LwIP W5500) platform! Please check your Tools->Board setting. +#endif + +////////////////////////////////////////////////////////////// + +// Use from 0 to 4. Higher number, more debugging messages and memory usage. +#define _ESP32_ETH_MGR_LOGLEVEL_ 4 + +// To not display stored SSIDs and PWDs on Config Portal, select false. Default is true +// Even the stored Credentials are not display, just leave them all blank to reconnect and reuse the stored Credentials +//#define DISPLAY_STORED_CREDENTIALS_IN_CP false + +////////////////////////////////////////////////////////////// + +// Enter a MAC address and IP address for your controller below. +#define NUMBER_OF_MAC 20 + +byte mac[][NUMBER_OF_MAC] = +{ + { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x01 }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xBE, 0x02 }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x03 }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xBE, 0x04 }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x05 }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xBE, 0x06 }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x07 }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xBE, 0x08 }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x09 }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xBE, 0x0A }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x0B }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xBE, 0x0C }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x0D }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xBE, 0x0E }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x0F }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xBE, 0x10 }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x11 }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xBE, 0x12 }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x13 }, + { 0xDE, 0xAD, 0xBE, 0xEF, 0xBE, 0x14 }, +}; + +////////////////////////////////////////////////////////// + +// Optional values to override default settings +// Don't change unless you know what you're doing +// Optional values to override default settings +//#define SPI_HOST 1 +//#define SPI_CLOCK_MHZ 8 + +// Must connect INT to GPIOxx or not working +//#define INT_GPIO 4 + +//#define MISO_GPIO 19 +//#define MOSI_GPIO 23 +//#define SCK_GPIO 18 +//#define CS_GPIO 5 + +////////////////////////////////////////////////////////// + +#include +// Now support ArduinoJson 6.0.0+ ( tested with v6.14.1 ) +#include // get it from https://arduinojson.org/ or install via Arduino library manager + +//For ESP32, To use ESP32 Dev Module, QIO, Flash 4MB/80MHz, Upload 921600 +//Ported to ESP32 +#include + +////////////////////////////////////////////////////////////// + +// LittleFS has higher priority than SPIFFS +#if ( defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 2) ) + #define USE_LITTLEFS true + #define USE_SPIFFS false +#elif defined(ARDUINO_ESP32C3_DEV) + // For core v1.0.6-, ESP32-C3 only supporting SPIFFS and EEPROM. To use v2.0.0+ for LittleFS + #define USE_LITTLEFS false + #define USE_SPIFFS true +#endif + +#if USE_LITTLEFS + // Use LittleFS + #include "FS.h" + + // Check cores/esp32/esp_arduino_version.h and cores/esp32/core_version.h + //#if ( ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(2, 0, 0) ) //(ESP_ARDUINO_VERSION_MAJOR >= 2) + #if ( defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 2) ) + #if (_ESP32_ETH_MGR_LOGLEVEL_ > 3) + #warning Using ESP32 Core 1.0.6 or 2.0.0+ + #endif + + // The library has been merged into esp32 core from release 1.0.6 + #include // https://github.com/espressif/arduino-esp32/tree/master/libraries/LittleFS + + FS* filesystem = &LittleFS; + #define FileFS LittleFS + #define FS_Name "LittleFS" + #else + #if (_ESP32_ETH_MGR_LOGLEVEL_ > 3) + #warning Using ESP32 Core 1.0.5-. You must install LITTLEFS library + #endif + + // The library has been merged into esp32 core from release 1.0.6 + #include // https://github.com/lorol/LITTLEFS + + FS* filesystem = &LITTLEFS; + #define FileFS LITTLEFS + #define FS_Name "LittleFS" + #endif + +#elif USE_SPIFFS + #include + FS* filesystem = &SPIFFS; + #define FileFS SPIFFS + #define FS_Name "SPIFFS" +#else + // +Use FFat + #include + FS* filesystem = &FFat; + #define FileFS FFat + #define FS_Name "FFat" +#endif + +////////////////////////////////////////////////////////////// + +#define LED_BUILTIN 2 +#define LED_ON HIGH +#define LED_OFF LOW + +////////////////////////////////////////////////////////////// + +//See file .../hardware/espressif/esp32/variants/(esp32|doitESP32devkitV1)/pins_arduino.h +#define LED_BUILTIN 2 // Pin D2 mapped to pin GPIO2/ADC12 of ESP32, control on-board LED +#define PIN_LED 2 // Pin D2 mapped to pin GPIO2/ADC12 of ESP32, control on-board LED + +#define PIN_D0 0 // Pin D0 mapped to pin GPIO0/BOOT/ADC11/TOUCH1 of ESP32 +#define PIN_D1 1 // Pin D1 mapped to pin GPIO1/TX0 of ESP32 +#define PIN_D2 2 // Pin D2 mapped to pin GPIO2/ADC12/TOUCH2 of ESP32 +#define PIN_D3 3 // Pin D3 mapped to pin GPIO3/RX0 of ESP32 +#define PIN_D4 4 // Pin D4 mapped to pin GPIO4/ADC10/TOUCH0 of ESP32 +#define PIN_D5 5 // Pin D5 mapped to pin GPIO5/SPISS/VSPI_SS of ESP32 +#define PIN_D6 6 // Pin D6 mapped to pin GPIO6/FLASH_SCK of ESP32 +#define PIN_D7 7 // Pin D7 mapped to pin GPIO7/FLASH_D0 of ESP32 +#define PIN_D8 8 // Pin D8 mapped to pin GPIO8/FLASH_D1 of ESP32 +#define PIN_D9 9 // Pin D9 mapped to pin GPIO9/FLASH_D2 of ESP32 + +#define PIN_D10 10 // Pin D10 mapped to pin GPIO10/FLASH_D3 of ESP32 +#define PIN_D11 11 // Pin D11 mapped to pin GPIO11/FLASH_CMD of ESP32 +#define PIN_D12 12 // Pin D12 mapped to pin GPIO12/HSPI_MISO/ADC15/TOUCH5/TDI of ESP32 +#define PIN_D13 13 // Pin D13 mapped to pin GPIO13/HSPI_MOSI/ADC14/TOUCH4/TCK of ESP32 +#define PIN_D14 14 // Pin D14 mapped to pin GPIO14/HSPI_SCK/ADC16/TOUCH6/TMS of ESP32 +#define PIN_D15 15 // Pin D15 mapped to pin GPIO15/HSPI_SS/ADC13/TOUCH3/TDO of ESP32 +#define PIN_D16 16 // Pin D16 mapped to pin GPIO16/TX2 of ESP32 +#define PIN_D17 17 // Pin D17 mapped to pin GPIO17/RX2 of ESP32 +#define PIN_D18 18 // Pin D18 mapped to pin GPIO18/VSPI_SCK of ESP32 +#define PIN_D19 19 // Pin D19 mapped to pin GPIO19/VSPI_MISO of ESP32 + +#define PIN_D21 21 // Pin D21 mapped to pin GPIO21/SDA of ESP32 +#define PIN_D22 22 // Pin D22 mapped to pin GPIO22/SCL of ESP32 +#define PIN_D23 23 // Pin D23 mapped to pin GPIO23/VSPI_MOSI of ESP32 +#define PIN_D24 24 // Pin D24 mapped to pin GPIO24 of ESP32 +#define PIN_D25 25 // Pin D25 mapped to pin GPIO25/ADC18/DAC1 of ESP32 +#define PIN_D26 26 // Pin D26 mapped to pin GPIO26/ADC19/DAC2 of ESP32 +#define PIN_D27 27 // Pin D27 mapped to pin GPIO27/ADC17/TOUCH7 of ESP32 + +#define PIN_D32 32 // Pin D32 mapped to pin GPIO32/ADC4/TOUCH9 of ESP32 +#define PIN_D33 33 // Pin D33 mapped to pin GPIO33/ADC5/TOUCH8 of ESP32 +#define PIN_D34 34 // Pin D34 mapped to pin GPIO34/ADC6 of ESP32 + +//Only GPIO pin < 34 can be used as output. Pins >= 34 can be only inputs +//See .../cores/esp32/esp32-hal-gpio.h/c +//#define digitalPinIsValid(pin) ((pin) < 40 && esp32_gpioMux[(pin)].reg) +//#define digitalPinCanOutput(pin) ((pin) < 34 && esp32_gpioMux[(pin)].reg) +//#define digitalPinToRtcPin(pin) (((pin) < 40)?esp32_gpioMux[(pin)].rtc:-1) +//#define digitalPinToAnalogChannel(pin) (((pin) < 40)?esp32_gpioMux[(pin)].adc:-1) +//#define digitalPinToTouchChannel(pin) (((pin) < 40)?esp32_gpioMux[(pin)].touch:-1) +//#define digitalPinToDacChannel(pin) (((pin) == 25)?0:((pin) == 26)?1:-1) + +#define PIN_D35 35 // Pin D35 mapped to pin GPIO35/ADC7 of ESP32 +#define PIN_D36 36 // Pin D36 mapped to pin GPIO36/ADC0/SVP of ESP32 +#define PIN_D39 39 // Pin D39 mapped to pin GPIO39/ADC3/SVN of ESP32 + +#define PIN_RX0 3 // Pin RX0 mapped to pin GPIO3/RX0 of ESP32 +#define PIN_TX0 1 // Pin TX0 mapped to pin GPIO1/TX0 of ESP32 + +#define PIN_SCL 22 // Pin SCL mapped to pin GPIO22/SCL of ESP32 +#define PIN_SDA 21 // Pin SDA mapped to pin GPIO21/SDA of ESP32 + +////////////////////////////////////////////////////////////// + +/* Trigger for inititating config mode is Pin D3 and also flash button on NodeMCU + Flash button is convenient to use but if it is pressed it will stuff up the serial port device driver + until the computer is rebooted on windows machines. +*/ +const int TRIGGER_PIN = PIN_D0; // Pin D0 mapped to pin GPIO0/BOOT/ADC11/TOUCH1 of ESP32 +/* + Alternative trigger pin. Needs to be connected to a button to use this pin. It must be a momentary connection + not connected permanently to ground. Either trigger pin will work. +*/ +#if ( ARDUINO_ESP32C3_DEV ) + const int TRIGGER_PIN2 = PIN_D8; // Pin D8 mapped to pin GPIO8/FLASH_D1 of ESP32 +#else + const int TRIGGER_PIN2 = PIN_D25; // Pin D25 mapped to pin GPIO25/ADC18/DAC1 of ESP32 +#endif + +int pinSda = PIN_SDA; // Pin SDA mapped to pin GPIO21/SDA of ESP32 +int pinScl = PIN_SCL; // Pin SCL mapped to pin GPIO22/SCL of ESP32 + +////////////////////////////////////////////////////////////// + +const char* JSON_CONFIG_FILE = "/ConfigSW.json"; + +// Variables + +// Default configuration values +char thingspeakApiKey[17] = ""; +bool sensorDht22 = true; + +#define ThingSpeakAPI_Label "thingspeakApiKey" +#define SensorDht22_Label "SensorDHT22" +#define PinSDA_Label "PinSda" +#define PinSCL_Label "PinScl" + +////////////////////////////////////////////////////////////// + +// Function Prototypes + +bool readConfigFile(); +bool writeConfigFile(); + +// You only need to format the filesystem once +//#define FORMAT_FILESYSTEM true +#define FORMAT_FILESYSTEM false + +////////////////////////////////////////////////////////////// + +// Assuming max 49 chars +#define TZNAME_MAX_LEN 50 +#define TIMEZONE_MAX_LEN 50 + +typedef struct +{ + char TZ_Name[TZNAME_MAX_LEN]; // "America/Toronto" + char TZ[TIMEZONE_MAX_LEN]; // "EST5EDT,M3.2.0,M11.1.0" + uint16_t checksum; +} EthConfig; + +EthConfig Ethconfig; + +#define CONFIG_FILENAME F("/eth_cred.dat") + +////////////////////////////////////////////////////////////// + +// Indicates whether ESP has credentials saved from previous session +bool initialConfig = false; + +// Use false if you don't like to display Available Pages in Information Page of Config Portal +// Comment out or use true to display Available Pages in Information Page of Config Portal +// Must be placed before #include +#define USE_AVAILABLE_PAGES true + +// From v1.0.10 to permit disable/enable StaticIP configuration in Config Portal from sketch. Valid only if DHCP is used. +// You'll loose the feature of dynamically changing from DHCP to static IP, or vice versa +// You have to explicitly specify false to disable the feature. +//#define USE_STATIC_IP_CONFIG_IN_CP false + +// Use false to disable NTP config. Advisable when using Cellphone, Tablet to access Config Portal. +// See Issue 23: On Android phone ConfigPortal is unresponsive (https://github.com/khoih-prog/ESP_WiFiManager/issues/23) +#define USE_ESP_ETH_MANAGER_NTP true + +// Just use enough to save memory. On ESP8266, can cause blank ConfigPortal screen +// if using too much memory +#define USING_AFRICA false +#define USING_AMERICA true +#define USING_ANTARCTICA false +#define USING_ASIA false +#define USING_ATLANTIC false +#define USING_AUSTRALIA false +#define USING_EUROPE false +#define USING_INDIAN false +#define USING_PACIFIC false +#define USING_ETC_GMT false + +// Use true to enable CloudFlare NTP service. System can hang if you don't have Internet access while accessing CloudFlare +// See Issue #21: CloudFlare link in the default portal (https://github.com/khoih-prog/ESP_WiFiManager/issues/21) +#define USE_CLOUDFLARE_NTP false + +// New in v1.0.11 +#define USING_CORS_FEATURE true + +////////////////////////////////////////////////////////////// + +// Use USE_DHCP_IP == true for dynamic DHCP IP, false to use static IP which you have to change accordingly to your network +#if (defined(USE_STATIC_IP_CONFIG_IN_CP) && !USE_STATIC_IP_CONFIG_IN_CP) + // Force DHCP to be true + #if defined(USE_DHCP_IP) + #undef USE_DHCP_IP + #endif + #define USE_DHCP_IP true +#else + // You can select DHCP or Static IP here + //#define USE_DHCP_IP true + #define USE_DHCP_IP false +#endif + +#if ( USE_DHCP_IP ) + // Use DHCP + + #if (_ESP32_ETH_MGR_LOGLEVEL_ > 3) + #warning Using DHCP IP + #endif + + IPAddress stationIP = IPAddress(0, 0, 0, 0); + IPAddress gatewayIP = IPAddress(192, 168, 2, 1); + IPAddress netMask = IPAddress(255, 255, 255, 0); + +#else + // Use static IP + + #if (_ESP32_ETH_MGR_LOGLEVEL_ > 3) + #warning Using static IP + #endif + + IPAddress stationIP = IPAddress(192, 168, 2, 232); + IPAddress gatewayIP = IPAddress(192, 168, 2, 1); + IPAddress netMask = IPAddress(255, 255, 255, 0); +#endif + +////////////////////////////////////////////////////////////// + +#define USE_CONFIGURABLE_DNS true + +IPAddress dns1IP = gatewayIP; +IPAddress dns2IP = IPAddress(8, 8, 8, 8); + +#include //https://github.com/khoih-prog/ESP32_ENC_Manager + +#define HTTP_PORT 80 + +////////////////////////////////////////////////////////////// + +/****************************************** + // Defined in ESP32_ENC_Manager.hpp + typedef struct + { + IPAddress _sta_static_ip; + IPAddress _sta_static_gw; + IPAddress _sta_static_sn; + #if USE_CONFIGURABLE_DNS + IPAddress _sta_static_dns1; + IPAddress _sta_static_dns2; + #endif + } ETH_STA_IPConfig; +******************************************/ + +ETH_STA_IPConfig EthSTA_IPconfig; + +////////////////////////////////////////////////////////////// + +void initSTAIPConfigStruct(ETH_STA_IPConfig &in_EthSTA_IPconfig) +{ + in_EthSTA_IPconfig._sta_static_ip = stationIP; + in_EthSTA_IPconfig._sta_static_gw = gatewayIP; + in_EthSTA_IPconfig._sta_static_sn = netMask; +#if USE_CONFIGURABLE_DNS + in_EthSTA_IPconfig._sta_static_dns1 = dns1IP; + in_EthSTA_IPconfig._sta_static_dns2 = dns2IP; +#endif +} + +////////////////////////////////////////////////////////////// + +void displayIPConfigStruct(ETH_STA_IPConfig in_EthSTA_IPconfig) +{ + LOGERROR3(F("stationIP ="), in_EthSTA_IPconfig._sta_static_ip, ", gatewayIP =", in_EthSTA_IPconfig._sta_static_gw); + LOGERROR1(F("netMask ="), in_EthSTA_IPconfig._sta_static_sn); +#if USE_CONFIGURABLE_DNS + LOGERROR3(F("dns1IP ="), in_EthSTA_IPconfig._sta_static_dns1, ", dns2IP =", in_EthSTA_IPconfig._sta_static_dns2); +#endif +} + +////////////////////////////////////////////////////////////// + +void toggleLED() +{ + //toggle state + digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); +} + +////////////////////////////////////////////////////////////// + +#if USE_ESP_ETH_MANAGER_NTP +void printLocalTime() +{ + struct tm timeinfo; + + getLocalTime( &timeinfo ); + + // Valid only if year > 2000. + // You can get from timeinfo : tm_year, tm_mon, tm_mday, tm_hour, tm_min, tm_sec + if (timeinfo.tm_year > 100 ) + { + Serial.print("Local Date/Time: "); + Serial.print( asctime( &timeinfo ) ); + } +} +#endif + +////////////////////////////////////////////////////////////// + +void heartBeatPrint() +{ +#if USE_ESP_ETH_MANAGER_NTP + printLocalTime(); +#else + static int num = 1; + + if (ESP32_ENC_isConnected()) + Serial.print(F("H")); // H means connected to Ethernet + else + Serial.print(F("F")); // F means not connected to Ethernet + + if (num == 80) + { + Serial.println(); + num = 1; + } + else if (num++ % 10 == 0) + { + Serial.print(F(" ")); + } + +#endif +} + +////////////////////////////////////////////////////////////// + +void check_status() +{ + static ulong checkstatus_timeout = 0; + static ulong LEDstatus_timeout = 0; + + static ulong current_millis; + +#if USE_ESP_ETH_MANAGER_NTP +#define HEARTBEAT_INTERVAL 60000L +#else +#define HEARTBEAT_INTERVAL 10000L +#endif + +#define LED_INTERVAL 2000L + + current_millis = millis(); + + if ((current_millis > LEDstatus_timeout) || (LEDstatus_timeout == 0)) + { + // Toggle LED at LED_INTERVAL = 2s + toggleLED(); + LEDstatus_timeout = current_millis + LED_INTERVAL; + } + + // Print hearbeat every HEARTBEAT_INTERVAL (10) seconds. + if ((current_millis > checkstatus_timeout) || (checkstatus_timeout == 0)) + { + heartBeatPrint(); + checkstatus_timeout = current_millis + HEARTBEAT_INTERVAL; + } +} + +////////////////////////////////////////////////////////////// + +int calcChecksum(uint8_t* address, uint16_t sizeToCalc) +{ + uint16_t checkSum = 0; + + for (uint16_t index = 0; index < sizeToCalc; index++) + { + checkSum += * ( ( (byte*) address ) + index); + } + + return checkSum; +} + +////////////////////////////////////////////////////////////// + +bool loadConfigData() +{ + File file = FileFS.open(CONFIG_FILENAME, "r"); + LOGERROR(F("LoadCfgFile ")); + + memset((void *) &Ethconfig, 0, sizeof(Ethconfig)); + memset((void *) &EthSTA_IPconfig, 0, sizeof(EthSTA_IPconfig)); + + if (file) + { + file.readBytes((char *) &Ethconfig, sizeof(Ethconfig)); + file.readBytes((char *) &EthSTA_IPconfig, sizeof(EthSTA_IPconfig)); + file.close(); + + LOGERROR(F("OK")); + + if ( Ethconfig.checksum != calcChecksum( (uint8_t*) &Ethconfig, sizeof(Ethconfig) - sizeof(Ethconfig.checksum) ) ) + { + LOGERROR(F("Ethconfig checksum wrong")); + + return false; + } + + displayIPConfigStruct(EthSTA_IPconfig); + + return true; + } + else + { + LOGERROR(F("failed")); + + return false; + } +} + +////////////////////////////////////////////////////////////// + +void saveConfigData() +{ + File file = FileFS.open(CONFIG_FILENAME, "w"); + LOGERROR(F("SaveCfgFile ")); + + if (file) + { + Ethconfig.checksum = calcChecksum( (uint8_t*) &Ethconfig, sizeof(Ethconfig) - sizeof(Ethconfig.checksum) ); + + file.write((uint8_t*) &Ethconfig, sizeof(Ethconfig)); + + displayIPConfigStruct(EthSTA_IPconfig); + + file.write((uint8_t*) &EthSTA_IPconfig, sizeof(EthSTA_IPconfig)); + file.close(); + + LOGERROR(F("OK")); + } + else + { + LOGERROR(F("failed")); + } +} + +////////////////////////////////////////////////////////////// + +bool readConfigFile() +{ + // this opens the config file in read-mode + File f = FileFS.open(JSON_CONFIG_FILE, "r"); + + if (!f) + { + Serial.println(F("Configuration file not found")); + + return false; + } + else + { + // we could open the file + size_t size = f.size(); + // Allocate a buffer to store contents of the file. + std::unique_ptr buf(new char[size + 1]); + + // Read and store file contents in buf + f.readBytes(buf.get(), size); + // Closing file + f.close(); + // Using dynamic JSON buffer which is not the recommended memory model, but anyway + // See https://github.com/bblanchon/ArduinoJson/wiki/Memory%20model + +#if (ARDUINOJSON_VERSION_MAJOR >= 6) + DynamicJsonDocument json(1024); + auto deserializeError = deserializeJson(json, buf.get()); + + if ( deserializeError ) + { + Serial.println(F("JSON parseObject() failed")); + + return false; + } + + serializeJson(json, Serial); +#else + DynamicJsonBuffer jsonBuffer; + // Parse JSON string + JsonObject& json = jsonBuffer.parseObject(buf.get()); + + // Test if parsing succeeds. + if (!json.success()) + { + Serial.println(F("JSON parseObject() failed")); + return false; + } + + json.printTo(Serial); +#endif + + // Parse all config file parameters, override + // local config variables with parsed values + if (json.containsKey(ThingSpeakAPI_Label)) + { + strcpy(thingspeakApiKey, json[ThingSpeakAPI_Label]); + } + + if (json.containsKey(SensorDht22_Label)) + { + sensorDht22 = json[SensorDht22_Label]; + } + + if (json.containsKey(PinSDA_Label)) + { + pinSda = json[PinSDA_Label]; + } + + if (json.containsKey(PinSCL_Label)) + { + pinScl = json[PinSCL_Label]; + } + } + + Serial.println(F("\nConfig file was successfully parsed")); + + return true; +} + +////////////////////////////////////////////////////////////// + +bool writeConfigFile() +{ + Serial.println(F("Saving config file")); + +#if (ARDUINOJSON_VERSION_MAJOR >= 6) + DynamicJsonDocument json(1024); +#else + DynamicJsonBuffer jsonBuffer; + JsonObject& json = jsonBuffer.createObject(); +#endif + + // JSONify local configuration parameters + json[ThingSpeakAPI_Label] = thingspeakApiKey; + json[SensorDht22_Label] = sensorDht22; + json[PinSDA_Label] = pinSda; + json[PinSCL_Label] = pinScl; + + // Open file for writing + File f = FileFS.open(JSON_CONFIG_FILE, "w"); + + if (!f) + { + Serial.println(F("Failed to open config file for writing")); + + return false; + } + +#if (ARDUINOJSON_VERSION_MAJOR >= 6) + serializeJsonPretty(json, Serial); + // Write data to file and close it + serializeJson(json, f); +#else + json.prettyPrintTo(Serial); + // Write data to file and close it + json.printTo(f); +#endif + + f.close(); + + Serial.println(F("\nConfig file was successfully saved")); + + return true; +} + +////////////////////////////////////////////////////////////// + +void beginEthernet() +{ + LOGWARN(F("Default SPI pinout:")); + LOGWARN1(F("MOSI:"), MOSI_GPIO); + LOGWARN1(F("MISO:"), MISO_GPIO); + LOGWARN1(F("SCK:"), SCK_GPIO); + LOGWARN1(F("CS:"), CS_GPIO); + LOGWARN1(F("INT:"), INT_GPIO); + LOGWARN1(F("SPI Clock (MHz):"), SPI_CLOCK_MHZ); + LOGWARN(F("=========================")); + + /////////////////////////////////// + + // To be called before ETH.begin() + ESP32_ENC_onEvent(); + + // start the ethernet connection and the server: + // Use DHCP dynamic IP and random mac + uint16_t index = millis() % NUMBER_OF_MAC; + + //bool begin(int MISO_GPIO, int MOSI_GPIO, int SCLK_GPIO, int CS_GPIO, int INT_GPIO, int SPI_CLOCK_MHZ, + // int SPI_HOST, uint8_t *ENC28J60_Mac = ENC28J60_Default_Mac); + //ETH.begin( MISO_GPIO, MOSI_GPIO, SCK_GPIO, CS_GPIO, INT_GPIO, SPI_CLOCK_MHZ, SPI_HOST ); + ETH.begin( MISO_GPIO, MOSI_GPIO, SCK_GPIO, CS_GPIO, INT_GPIO, SPI_CLOCK_MHZ, SPI_HOST, mac[index] ); +} + +////////////////////////////////////////////////////////////// + +void initEthernet() +{ +#if !( USE_DHCP_IP ) + displayIPConfigStruct(EthSTA_IPconfig); + + // Static IP, leave without this line to get IP via DHCP + //bool config(IPAddress local_ip, IPAddress gateway, IPAddress subnet, IPAddress dns1 = 0, IPAddress dns2 = 0); + //ETH.config(stationIP, gatewayIP, netMask, dns1IP, dns2IP); + ETH.config(EthSTA_IPconfig._sta_static_ip, EthSTA_IPconfig._sta_static_gw, EthSTA_IPconfig._sta_static_sn, + EthSTA_IPconfig._sta_static_dns1); +#endif + + ESP32_ENC_waitForConnect(); +} + +////////////////////////////////////////////////////////////// + +void setup() +{ + //set led pin as output + pinMode(LED_BUILTIN, OUTPUT); + + // Put your setup code here, to run once + Serial.begin(115200); + + while (!Serial && millis() < 5000); + + delay(200); + + Serial.print(F("\nStarting ConfigOnSwichFS using ")); + Serial.print(FS_Name); + Serial.print(F(" on ")); + Serial.print(ARDUINO_BOARD); + Serial.print(F(" with ")); + Serial.println(SHIELD_TYPE); + Serial.println(ESP32_ENC_MANAGER_VERSION); + + // Initialize the LED digital pin as an output. + pinMode(PIN_LED, OUTPUT); + // Initialize trigger pins + pinMode(TRIGGER_PIN, INPUT_PULLUP); + pinMode(TRIGGER_PIN2, INPUT_PULLUP); + + if (FORMAT_FILESYSTEM) + { + Serial.println(F("Forced Formatting.")); + FileFS.format(); + } + + // Format FileFS if not yet +#ifdef ESP32 + + if (!FileFS.begin(true)) +#else + if (!FileFS.begin()) +#endif + { +#ifdef ESP8266 + FileFS.format(); +#endif + + Serial.println(F("SPIFFS/LittleFS failed! Already tried formatting.")); + + if (!FileFS.begin()) + { + // prevents debug info from the library to hide err message. + delay(100); + +#if USE_LITTLEFS + Serial.println(F("LittleFS failed!. Please use SPIFFS or EEPROM. Stay forever")); +#else + Serial.println(F("SPIFFS failed!. Please use LittleFS or EEPROM. Stay forever")); +#endif + + while (true) + { + delay(1); + } + } + } + + beginEthernet(); + + initSTAIPConfigStruct(EthSTA_IPconfig); + + if (!readConfigFile()) + { + Serial.println(F("Failed to read ConfigFile, using default values")); + } + + unsigned long startedAt = millis(); + + //Local intialization. Once its business is done, there is no need to keep it around + // Use this to default DHCP hostname to ESP32-XXXXXX + //ESP32_ENC_Manager ESP32_ENC_manager; + // Use this to personalize DHCP hostname (RFC952 conformed) + ESP32_ENC_Manager ESP32_ENC_manager("ConfigOnSwitchFS"); + + ESP32_ENC_manager.setDebugOutput(true); + +#if !USE_DHCP_IP + // Set (static IP, Gateway, Subnetmask, DNS1 and DNS2) or (IP, Gateway, Subnetmask) + ESP32_ENC_manager.setSTAStaticIPConfig(EthSTA_IPconfig); +#endif + +#if USING_CORS_FEATURE + ESP32_ENC_manager.setCORSHeader("Your Access-Control-Allow-Origin"); +#endif + + bool configDataLoaded = false; + + if (loadConfigData()) + { + configDataLoaded = true; + + //If no access point name has been previously entered disable timeout. + ESP32_ENC_manager.setConfigPortalTimeout(120); + + Serial.println(F("Got stored Credentials. Timeout 120s for Config Portal")); + +#if USE_ESP_ETH_MANAGER_NTP + + if ( strlen(Ethconfig.TZ_Name) > 0 ) + { + LOGERROR3(F("Current TZ_Name ="), Ethconfig.TZ_Name, F(", TZ = "), Ethconfig.TZ); + + //configTzTime(Ethconfig.TZ, "pool.ntp.org" ); + configTzTime(Ethconfig.TZ, "time.nist.gov", "0.pool.ntp.org", "1.pool.ntp.org"); + } + else + { + Serial.println(F("Current Timezone is not set. Enter Config Portal to set.")); + } + +#endif + } + else + { + // Enter CP only if no stored SSID on flash and file + Serial.println(F("Open Config Portal without Timeout: No stored Credentials.")); + initialConfig = true; + } + + + ////////////////////////////////// + + // Connect ETH now if using STA + initEthernet(); + + ////////////////////////////////// + + if (initialConfig) + { + Serial.print(F("Starting configuration portal @ ")); + Serial.println(ETH.localIP()); + + digitalWrite(LED_BUILTIN, LED_ON); // Turn led on as we are in configuration mode. + + //sets timeout in seconds until configuration portal gets turned off. + //If not specified device will remain in configuration mode until + //switched off via webserver or device is restarted. + //ESP32_ENC_manager.setConfigPortalTimeout(600); + + // Starts an access point + if (!ESP32_ENC_manager.startConfigPortal()) + Serial.println(F("Not connected to ETH network but continuing anyway.")); + else + { + Serial.println(F("ETH network connected...yeey :)")); + } + + +#if USE_ESP_ETH_MANAGER_NTP + String tempTZ = ESP32_ENC_manager.getTimezoneName(); + + if (strlen(tempTZ.c_str()) < sizeof(Ethconfig.TZ_Name) - 1) + strcpy(Ethconfig.TZ_Name, tempTZ.c_str()); + else + strncpy(Ethconfig.TZ_Name, tempTZ.c_str(), sizeof(Ethconfig.TZ_Name) - 1); + + const char * TZ_Result = ESP32_ENC_manager.getTZ(Ethconfig.TZ_Name); + + if (strlen(TZ_Result) < sizeof(Ethconfig.TZ) - 1) + strcpy(Ethconfig.TZ, TZ_Result); + else + strncpy(Ethconfig.TZ, TZ_Result, sizeof(Ethconfig.TZ_Name) - 1); + + if ( strlen(Ethconfig.TZ_Name) > 0 ) + { + LOGERROR3(F("Saving current TZ_Name ="), Ethconfig.TZ_Name, F(", TZ = "), Ethconfig.TZ); + + //configTzTime(Ethconfig.TZ, "pool.ntp.org" ); + configTzTime(Ethconfig.TZ, "time.nist.gov", "0.pool.ntp.org", "1.pool.ntp.org"); + } + else + { + LOGERROR(F("Current Timezone Name is not set. Enter Config Portal to set.")); + } + +#endif + + ESP32_ENC_manager.getSTAStaticIPConfig(EthSTA_IPconfig); + + saveConfigData(); + } + + digitalWrite(LED_BUILTIN, LED_OFF); // Turn led off as we are not in configuration mode. + + startedAt = millis(); + + Serial.print(F("After waiting ")); + Serial.print((float) (millis() - startedAt) / 1000); + Serial.print(F(" secs more in setup(), connection result is ")); + + if (ESP32_ENC_isConnected()) + { + Serial.print(F("connected. Local IP: ")); + Serial.println(ETH.localIP()); + } +} + +////////////////////////////////////////////////////////////// + +void loop() +{ + // is configuration portal requested? + if ((digitalRead(TRIGGER_PIN) == LOW) || (digitalRead(TRIGGER_PIN2) == LOW)) + { + Serial.println(F("\nConfiguration portal requested.")); + digitalWrite(LED_BUILTIN, LED_ON); // turn the LED on by making the voltage LOW to tell us we are in configuration mode. + + //Local intialization. Once its business is done, there is no need to keep it around + // Use this to default DHCP hostname to ESP32-XXXXXX + //ESP32_ENC_Manager ESP32_ENC_manager; + // Use this to personalize DHCP hostname (RFC952 conformed) + ESP32_ENC_Manager ESP32_ENC_manager("ConfigOnSwitchFS"); + + //Check if there is stored credentials. + //If not found, device will remain in configuration mode until switched off via webserver. + Serial.println(F("Opening configuration portal. ")); + + if (loadConfigData()) + { + //If no access point name has been previously entered disable timeout. + ESP32_ENC_manager.setConfigPortalTimeout(120); + + Serial.println(F("Got stored Credentials. Timeout 120s for Config Portal")); + } + else + { + // Enter CP only if no stored SSID on flash and file + Serial.println(F("Open Config Portal without Timeout: No stored Credentials.")); + initialConfig = true; + } + + // Extra parameters to be configured + // After connecting, parameter.getValue() will get you the configured value + // Format:
"; + +const char EM_FLDSET_START[] PROGMEM = "
"; +const char EM_FLDSET_END[] PROGMEM = "
"; + +//////////////////////////////////////////////////// + +const char EM_HTTP_PORTAL_OPTIONS[] PROGMEM = "



"; +const char EM_HTTP_ITEM[] PROGMEM = "
{v} {r}%
"; +const char JSON_ITEM[] PROGMEM = "{\"SSID\":\"{v}\", \"Encryption\":{i}, \"Quality\":\"{r}\"}"; + +//////////////////////////////////////////////////// + +// To permit display stored Credentials on CP +#ifndef DISPLAY_STORED_CREDENTIALS_IN_CP + #define DISPLAY_STORED_CREDENTIALS_IN_CP true +#endif + +#if ( (_ESP32_ETH_MGR_LOGLEVEL_ > 3) && DISPLAY_STORED_CREDENTIALS_IN_CP ) + #warning Enable DISPLAY_STORED_CREDENTIALS_IN_CP +#endif + +#if DISPLAY_STORED_CREDENTIALS_IN_CP +const char EM_HTTP_FORM_START[] PROGMEM = "
"; +#else +const char EM_HTTP_FORM_START[] PROGMEM = ""; +#endif + +//////////////////////////////////////////////////// + +const char EM_HTTP_FORM_LABEL_BEFORE[] PROGMEM = "
"; +const char EM_HTTP_FORM_LABEL_AFTER[] PROGMEM = "
"; + +//////////////////////////////////////////////////// + +const char EM_HTTP_FORM_LABEL[] PROGMEM = ""; +const char EM_HTTP_FORM_PARAM[] PROGMEM = ""; + +const char EM_HTTP_FORM_END[] PROGMEM = "
"; + +//////////////////////////////////////////////////// + +const char EM_HTTP_SAVED[] PROGMEM = "
Credentials Saved
"; + +//////////////////////////////////////////////////// + +const char EM_HTTP_END[] PROGMEM = "
"; + +//////////////////////////////////////////////////// + +const char EM_HTTP_HEAD_CL[] = "Content-Length"; +const char EM_HTTP_HEAD_CT[] = "text/html"; +const char EM_HTTP_HEAD_CT2[] = "text/plain"; + +const char EM_HTTP_HEAD_JSON[] ="application/json"; + +//KH Add repeatedly used const +const char EM_HTTP_CACHE_CONTROL[] = "Cache-Control"; +const char EM_HTTP_NO_STORE[] = "no-cache, no-store, must-revalidate"; +const char EM_HTTP_PRAGMA[] = "Pragma"; +const char EM_HTTP_NO_CACHE[] = "no-cache"; +const char EM_HTTP_EXPIRES[] = "Expires"; +const char EM_HTTP_CORS[] = "Access-Control-Allow-Origin"; +const char EM_HTTP_CORS_ALLOW_ALL[] = "*"; + +//////////////////////////////////////////////////// + +#if USE_AVAILABLE_PAGES + const char EM_HTTP_AVAILABLE_PAGES[] PROGMEM = "

Available Pages

PageFunction
/Menu page.
/ethEnter ETH Config Page
/ethsaveSave Config. Portal Info with supplied variables.
/closeClose the Config Portal.
/iThis Info page.
/rDelete ETH configuration and reboot.
/stateCurrent device state in JSON format. Interface for ETH configuration.
"; +#else + const char EM_HTTP_AVAILABLE_PAGES[] PROGMEM = ""; +#endif + +//////////////////////////////////////////////////// + +#define ETH_MANAGER_MAX_PARAMS 20 + +//////////////////////////////////////////////////// + +// To permit autoConnect() to use STA static IP or DHCP IP. +#ifndef AUTOCONNECT_NO_INVALIDATE + #define AUTOCONNECT_NO_INVALIDATE true +#endif + +//////////////////////////////////////////////////// + +typedef struct +{ + const char *_id; + const char *_placeholder; + char *_value; + int _length; + int _labelPlacement; +} EMParam_Data; + + +//////////////////////////////////////////////////// +//////////////////////////////////////////////////// + +class ESP32_EMParameter +{ + public: + + ESP32_EMParameter(const char *custom); + ESP32_EMParameter(const char *id, const char *placeholder, const char *defaultValue, const int& length, + const char *custom = "", const int& labelPlacement = WFM_LABEL_BEFORE); + + ESP32_EMParameter(const EMParam_Data& EMParam_data); + + ~ESP32_EMParameter(); + + void setEMParam_Data(const EMParam_Data& EMParam_data); + void getEMParam_Data(EMParam_Data& EMParam_data); + + const char *getID(); + const char *getValue(); + const char *getPlaceholder(); + int getValueLength(); + int getLabelPlacement(); + const char *getCustomHTML(); + + private: + + EMParam_Data _EMParam_data; + + const char *_customHTML; + + void init(const char *id, const char *placeholder, const char *defaultValue, const int& length, + const char *custom, const int& labelPlacement); + + friend class ESP32_ENC_Manager; +}; + +//////////////////////////////////////////////////// + +#define USE_DYNAMIC_PARAMS true +#define DEFAULT_PORTAL_TIMEOUT 60000L + +// To permit disable/enable StaticIP configuration in Config Portal from sketch. Valid only if DHCP is used. +// You have to explicitly specify false to disable the feature. +#ifndef USE_STATIC_IP_CONFIG_IN_CP + #define USE_STATIC_IP_CONFIG_IN_CP true +#endif + +//////////////////////////////////////////////////// +//////////////////////////////////////////////////// + +class ESP32_ENC_Manager +{ + public: + + ESP32_ENC_Manager(const char *iHostname = ""); + + ~ESP32_ENC_Manager(); + + // If you want to start the config portal + bool startConfigPortal(); + + //sets timeout before webserver loop ends and exits even if there has been no setup. + //usefully for devices that failed to connect at some point and got stuck in a webserver loop + //in seconds setConfigPortalTimeout is a new name for setTimeout + void setConfigPortalTimeout(const unsigned long& seconds); + void setTimeout(const unsigned long& seconds); + + //sets timeout for which to attempt connecting, usefull if you get a lot of failed connects + void setConnectTimeout(const unsigned long& seconds); + + void setDebugOutput(bool debug); + + //sets config for a static IP + void setSTAStaticIPConfig(const IPAddress& ip, const IPAddress& gw, const IPAddress& sn); + + void setSTAStaticIPConfig(const ETH_STA_IPConfig& EM_STA_IPconfig); + void getSTAStaticIPConfig(ETH_STA_IPConfig& EM_STA_IPconfig); + +#if USE_CONFIGURABLE_DNS + void setSTAStaticIPConfig(const IPAddress& ip, const IPAddress& gw, const IPAddress& sn, + const IPAddress& dns_address_1, const IPAddress& dns_address_2); +#endif + + //called when settings have been changed and connection was successful + void setSaveConfigCallback(void(*func)()); + +#if USE_DYNAMIC_PARAMS + //adds a custom parameter + bool addParameter(ESP32_EMParameter *p); +#else + //adds a custom parameter + void addParameter(ESP32_EMParameter *p); +#endif + + //if this is set, it will exit after config, even if connection is unsucessful. + void setBreakAfterConfig(bool shouldBreak); + + //if this is set, try WPS setup when starting (this will delay config portal for up to 2 mins) + //TODO + //if this is set, customise style + void setCustomHeadElement(const char* element); + +//////////////////////////////////////////////////// + + // For configuring CORS Header, default to EM_HTTP_CORS_ALLOW_ALL = "*" +#if USING_CORS_FEATURE + void setCORSHeader(const char* CORSHeaders) + { + _CORS_Header = CORSHeaders; + + LOGWARN1(F("Set CORS Header to : "), _CORS_Header); + } + + /////////////////////////// + + inline const char* getCORSHeader() + { + return _CORS_Header; + } +#endif + + /////////////////////////// + + //returns the list of Parameters + ESP32_EMParameter** getParameters(); + + // returns the Parameters Count + int getParametersCount(); + + /////////////////////////// + + void setHostname() + { + if (RFC952_hostname[0] != 0) + { + ETH.setHostname(RFC952_hostname); + } + } + +//////////////////////////////////////////////////// + +#if USE_ESP_ETH_MANAGER_NTP + + inline String getTimezoneName() + { + return _timezoneName; + } + + /////////////////////////// + + inline void setTimezoneName(const String& inTimezoneName) + { + _timezoneName = inTimezoneName; + } + + /////////////////////////// + + //See: https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html + // EST5EDT,M3.2.0,M11.1.0 (for America/New_York) + // EST5EDT is the name of the time zone + // EST is the abbreviation used when DST is off + // 6 hours is the time difference from GMT + // EDT is the abbreviation used when DST is on + // ,M3 is the third month + // .2 is the second occurrence of the day in the month + // .0 is Sunday + // ,M11 is the eleventh month + // .1 is the first occurrence of the day in the month + // .0 is Sunday + + const char * getTZ(const char * timezoneName) + { + //const char TZ_NAME[][TIMEZONE_MAX_LEN] + for (uint16_t index = 0; index < sizeof(TZ_NAME) / TIMEZONE_MAX_LEN; index++) + { + if ( !strncmp(timezoneName, (TZ_NAME[index]), strlen((TZ_NAME[index])) ) ) + { + yield(); + + return (ESP_TZ_NAME[index]); + } + } + + return ""; + } + + /////////////////////////// + + const char * getTZ(const String& timezoneName) + { + return getTZ(timezoneName.c_str()); + } + + /////////////////////////// + +#endif + + private: + + std::unique_ptr dnsServer; + + std::unique_ptr server; + + bool needInfo = true; + String pager; + wl_status_t ethStatus; + +#define RFC952_HOSTNAME_MAXLEN 24 + + char RFC952_hostname[RFC952_HOSTNAME_MAXLEN + 1]; + + char* getRFC952_hostname(const char* iHostname); + + void setupConfigPortal(); + void startWPS(); + + //////////////////////////////////////////////////// + +#if USE_ESP_ETH_MANAGER_NTP + // Timezone info + String _timezoneName = ""; +#endif + + //////////////////////////////////////////////////// + + unsigned long _configPortalTimeout = 0; + + unsigned long _connectTimeout = 0; + unsigned long _configPortalStart = 0; + + //////////////////////////////////////////////////// + + ETH_STA_IPConfig _ETH_STA_IPconfig = { IPAddress(0, 0, 0, 0), IPAddress(192, 168, 2, 1), IPAddress(255, 255, 255, 0), + IPAddress(192, 168, 2, 1), IPAddress(8, 8, 8, 8) }; + + //////////////////////////////////////////////////// + + int _paramsCount = 0; + int _minimumQuality = -1; + bool _removeDuplicateAPs = true; + bool _shouldBreakAfterConfig = false; + bool _tryWPS = false; + + const char* _customHeadElement = ""; + + int status = WL_IDLE_STATUS; + + // For configuring CORS Header, default to EM_HTTP_CORS_ALLOW_ALL = "*" +#if USING_CORS_FEATURE + const char* _CORS_Header = EM_HTTP_CORS_ALLOW_ALL; //"*"; +#endif + + wl_status_t waitForConnectResult(); + + void setInfo(); + String networkListAsString(); + + void handleRoot(); + void handleETH(); + void handleETHSave(); + void handleServerClose(); + void handleInfo(); + void handleState(); + void handleReset(); + void handleNotFound(); + bool captivePortal(); + + void reportStatus(String& page); + + // DNS server + const byte DNS_PORT = 53; + + //helpers + bool isIp(const String& str); + String toStringIp(const IPAddress& ip); + + bool connect; + bool stopConfigPortal = false; + + bool _debug = false; //true; + + void(*_savecallback)() = NULL; + + //////////////////////////////////////////////////// + +#if USE_DYNAMIC_PARAMS + int _max_params; + ESP32_EMParameter** _params; +#else + ESP32_EMParameter* _params[ETH_MANAGER_MAX_PARAMS]; +#endif + + //////////////////////////////////////////////////// + + template + auto optionalIPFromString(T *obj, const char *s) -> decltype(obj->fromString(s)) + { + return obj->fromString(s); + } + + /////////////////////////// + + auto optionalIPFromString(...) -> bool + { + LOGINFO("No IPAddress.fromString(), use ESP8266 core 2.1.0+ for Custom IP configuration to work."); + + return false; + } + + /////////////////////////// + +}; + +#endif // ESP32_ENC_Manager_hpp + diff --git a/src/ESP32_ENC_Manager_Debug.h b/src/ESP32_ENC_Manager_Debug.h new file mode 100644 index 0000000..c02277f --- /dev/null +++ b/src/ESP32_ENC_Manager_Debug.h @@ -0,0 +1,91 @@ +/**************************************************************************************************************************** + ESP32_ENC_Manager_Debug.h + + For Ethernet shields using ESP32_ENC (ESP32 + LwIP ENC28J60) + + WebServer_ESP32_ENC is a library for the ESP32 with Ethernet ENC28J60 to run WebServer + + Modified from + 1. Tzapu (https://github.com/tzapu/WiFiManager) + 2. Ken Taylor (https://github.com/kentaylor) + 3. Khoi Hoang (https://github.com/khoih-prog/ESP_WiFiManager) + + Built by Khoi Hoang https://github.com/khoih-prog/ESP32_ENC_Manager + Licensed under MIT license + + Version: 1.0.0 + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 11/12/2022 Initial coding for ESP32_ENC + *****************************************************************************************************************************/ + +#pragma once + +#ifndef ESP32_ENC_Manager_Debug_H +#define ESP32_ENC_Manager_Debug_H + +#ifdef ESP32_ETH_MGR_DEBUG_PORT + #define DBG_PORT_ESP_EM ESP32_ETH_MGR_DEBUG_PORT +#else + #define DBG_PORT_ESP_EM Serial +#endif + +// Change _ESP32_ETH_MGR_LOGLEVEL_ to set tracing and logging verbosity +// 0: DISABLED: no logging +// 1: ERROR: errors +// 2: WARN: errors and warnings +// 3: INFO: errors, warnings and informational (default) +// 4: DEBUG: errors, warnings, informational and debug + +#ifndef _ESP32_ETH_MGR_LOGLEVEL_ + #define _ESP32_ETH_MGR_LOGLEVEL_ 1 +#endif + +///////////////////////////////////////////////////////// + +const char ESP_EM_MARK[] = "[EM] "; +const char ESP_EM_SP[] = " "; + +#define ESP_EM_PRINT DBG_PORT_ESP_EM.print +#define ESP_EM_PRINTLN DBG_PORT_ESP_EM.println + +#define ESP_EM_PRINT_MARK ESP_EM_PRINT(ESP_EM_MARK) +#define ESP_EM_PRINT_SP ESP_EM_PRINT(ESP_EM_SP) + +///////////////////////////////////////////////////////// + +#define LOGERROR(x) if(_ESP32_ETH_MGR_LOGLEVEL_>0) { ESP_EM_PRINT_MARK; ESP_EM_PRINTLN(x); } +#define LOGERROR0(x) if(_ESP32_ETH_MGR_LOGLEVEL_>0) { ESP_EM_PRINT(x); } +#define LOGERROR1(x,y) if(_ESP32_ETH_MGR_LOGLEVEL_>0) { ESP_EM_PRINT_MARK; ESP_EM_PRINT(x); ESP_EM_PRINT_SP; ESP_EM_PRINTLN(y); } +#define LOGERROR2(x,y,z) if(_ESP32_ETH_MGR_LOGLEVEL_>0) { ESP_EM_PRINT_MARK; ESP_EM_PRINT(x); ESP_EM_PRINT_SP; ESP_EM_PRINT(y); ESP_EM_PRINT_SP; ESP_EM_PRINTLN(z); } +#define LOGERROR3(x,y,z,w) if(_ESP32_ETH_MGR_LOGLEVEL_>0) { ESP_EM_PRINT_MARK; ESP_EM_PRINT(x); ESP_EM_PRINT_SP; ESP_EM_PRINT(y); ESP_EM_PRINT_SP; ESP_EM_PRINT(z); ESP_EM_PRINT_SP; ESP_EM_PRINTLN(w); } + +///////////////////////////////////////////////////////// + +#define LOGWARN(x) if(_ESP32_ETH_MGR_LOGLEVEL_>1) { ESP_EM_PRINT_MARK; ESP_EM_PRINTLN(x); } +#define LOGWARN0(x) if(_ESP32_ETH_MGR_LOGLEVEL_>1) { ESP_EM_PRINT(x); } +#define LOGWARN1(x,y) if(_ESP32_ETH_MGR_LOGLEVEL_>1) { ESP_EM_PRINT_MARK; ESP_EM_PRINT(x); ESP_EM_PRINT_SP; ESP_EM_PRINTLN(y); } +#define LOGWARN2(x,y,z) if(_ESP32_ETH_MGR_LOGLEVEL_>1) { ESP_EM_PRINT_MARK; ESP_EM_PRINT(x); ESP_EM_PRINT_SP; ESP_EM_PRINT(y); ESP_EM_PRINT_SP; ESP_EM_PRINTLN(z); } +#define LOGWARN3(x,y,z,w) if(_ESP32_ETH_MGR_LOGLEVEL_>1) { ESP_EM_PRINT_MARK; ESP_EM_PRINT(x); ESP_EM_PRINT_SP; ESP_EM_PRINT(y); ESP_EM_PRINT_SP; ESP_EM_PRINT(z); ESP_EM_PRINT_SP; ESP_EM_PRINTLN(w); } + +///////////////////////////////////////////////////////// + +#define LOGINFO(x) if(_ESP32_ETH_MGR_LOGLEVEL_>2) { ESP_EM_PRINT_MARK; ESP_EM_PRINTLN(x); } +#define LOGINFO0(x) if(_ESP32_ETH_MGR_LOGLEVEL_>2) { ESP_EM_PRINT(x); } +#define LOGINFO1(x,y) if(_ESP32_ETH_MGR_LOGLEVEL_>2) { ESP_EM_PRINT_MARK; ESP_EM_PRINT(x); ESP_EM_PRINT_SP; ESP_EM_PRINTLN(y); } +#define LOGINFO2(x,y,z) if(_ESP32_ETH_MGR_LOGLEVEL_>2) { ESP_EM_PRINT_MARK; ESP_EM_PRINT(x); ESP_EM_PRINT_SP; ESP_EM_PRINT(y); ESP_EM_PRINT_SP; ESP_EM_PRINTLN(z); } +#define LOGINFO3(x,y,z,w) if(_ESP32_ETH_MGR_LOGLEVEL_>2) { ESP_EM_PRINT_MARK; ESP_EM_PRINT(x); ESP_EM_PRINT_SP; ESP_EM_PRINT(y); ESP_EM_PRINT_SP; ESP_EM_PRINT(z); ESP_EM_PRINT_SP; ESP_EM_PRINTLN(w); } + +///////////////////////////////////////////////////////// + +#define LOGDEBUG(x) if(_ESP32_ETH_MGR_LOGLEVEL_>3) { ESP_EM_PRINT_MARK; ESP_EM_PRINTLN(x); } +#define LOGDEBUG0(x) if(_ESP32_ETH_MGR_LOGLEVEL_>3) { ESP_EM_PRINT(x); } +#define LOGDEBUG1(x,y) if(_ESP32_ETH_MGR_LOGLEVEL_>3) { ESP_EM_PRINT_MARK; ESP_EM_PRINT(x); ESP_EM_PRINT_SP; ESP_EM_PRINTLN(y); } +#define LOGDEBUG2(x,y,z) if(_ESP32_ETH_MGR_LOGLEVEL_>3) { ESP_EM_PRINT_MARK; ESP_EM_PRINT(x); ESP_EM_PRINT_SP; ESP_EM_PRINT(y); ESP_EM_PRINT_SP; ESP_EM_PRINTLN(z); } +#define LOGDEBUG3(x,y,z,w) if(_ESP32_ETH_MGR_LOGLEVEL_>3) { ESP_EM_PRINT_MARK; ESP_EM_PRINT(x); ESP_EM_PRINT_SP; ESP_EM_PRINT(y); ESP_EM_PRINT_SP; ESP_EM_PRINT(z); ESP_EM_PRINT_SP; ESP_EM_PRINTLN(w); } + +///////////////////////////////////////////////////////// + +#endif // ESP32_ENC_Manager_Debug_H + diff --git a/src/ESP32_ENC_Manager_Impl.h b/src/ESP32_ENC_Manager_Impl.h new file mode 100644 index 0000000..e0b33f1 --- /dev/null +++ b/src/ESP32_ENC_Manager_Impl.h @@ -0,0 +1,1219 @@ +/**************************************************************************************************************************** + ESP32_ENC_Manager_Impl.h + + For Ethernet shields using ESP32_ENC (ESP32 + LwIP ENC28J60) + + WebServer_ESP32_ENC is a library for the ESP32 with Ethernet ENC28J60 to run WebServer + + Modified from + 1. Tzapu (https://github.com/tzapu/WiFiManager) + 2. Ken Taylor (https://github.com/kentaylor) + 3. Khoi Hoang (https://github.com/khoih-prog/ESP_WiFiManager) + + Built by Khoi Hoang https://github.com/khoih-prog/ESP32_ENC_Manager + Licensed under MIT license + + Version: 1.0.0 + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 11/12/2022 Initial coding for ESP32_ENC + *****************************************************************************************************************************/ + +#pragma once + +#ifndef ESP32_ENC_Manager_Impl_h +#define ESP32_ENC_Manager_Impl_h + +////////////////////////////////////////// + +ESP32_EMParameter::ESP32_EMParameter(const char *custom) +{ + _EMParam_data._id = NULL; + _EMParam_data._placeholder = NULL; + _EMParam_data._length = 0; + _EMParam_data._value = NULL; + _EMParam_data._labelPlacement = WFM_LABEL_BEFORE; + + _customHTML = custom; +} + +////////////////////////////////////////// + +ESP32_EMParameter::ESP32_EMParameter(const char *id, const char *placeholder, const char *defaultValue, + const int& length, const char *custom, const int& labelPlacement) +{ + init(id, placeholder, defaultValue, length, custom, labelPlacement); +} + +////////////////////////////////////////// + +// KH, using struct +ESP32_EMParameter::ESP32_EMParameter(const EMParam_Data& EMParam_data) +{ + init(EMParam_data._id, EMParam_data._placeholder, EMParam_data._value, + EMParam_data._length, "", EMParam_data._labelPlacement); +} + +////////////////////////////////////////// + +void ESP32_EMParameter::init(const char *id, const char *placeholder, const char *defaultValue, + const int& length, const char *custom, const int& labelPlacement) +{ + _EMParam_data._id = id; + _EMParam_data._placeholder = placeholder; + _EMParam_data._length = length; + _EMParam_data._labelPlacement = labelPlacement; + + _EMParam_data._value = new char[_EMParam_data._length + 1]; + + if (_EMParam_data._value != NULL) + { + memset(_EMParam_data._value, 0, _EMParam_data._length + 1); + + if (defaultValue != NULL) + { + strncpy(_EMParam_data._value, defaultValue, _EMParam_data._length); + } + } + + _customHTML = custom; +} + +////////////////////////////////////////// + +ESP32_EMParameter::~ESP32_EMParameter() +{ + if (_EMParam_data._value != NULL) + { + delete[] _EMParam_data._value; + } +} + +////////////////////////////////////////// + +// Using Struct to get/set whole data at once +void ESP32_EMParameter::setEMParam_Data(const EMParam_Data& EMParam_data) +{ + LOGINFO(F("setEMParam_Data")); + + memcpy(&_EMParam_data, &EMParam_data, sizeof(_EMParam_data)); +} + +////////////////////////////////////////// + +void ESP32_EMParameter::getEMParam_Data(EMParam_Data& EMParam_data) +{ + LOGINFO(F("getEMParam_Data")); + + memcpy(&EMParam_data, &_EMParam_data, sizeof(EMParam_data)); +} + +////////////////////////////////////////// + +const char* ESP32_EMParameter::getValue() +{ + return _EMParam_data._value; +} + +////////////////////////////////////////// + +const char* ESP32_EMParameter::getID() +{ + return _EMParam_data._id; +} + +////////////////////////////////////////// + +const char* ESP32_EMParameter::getPlaceholder() +{ + return _EMParam_data._placeholder; +} + +////////////////////////////////////////// + +int ESP32_EMParameter::getValueLength() +{ + return _EMParam_data._length; +} + +////////////////////////////////////////// + +int ESP32_EMParameter::getLabelPlacement() +{ + return _EMParam_data._labelPlacement; +} + +////////////////////////////////////////// + +const char* ESP32_EMParameter::getCustomHTML() +{ + return _customHTML; +} + +////////////////////////////////////////// + +/** + [getParameters description] + @access public +*/ +ESP32_EMParameter** ESP32_ENC_Manager::getParameters() +{ + return _params; +} + +////////////////////////////////////////// +////////////////////////////////////////// + +/** + [getParametersCount description] + @access public +*/ +int ESP32_ENC_Manager::getParametersCount() +{ + return _paramsCount; +} + +////////////////////////////////////////// + +char* ESP32_ENC_Manager::getRFC952_hostname(const char* iHostname) +{ + memset(RFC952_hostname, 0, sizeof(RFC952_hostname)); + + size_t len = (RFC952_HOSTNAME_MAXLEN < strlen(iHostname)) ? RFC952_HOSTNAME_MAXLEN : strlen(iHostname); + + size_t j = 0; + + for (size_t i = 0; i < len - 1; i++) + { + if (isalnum(iHostname[i]) || iHostname[i] == '-') + { + RFC952_hostname[j] = iHostname[i]; + j++; + } + } + + // no '-' as last char + if (isalnum(iHostname[len - 1]) || (iHostname[len - 1] != '-')) + RFC952_hostname[j] = iHostname[len - 1]; + + return RFC952_hostname; +} + +////////////////////////////////////////// + +ESP32_ENC_Manager::ESP32_ENC_Manager(const char *iHostname) +{ + + //server = webserver; + //dnsServer = dnsserver; + +#if USE_DYNAMIC_PARAMS + _max_params = ETH_MANAGER_MAX_PARAMS; + _params = (ESP32_EMParameter**) malloc(_max_params * sizeof(ESP32_EMParameter*)); +#endif + + if (iHostname[0] == 0) + { + String _hostname = "ESP32-" + String(ESP_getChipId(), HEX); + + _hostname.toUpperCase(); + + getRFC952_hostname(_hostname.c_str()); + + } + else + { + // Prepare and store the hostname only not NULL + getRFC952_hostname(iHostname); + } + + LOGWARN1(F("RFC925 Hostname ="), RFC952_hostname); + + setHostname(); +} + +////////////////////////////////////////// + +ESP32_ENC_Manager::~ESP32_ENC_Manager() +{ +#if USE_DYNAMIC_PARAMS + + if (_params != NULL) + { + LOGINFO(F("freeing allocated params!")); + + free(_params); + } + +#endif +} + +////////////////////////////////////////// + +#if USE_DYNAMIC_PARAMS + bool ESP32_ENC_Manager::addParameter(ESP32_EMParameter *p) +#else + void ESP32_ENC_Manager::addParameter(ESP32_EMParameter *p) +#endif +{ +#if USE_DYNAMIC_PARAMS + + if (_paramsCount == _max_params) + { + // rezise the params array + _max_params += ETH_MANAGER_MAX_PARAMS; + + LOGINFO1(F("Increasing _max_params to:"), _max_params); + + ESP32_EMParameter** new_params = (ESP32_EMParameter**) realloc(_params, _max_params * sizeof(ESP32_EMParameter*)); + + if (new_params != NULL) + { + _params = new_params; + } + else + { + LOGINFO(F("ERROR: failed to realloc params, size not increased!")); + + return false; + } + } + + _params[_paramsCount] = p; + _paramsCount++; + + LOGINFO1(F("Adding parameter"), p->getID()); + + return true; + +#else + + // Danger here. Better to use Tzapu way here + if (_paramsCount < (ETH_MANAGER_MAX_PARAMS)) + { + _params[_paramsCount] = p; + _paramsCount++; + + LOGINFO1(F("Adding parameter"), p->getID()); + } + else + { + LOGINFO("Can't add parameter. Full"); + } + +#endif +} + +////////////////////////////////////////// + +void ESP32_ENC_Manager::setupConfigPortal() +{ + stopConfigPortal = false; //Signal not to close config portal + + dnsServer.reset(new DNSServer()); + + server.reset(new WebServer(HTTP_PORT_TO_USE)); + + /* Setup the DNS server redirecting all the domains to the apIP */ + if (dnsServer) + { + dnsServer->setErrorReplyCode(DNSReplyCode::NoError); + + // AsyncDNSServer started with "*" domain name, all DNS requests will be passsed to ETH.localIP() + if (! dnsServer->start(DNS_PORT, "*", ETH.localIP())) + { + // No socket available + LOGERROR(F("Can't start DNS Server. No available socket")); + } + } + else + { + // No space available + LOGERROR(F("Can't initiate DNS Server. No enough space")); + } + + _configPortalStart = millis(); + + LOGDEBUG1(F("_configPortalStart millis() ="), millis()); + + LOGWARN1(F("Config Portal IP address ="), ETH.localIP()); + + /* Setup web pages: root, eth config pages, SO captive portal detectors and not found. */ + + server->on("/", std::bind(&ESP32_ENC_Manager::handleRoot, this)); + server->on("/eth", std::bind(&ESP32_ENC_Manager::handleETH, this)); + server->on("/ethsave", std::bind(&ESP32_ENC_Manager::handleETHSave, this)); + server->on("/close", std::bind(&ESP32_ENC_Manager::handleServerClose, this)); + server->on("/i", std::bind(&ESP32_ENC_Manager::handleInfo, this)); + server->on("/r", std::bind(&ESP32_ENC_Manager::handleReset, this)); + server->on("/state", std::bind(&ESP32_ENC_Manager::handleState, this)); + //Microsoft captive portal. Maybe not needed. Might be handled by notFound handler. + server->on("/fwlink", std::bind(&ESP32_ENC_Manager::handleRoot, this)); + server->onNotFound( std::bind(&ESP32_ENC_Manager::handleNotFound, this)); + + server->begin(); // Web server start + + LOGWARN(F("HTTP server started")); +} + +////////////////////////////////////////// + +bool ESP32_ENC_Manager::startConfigPortal() +{ + connect = false; + + setupConfigPortal(); + + bool TimedOut = true; + + LOGINFO("startConfigPortal : Enter loop"); + + while (true) + { + //DNS + dnsServer->processNextRequest(); + //HTTP + server->handleClient(); + +#if ( USING_ESP32_S2 || USING_ESP32_C3 ) + // Fix ESP32-S2 issue with WebServer (https://github.com/espressif/arduino-esp32/issues/4348) + delay(1); +#endif + + if (connect) + { + TimedOut = false; + + if (_shouldBreakAfterConfig) + { + //flag set to exit after config after trying to connect + //notify that configuration has changed and any optional parameters should be saved + if (_savecallback != NULL) + { + //todo: check if any custom parameters actually exist, and check if they really changed maybe + _savecallback(); + } + + LOGDEBUG("Stop ConfigPortal: _shouldBreakAfterConfig"); + + break; + } + } + + if (stopConfigPortal) + { + TimedOut = false; + + LOGERROR("stopConfigPortal"); + + stopConfigPortal = false; + + break; + } + + if (_configPortalTimeout > 0 && ( millis() > _configPortalStart + _configPortalTimeout) ) + { + //LOGDEBUG3("startConfigPortal: timeout, _configPortalTimeout =", _configPortalTimeout, "millis() =", millis()); + + stopConfigPortal = false; + + break; + } + +#define TIME_BETWEEN_CONFIG_PORTAL_LOOP 50 + + vTaskDelay(TIME_BETWEEN_CONFIG_PORTAL_LOOP / portTICK_PERIOD_MS); + } + + //LOGDEBUG3("startConfigPortal: exit, _configPortalTimeout =", _configPortalTimeout, "millis() =", millis()); + + server->stop(); + server.reset(); + dnsServer->stop(); + dnsServer.reset(); + + return (ESP32_ENC_isConnected()); +} + +////////////////////////////////////////// + +void ESP32_ENC_Manager::setTimeout(const unsigned long& seconds) +{ + setConfigPortalTimeout(seconds); +} + +////////////////////////////////////////// + +void ESP32_ENC_Manager::setConfigPortalTimeout(const unsigned long& seconds) +{ + _configPortalTimeout = seconds * 1000; +} + +////////////////////////////////////////// + +void ESP32_ENC_Manager::setConnectTimeout(const unsigned long& seconds) +{ + _connectTimeout = seconds * 1000; +} + +void ESP32_ENC_Manager::setDebugOutput(bool debug) +{ + _debug = debug; +} + +////////////////////////////////////////// + +void ESP32_ENC_Manager::setBreakAfterConfig(bool shouldBreak) +{ + _shouldBreakAfterConfig = shouldBreak; +} + +////////////////////////////////////////// + +void ESP32_ENC_Manager::reportStatus(String& page) +{ + page += FPSTR(EM_HTTP_SCRIPT_NTP_MSG); +} + + + +////////////////////////////////////////// + +void ESP32_ENC_Manager::setSTAStaticIPConfig(const IPAddress& ip, const IPAddress& gw, const IPAddress& sn) +{ + LOGINFO(F("setSTAStaticIPConfig")); + + _ETH_STA_IPconfig._sta_static_ip = ip; + _ETH_STA_IPconfig._sta_static_gw = gw; + _ETH_STA_IPconfig._sta_static_sn = sn; +} + +////////////////////////////////////////// + +void ESP32_ENC_Manager::setSTAStaticIPConfig(const ETH_STA_IPConfig& EM_STA_IPconfig) +{ + LOGINFO(F("setSTAStaticIPConfig")); + + memcpy((void *) &_ETH_STA_IPconfig, &EM_STA_IPconfig, sizeof(_ETH_STA_IPconfig)); +} + +////////////////////////////////////////// + +void ESP32_ENC_Manager::getSTAStaticIPConfig(ETH_STA_IPConfig& EM_STA_IPconfig) +{ + LOGINFO(F("getSTAStaticIPConfig")); + + memcpy((void *) &EM_STA_IPconfig, &_ETH_STA_IPconfig, sizeof(EM_STA_IPconfig)); +} + + +////////////////////////////////////////// + +#if USE_CONFIGURABLE_DNS +void ESP32_ENC_Manager::setSTAStaticIPConfig(const IPAddress& ip, const IPAddress& gw, const IPAddress& sn, + const IPAddress& dns_address_1, const IPAddress& dns_address_2) +{ + LOGINFO(F("setSTAStaticIPConfig for USE_CONFIGURABLE_DNS")); + + _ETH_STA_IPconfig._sta_static_ip = ip; + _ETH_STA_IPconfig._sta_static_gw = gw; + _ETH_STA_IPconfig._sta_static_sn = sn; + _ETH_STA_IPconfig._sta_static_dns1 = dns_address_1; //***** Added argument ***** + _ETH_STA_IPconfig._sta_static_dns2 = dns_address_2; //***** Added argument ***** +} +#endif + +////////////////////////////////////////// + +// Handle root or redirect to captive portal +void ESP32_ENC_Manager::handleRoot() +{ + LOGDEBUG(F("handleRoot")); + + // Disable _configPortalTimeout when someone accessing Portal to give some time to config + _configPortalTimeout = 0; + + if (captivePortal()) + { + LOGDEBUG(F("handleRoot: captive portal exit")); + + // If captive portal redirect instead of displaying the error page. + return; + } + + server->sendHeader(FPSTR(EM_HTTP_CACHE_CONTROL), FPSTR(EM_HTTP_NO_STORE)); + +#if USING_CORS_FEATURE + // For configure CORS Header, default to EM_HTTP_CORS_ALLOW_ALL = "*" + server->sendHeader(FPSTR(EM_HTTP_CORS), _CORS_Header); +#endif + + server->sendHeader(FPSTR(EM_HTTP_PRAGMA), FPSTR(EM_HTTP_NO_CACHE)); + server->sendHeader(FPSTR(EM_HTTP_EXPIRES), "-1"); + + String page = FPSTR(EM_HTTP_HEAD_START); + + page.replace("{v}", "Options"); + page += FPSTR(EM_HTTP_SCRIPT); + page += FPSTR(EM_HTTP_SCRIPT_NTP); + page += FPSTR(EM_HTTP_STYLE); + page += _customHeadElement; + page += FPSTR(EM_HTTP_HEAD_END); + + page += FPSTR(EM_HTTP_PORTAL_OPTIONS); + page += F("
"); + reportStatus(page); + page += F("
"); + page += FPSTR(EM_HTTP_END); + + server->send(200, "text/html", page); +} + +////////////////////////////////////////// + +// ETH config page handler +void ESP32_ENC_Manager::handleETH() +{ + LOGDEBUG(F("Handle ETH")); + + // Disable _configPortalTimeout when someone accessing Portal to give some time to config + _configPortalTimeout = 0; + + server->sendHeader(FPSTR(EM_HTTP_CACHE_CONTROL), FPSTR(EM_HTTP_NO_STORE)); + +#if USING_CORS_FEATURE + // For configure CORS Header, default to EM_HTTP_CORS_ALLOW_ALL = "*" + server->sendHeader(FPSTR(EM_HTTP_CORS), _CORS_Header); +#endif + + server->sendHeader(FPSTR(EM_HTTP_PRAGMA), FPSTR(EM_HTTP_NO_CACHE)); + server->sendHeader(FPSTR(EM_HTTP_EXPIRES), "-1"); + + String page = FPSTR(EM_HTTP_HEAD_START); + + page.replace("{v}", "Config ESP"); + page += FPSTR(EM_HTTP_SCRIPT); + page += FPSTR(EM_HTTP_SCRIPT_NTP); + page += FPSTR(EM_HTTP_STYLE); + page += _customHeadElement; + page += FPSTR(EM_HTTP_HEAD_END); + page += F("

Configuration

"); + + page += FPSTR(EM_HTTP_FORM_START); + + char parLength[2]; + + page += FPSTR(EM_FLDSET_START); + + // add the extra parameters to the form + for (int i = 0; i < _paramsCount; i++) + { + if (_params[i] == NULL) + { + break; + } + + String pitem; + + switch (_params[i]->getLabelPlacement()) + { + case WFM_LABEL_BEFORE: + pitem = FPSTR(EM_HTTP_FORM_LABEL_BEFORE); + break; + + case WFM_LABEL_AFTER: + pitem = FPSTR(EM_HTTP_FORM_LABEL_AFTER); + break; + + default: + // WFM_NO_LABEL + pitem = FPSTR(EM_HTTP_FORM_PARAM); + break; + } + + if (_params[i]->getID() != NULL) + { + pitem.replace("{i}", _params[i]->getID()); + pitem.replace("{n}", _params[i]->getID()); + pitem.replace("{p}", _params[i]->getPlaceholder()); + + snprintf(parLength, 2, "%d", _params[i]->getValueLength()); + + pitem.replace("{l}", parLength); + pitem.replace("{v}", _params[i]->getValue()); + pitem.replace("{c}", _params[i]->getCustomHTML()); + } + else + { + pitem = _params[i]->getCustomHTML(); + } + + page += pitem; + } + + if (_paramsCount > 0) + { + page += FPSTR(EM_FLDSET_END); + } + + if (_params[0] != NULL) + { + page += "
"; + } + + LOGDEBUG1(F("Static IP ="), _ETH_STA_IPconfig._sta_static_ip.toString()); + + // KH, Comment out to permit changing from DHCP to static IP, or vice versa + // and add staticIP label in CP + + // To permit disable/enable StaticIP configuration in Config Portal from sketch. Valid only if DHCP is used. + // You'll loose the feature of dynamically changing from DHCP to static IP, or vice versa + // You have to explicitly specify false to disable the feature. + +#if !USE_STATIC_IP_CONFIG_IN_CP + + if (_ETH_STA_IPconfig._sta_static_ip) +#endif + { + page += FPSTR(EM_FLDSET_START); + + String item = FPSTR(EM_HTTP_FORM_LABEL); + + item += FPSTR(EM_HTTP_FORM_PARAM); + + item.replace("{i}", "ip"); + item.replace("{n}", "ip"); + item.replace("{p}", "Static IP"); + item.replace("{l}", "15"); + item.replace("{v}", _ETH_STA_IPconfig._sta_static_ip.toString()); + + page += item; + + item = FPSTR(EM_HTTP_FORM_LABEL); + item += FPSTR(EM_HTTP_FORM_PARAM); + + item.replace("{i}", "gw"); + item.replace("{n}", "gw"); + item.replace("{p}", "Gateway IP"); + item.replace("{l}", "15"); + item.replace("{v}", _ETH_STA_IPconfig._sta_static_gw.toString()); + + page += item; + + item = FPSTR(EM_HTTP_FORM_LABEL); + item += FPSTR(EM_HTTP_FORM_PARAM); + + item.replace("{i}", "sn"); + item.replace("{n}", "sn"); + item.replace("{p}", "Subnet"); + item.replace("{l}", "15"); + item.replace("{v}", _ETH_STA_IPconfig._sta_static_sn.toString()); + +#if USE_CONFIGURABLE_DNS + //***** Added for DNS address options ***** + page += item; + + item = FPSTR(EM_HTTP_FORM_LABEL); + item += FPSTR(EM_HTTP_FORM_PARAM); + + item.replace("{i}", "dns1"); + item.replace("{n}", "dns1"); + item.replace("{p}", "DNS1 IP"); + item.replace("{l}", "15"); + item.replace("{v}", _ETH_STA_IPconfig._sta_static_dns1.toString()); + + page += item; + + item = FPSTR(EM_HTTP_FORM_LABEL); + item += FPSTR(EM_HTTP_FORM_PARAM); + + item.replace("{i}", "dns2"); + item.replace("{n}", "dns2"); + item.replace("{p}", "DNS2 IP"); + item.replace("{l}", "15"); + item.replace("{v}", _ETH_STA_IPconfig._sta_static_dns2.toString()); + //***** End added for DNS address options ***** +#endif + + page += item; + + page += FPSTR(EM_FLDSET_END); + + page += "
"; + } + + page += FPSTR(EM_HTTP_SCRIPT_NTP_HIDDEN); + + page += FPSTR(EM_HTTP_FORM_END); + + page += FPSTR(EM_HTTP_END); + + server->send(200, "text/html", page); + + LOGDEBUG(F("Sent config page")); +} + +////////////////////////////////////////// + +// Handle the WLAN save form and redirect to WLAN config page again +void ESP32_ENC_Manager::handleETHSave() +{ + LOGDEBUG(F("ETH save")); + +#if USING_CORS_FEATURE + // For configuring CORS Header, default to EM_HTTP_CORS_ALLOW_ALL = "*" + server->sendHeader(FPSTR(EM_HTTP_CORS), _CORS_Header); +#endif + +#if USE_ESP_ETH_MANAGER_NTP + + if (server->arg("timezone") != "") + { + _timezoneName = server->arg("timezone"); + LOGDEBUG1(F("TZ name ="), _timezoneName); + } + else + { + LOGDEBUG(F("No TZ arg")); + } + +#endif + + /////////////////////// + + //parameters + for (int i = 0; i < _paramsCount; i++) + { + if (_params[i] == NULL) + { + break; + } + + //read parameter + String value = server->arg(_params[i]->getID()).c_str(); + + //store it in array + value.toCharArray(_params[i]->_EMParam_data._value, _params[i]->_EMParam_data._length); + + LOGDEBUG2(F("Parameter and value :"), _params[i]->getID(), value); + } + + + if (server->arg("ip") != "") + { + String ip = server->arg("ip"); + + optionalIPFromString(&_ETH_STA_IPconfig._sta_static_ip, ip.c_str()); + + LOGDEBUG1(F("New Static IP ="), _ETH_STA_IPconfig._sta_static_ip.toString()); + } + + if (server->arg("gw") != "") + { + String gw = server->arg("gw"); + + optionalIPFromString(&_ETH_STA_IPconfig._sta_static_gw, gw.c_str()); + + LOGDEBUG1(F("New Static Gateway ="), _ETH_STA_IPconfig._sta_static_gw.toString()); + } + + if (server->arg("sn") != "") + { + String sn = server->arg("sn"); + + optionalIPFromString(&_ETH_STA_IPconfig._sta_static_sn, sn.c_str()); + + LOGDEBUG1(F("New Static Netmask ="), _ETH_STA_IPconfig._sta_static_sn.toString()); + } + +#if USE_CONFIGURABLE_DNS + + //***** Added for DNS Options ***** + if (server->arg("dns1") != "") + { + String dns1 = server->arg("dns1"); + + optionalIPFromString(&_ETH_STA_IPconfig._sta_static_dns1, dns1.c_str()); + + LOGDEBUG1(F("New Static DNS1 ="), _ETH_STA_IPconfig._sta_static_dns1.toString()); + } + + if (server->arg("dns2") != "") + { + String dns2 = server->arg("dns2"); + + optionalIPFromString(&_ETH_STA_IPconfig._sta_static_dns2, dns2.c_str()); + + LOGDEBUG1(F("New Static DNS2 ="), _ETH_STA_IPconfig._sta_static_dns2.toString()); + } + + //***** End added for DNS Options ***** +#endif + + String page = FPSTR(EM_HTTP_HEAD_START); + page.replace("{v}", "Credentials Saved"); + + page += FPSTR(EM_HTTP_SCRIPT); + page += FPSTR(EM_HTTP_STYLE); + page += _customHeadElement; + page += FPSTR(EM_HTTP_HEAD_END); + page += FPSTR(EM_HTTP_SAVED); + + page += FPSTR(EM_HTTP_END); + + server->send(200, "text/html", page); + + LOGDEBUG(F("Sent eth save page")); + + connect = true; //signal ready to connect/reset + + stopConfigPortal = true; //signal ready to shutdown config portal + + // Restore when Press Save WiFi + _configPortalTimeout = DEFAULT_PORTAL_TIMEOUT; +} + +////////////////////////////////////////// + +// Handle shut down the server page +void ESP32_ENC_Manager::handleServerClose() +{ + LOGDEBUG(F("Server Close")); + + server->sendHeader(FPSTR(EM_HTTP_CACHE_CONTROL), FPSTR(EM_HTTP_NO_STORE)); + + +#if USING_CORS_FEATURE + // For configuring CORS Header, default to EM_HTTP_CORS_ALLOW_ALL = "*" + server->sendHeader(FPSTR(EM_HTTP_CORS), _CORS_Header); +#endif + + server->sendHeader(FPSTR(EM_HTTP_PRAGMA), FPSTR(EM_HTTP_NO_CACHE)); + server->sendHeader(FPSTR(EM_HTTP_EXPIRES), "-1"); + + String page = FPSTR(EM_HTTP_HEAD_START); + + page.replace("{v}", "Close Server"); + + page += FPSTR(EM_HTTP_SCRIPT); + page += FPSTR(EM_HTTP_STYLE); + page += _customHeadElement; + page += FPSTR(EM_HTTP_HEAD_END); + page += F("
"); + page += F("
"); + page += F("IP address is "); + page += ETH.localIP().toString(); + page += F("

"); + page += F("Portal closed...

"); + + //page += F("Push button on device to restart configuration server!"); + + page += FPSTR(EM_HTTP_END); + + server->send(200, "text/html", page); + + stopConfigPortal = true; //signal ready to shutdown config portal + + LOGDEBUG(F("Sent server close page")); + + // Restore when Press Save WiFi + _configPortalTimeout = DEFAULT_PORTAL_TIMEOUT; +} + +////////////////////////////////////////// + +// Handle the info page +void ESP32_ENC_Manager::handleInfo() +{ + LOGDEBUG(F("Info")); + + // Disable _configPortalTimeout when someone accessing Portal to give some time to config + _configPortalTimeout = 0; + + server->sendHeader(FPSTR(EM_HTTP_CACHE_CONTROL), FPSTR(EM_HTTP_NO_STORE)); + +#if USING_CORS_FEATURE + // For configuring CORS Header, default to EM_HTTP_CORS_ALLOW_ALL = "*" + server->sendHeader(FPSTR(EM_HTTP_CORS), _CORS_Header); +#endif + + server->sendHeader(FPSTR(EM_HTTP_PRAGMA), FPSTR(EM_HTTP_NO_CACHE)); + server->sendHeader(FPSTR(EM_HTTP_EXPIRES), "-1"); + + String page = FPSTR(EM_HTTP_HEAD_START); + page.replace("{v}", "Info"); + + page += FPSTR(EM_HTTP_SCRIPT); + page += FPSTR(EM_HTTP_SCRIPT_NTP); + page += FPSTR(EM_HTTP_STYLE); + page += _customHeadElement; + + if (connect) + page += F(""); + + page += FPSTR(EM_HTTP_HEAD_END); + + page += F("
"); + + if (connect) + { + page += F("
Trying to connect
"); + page += ethStatus; + page += F("
"); + } + + page += pager; + page += F("

Information

"); + + reportStatus(page); + + page += FPSTR(EM_FLDSET_START); + page += F("

Device Data

"); + page += F(""); + page += F(""); + + page += F(""); + + page += F(""); + + page += F(""); + + page += F(""); + + page += F(""); + + page += F(""); + + page += F(""); + page += F("
NameValue
Chip ID"); + + page += String(ESP_getChipId(), HEX); + page += F("
Chip OUI"); + page += F("0x"); + page += String(getChipOUI(), HEX); + page += F("
Chip Model"); + page += ESP.getChipModel(); + page += F(" Rev"); + page += ESP.getChipRevision(); + + page += F("
Flash Chip ID"); + + // TODO + page += F("TODO"); + + page += F("
IDE Flash Size"); + page += ESP.getFlashChipSize(); + page += F(" bytes
Real Flash Size"); + + // TODO + page += F("TODO"); + + page += F(" bytes
Station IP"); + page += ETH.localIP().toString(); + page += F("
Station MAC"); + page += ETH.macAddress(); + page += F("
"); + + page += FPSTR(EM_FLDSET_END); + +#if USE_AVAILABLE_PAGES + page += FPSTR(EM_FLDSET_START); + page += FPSTR(EM_HTTP_AVAILABLE_PAGES); + page += FPSTR(EM_FLDSET_END); +#endif + + page += F("

More information about ESP32_ENC_Manager at"); + page += F("

https://github.com/khoih-prog/ESP32_ENC_Manager"); + page += FPSTR(EM_HTTP_END); + + server->send(200, "text/html", page); + + LOGDEBUG(F("Sent info page")); +} + +////////////////////////////////////////// + +// Handle the state page +void ESP32_ENC_Manager::handleState() +{ + LOGDEBUG(F("State-Json")); + + LOGDEBUG(F("Sent state page in json format")); +} + +////////////////////////////////////////// + +// Handle the reset page +void ESP32_ENC_Manager::handleReset() +{ + LOGDEBUG(F("Reset")); + + server->sendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); + server->sendHeader("Pragma", "no-cache"); + server->sendHeader("Expires", "-1"); + + String page = FPSTR(EM_HTTP_HEAD_START); + + page.replace("{v}", "ETH Information"); + page += FPSTR(EM_HTTP_SCRIPT); + page += FPSTR(EM_HTTP_STYLE); + page += _customHeadElement; + page += FPSTR(EM_HTTP_HEAD_END); + page += F("Resetting"); + page += FPSTR(EM_HTTP_END); + + server->send(200, "text/html", page); + + LOGDEBUG(F("Sent reset page")); + delay(5000); + + ESP.restart(); + + delay(2000); +} + +////////////////////////////////////////// + +void ESP32_ENC_Manager::handleNotFound() +{ + if (captivePortal()) + { + LOGDEBUG(F("handleNotFound: captive portal exit")); + + // If captive portal redirect instead of displaying the error page. + return; + } + + String message = "File Not Found\n\n"; + + message += "URI: "; + message += server->uri(); + message += "\nMethod: "; + message += (server->method() == HTTP_GET) ? "GET" : "POST"; + message += "\nArguments: "; + message += server->args(); + message += "\n"; + + for (uint8_t i = 0; i < server->args(); i++) + { + message += " " + server->argName(i) + ": " + server->arg(i) + "\n"; + } + + server->sendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); + server->sendHeader("Pragma", "no-cache"); + server->sendHeader("Expires", "-1"); + + server->send(404, "text/plain", message); +} + +////////////////////////////////////////// + +/** + HTTPD redirector + Redirect to captive portal if we got a request for another domain. + Return true in that case so the page handler do not try to handle the request again. +*/ +bool ESP32_ENC_Manager::captivePortal() +{ + LOGDEBUG1(F("captivePortal: hostHeader = "), server->hostHeader()); + + if (!isIp(server->hostHeader())) + { + LOGINFO1(F("Request redirected to captive portal : "), server->client().localIP()); + + server->sendHeader(F("Location"), (String)F("http://") + toStringIp(server->client().localIP()), true); + + // Empty content inhibits Content-length header so we have to close the socket ourselves. + server->send(302, FPSTR(EM_HTTP_HEAD_CT2), ""); + + server->client().stop(); // Stop is needed because we sent no content length + + return true; + } + + return false; +} + +////////////////////////////////////////// + +// start up save config callback +void ESP32_ENC_Manager::setSaveConfigCallback(void(*func)()) +{ + _savecallback = func; +} + +////////////////////////////////////////// + +// sets a custom element to add to head, like a new style tag +void ESP32_ENC_Manager::setCustomHeadElement(const char* element) +{ + _customHeadElement = element; +} + +////////////////////////////////////////// + +// Is this an IP? +bool ESP32_ENC_Manager::isIp(const String& str) +{ + for (unsigned int i = 0; i < str.length(); i++) + { + int c = str.charAt(i); + + if ( (c != '.') && (c != ':') && ( (c < '0') || (c > '9') ) ) + { + return false; + } + } + + return true; +} + +////////////////////////////////////////// + +// IP to String +String ESP32_ENC_Manager::toStringIp(const IPAddress& ip) +{ + String res = ""; + + for (int i = 0; i < 3; i++) + { + res += String((ip >> (8 * i)) & 0xFF) + "."; + } + + res += String(((ip >> 8 * 3)) & 0xFF); + + return res; +} + +////////////////////////////////////////// + +uint32_t getChipID() +{ + uint64_t chipId64 = 0; + + for (int i = 0; i < 6; i++) + { + chipId64 |= ( ( (uint64_t) ESP.getEfuseMac() >> (40 - (i * 8)) ) & 0xff ) << (i * 8); + } + + return (uint32_t) (chipId64 & 0xFFFFFF); +} + +////////////////////////////////////////// + +uint32_t getChipOUI() +{ + uint64_t chipId64 = 0; + + for (int i = 0; i < 6; i++) + { + chipId64 |= ( ( (uint64_t) ESP.getEfuseMac() >> (40 - (i * 8)) ) & 0xff ) << (i * 8); + } + + return (uint32_t) (chipId64 >> 24); +} + +////////////////////////////////////////// + +#endif // ESP32_ENC_Manager_Impl_h diff --git a/src/utils/TZ.h b/src/utils/TZ.h new file mode 100644 index 0000000..e96b0c7 --- /dev/null +++ b/src/utils/TZ.h @@ -0,0 +1,1526 @@ + +// autogenerated from https://raw.githubusercontent.com/nayarsystems/posix_tz_db/master/zones.csv +// by script /tools/TZupdate.sh +// Thu Nov 12 04:07:03 UTC 2020 +// +// This database is autogenerated from IANA timezone database +// https://raw.githubusercontent.com/nayarsystems/posix_tz_db/master/zones.csv +// (using https://www.iana.org/time-zones) +// and can be updated on demand in this repository +// or by yourself using the above script + +#ifndef TZDB_H +#define TZDB_H + +//See: https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html +// EST5EDT,M3.2.0,M11.1.0 (for America/New_York) +// EST5EDT is the name of the time zone +// EST is the abbreviation used when DST is off +// 6 hours is the time difference from GMT +// EDT is the abbreviation used when DST is on +// ,M3 is the third month +// .2 is the second occurrence of the day in the month +// .0 is Sunday +// ,M11 is the eleventh month +// .1 is the first occurrence of the day in the month +// .0 is Sunday + + +#if !defined(USING_AFRICA) + #define USING_AFRICA false +#endif + +#if !defined(USING_AMERICA) + #define USING_AMERICA true +#endif + +#if !defined(USING_ANTARCTICA) + #define USING_ANTARCTICA false +#endif + +#if !defined(USING_ASIA) + #define USING_ASIA false +#endif + +#if !defined(USING_ATLANTIC) + #define USING_ATLANTIC false +#endif + +#if !defined(USING_AUSTRALIA) + #define USING_AUSTRALIA true +#endif + +#if !defined(USING_EUROPE) + #define USING_EUROPE false +#endif + +#if !defined(USING_INDIAN) + #define USING_INDIAN false +#endif + +#if !defined(USING_PACIFIC) + #define USING_PACIFIC false +#endif + +#if !defined(USING_ETC_GMT) + #define USING_ETC_GMT false +#endif + +//////////////////////////////////////////////////// + +#define TZ_Africa_Abidjan ("GMT0") +#define TZ_Africa_Accra ("GMT0") +#define TZ_Africa_Addis_Ababa ("EAT-3") +#define TZ_Africa_Algiers ("CET-1") +#define TZ_Africa_Asmara ("EAT-3") +#define TZ_Africa_Bamako ("GMT0") +#define TZ_Africa_Bangui ("WAT-1") +#define TZ_Africa_Banjul ("GMT0") +#define TZ_Africa_Bissau ("GMT0") +#define TZ_Africa_Blantyre ("CAT-2") +#define TZ_Africa_Brazzaville ("WAT-1") +#define TZ_Africa_Bujumbura ("CAT-2") +#define TZ_Africa_Cairo ("EET-2") +#define TZ_Africa_Casablanca ("<+01>-1") +#define TZ_Africa_Ceuta ("CET-1CEST,M3.5.0,M10.5.0/3") +#define TZ_Africa_Conakry ("GMT0") +#define TZ_Africa_Dakar ("GMT0") +#define TZ_Africa_Dar_es_Salaam ("EAT-3") +#define TZ_Africa_Djibouti ("EAT-3") +#define TZ_Africa_Douala ("WAT-1") +#define TZ_Africa_El_Aaiun ("<+01>-1") +#define TZ_Africa_Freetown ("GMT0") +#define TZ_Africa_Gaborone ("CAT-2") +#define TZ_Africa_Harare ("CAT-2") +#define TZ_Africa_Johannesburg ("SAST-2") +#define TZ_Africa_Juba ("EAT-3") +#define TZ_Africa_Kampala ("EAT-3") +#define TZ_Africa_Khartoum ("CAT-2") +#define TZ_Africa_Kigali ("CAT-2") +#define TZ_Africa_Kinshasa ("WAT-1") +#define TZ_Africa_Lagos ("WAT-1") +#define TZ_Africa_Libreville ("WAT-1") +#define TZ_Africa_Lome ("GMT0") +#define TZ_Africa_Luanda ("WAT-1") +#define TZ_Africa_Lubumbashi ("CAT-2") +#define TZ_Africa_Lusaka ("CAT-2") +#define TZ_Africa_Malabo ("WAT-1") +#define TZ_Africa_Maputo ("CAT-2") +#define TZ_Africa_Maseru ("SAST-2") +#define TZ_Africa_Mbabane ("SAST-2") +#define TZ_Africa_Mogadishu ("EAT-3") +#define TZ_Africa_Monrovia ("GMT0") +#define TZ_Africa_Nairobi ("EAT-3") +#define TZ_Africa_Ndjamena ("WAT-1") +#define TZ_Africa_Niamey ("WAT-1") +#define TZ_Africa_Nouakchott ("GMT0") +#define TZ_Africa_Ouagadougou ("GMT0") +#define TZ_Africa_PortomNovo ("WAT-1") +#define TZ_Africa_Sao_Tome ("GMT0") +#define TZ_Africa_Tripoli ("EET-2") +#define TZ_Africa_Tunis ("CET-1") +#define TZ_Africa_Windhoek ("CAT-2") +#define TZ_America_Adak ("HST10HDT,M3.2.0,M11.1.0") +#define TZ_America_Anchorage ("AKST9AKDT,M3.2.0,M11.1.0") +#define TZ_America_Anguilla ("AST4") +#define TZ_America_Antigua ("AST4") +#define TZ_America_Araguaina ("<-03>3") +#define TZ_America_Argentina_Buenos_Aires ("<-03>3") +#define TZ_America_Argentina_Catamarca ("<-03>3") +#define TZ_America_Argentina_Cordoba ("<-03>3") +#define TZ_America_Argentina_Jujuy ("<-03>3") +#define TZ_America_Argentina_La_Rioja ("<-03>3") +#define TZ_America_Argentina_Mendoza ("<-03>3") +#define TZ_America_Argentina_Rio_Gallegos ("<-03>3") +#define TZ_America_Argentina_Salta ("<-03>3") +#define TZ_America_Argentina_San_Juan ("<-03>3") +#define TZ_America_Argentina_San_Luis ("<-03>3") +#define TZ_America_Argentina_Tucuman ("<-03>3") +#define TZ_America_Argentina_Ushuaia ("<-03>3") +#define TZ_America_Aruba ("AST4") +#define TZ_America_Asuncion ("<-04>4<-03>,M10.1.0/0,M3.4.0/0") +#define TZ_America_Atikokan ("EST5") +#define TZ_America_Bahia ("<-03>3") +#define TZ_America_Bahia_Banderas ("CST6CDT,M4.1.0,M10.5.0") +#define TZ_America_Barbados ("AST4") +#define TZ_America_Belem ("<-03>3") +#define TZ_America_Belize ("CST6") +#define TZ_America_BlancmSablon ("AST4") +#define TZ_America_Boa_Vista ("<-04>4") +#define TZ_America_Bogota ("<-05>5") +#define TZ_America_Boise ("MST7MDT,M3.2.0,M11.1.0") +#define TZ_America_Cambridge_Bay ("MST7MDT,M3.2.0,M11.1.0") +#define TZ_America_Campo_Grande ("<-04>4") +#define TZ_America_Cancun ("EST5") +#define TZ_America_Caracas ("<-04>4") +#define TZ_America_Cayenne ("<-03>3") +#define TZ_America_Cayman ("EST5") +#define TZ_America_Chicago ("CST6CDT,M3.2.0,M11.1.0") +#define TZ_America_Chihuahua ("MST7MDT,M4.1.0,M10.5.0") +#define TZ_America_Costa_Rica ("CST6") +#define TZ_America_Creston ("MST7") +#define TZ_America_Cuiaba ("<-04>4") +#define TZ_America_Curacao ("AST4") +#define TZ_America_Danmarkshavn ("GMT0") +#define TZ_America_Dawson ("MST7") +#define TZ_America_Dawson_Creek ("MST7") +#define TZ_America_Denver ("MST7MDT,M3.2.0,M11.1.0") +#define TZ_America_Detroit ("EST5EDT,M3.2.0,M11.1.0") +#define TZ_America_Dominica ("AST4") +#define TZ_America_Edmonton ("MST7MDT,M3.2.0,M11.1.0") +#define TZ_America_Eirunepe ("<-05>5") +#define TZ_America_El_Salvador ("CST6") +#define TZ_America_Fortaleza ("<-03>3") +#define TZ_America_Fort_Nelson ("MST7") +#define TZ_America_Glace_Bay ("AST4ADT,M3.2.0,M11.1.0") +#define TZ_America_Godthab ("<-03>3<-02>,M3.5.0/-2,M10.5.0/-1") +#define TZ_America_Goose_Bay ("AST4ADT,M3.2.0,M11.1.0") +#define TZ_America_Grand_Turk ("EST5EDT,M3.2.0,M11.1.0") +#define TZ_America_Grenada ("AST4") +#define TZ_America_Guadeloupe ("AST4") +#define TZ_America_Guatemala ("CST6") +#define TZ_America_Guayaquil ("<-05>5") +#define TZ_America_Guyana ("<-04>4") +#define TZ_America_Halifax ("AST4ADT,M3.2.0,M11.1.0") +#define TZ_America_Havana ("CST5CDT,M3.2.0/0,M11.1.0/1") +#define TZ_America_Hermosillo ("MST7") +#define TZ_America_Indiana_Indianapolis ("EST5EDT,M3.2.0,M11.1.0") +#define TZ_America_Indiana_Knox ("CST6CDT,M3.2.0,M11.1.0") +#define TZ_America_Indiana_Marengo ("EST5EDT,M3.2.0,M11.1.0") +#define TZ_America_Indiana_Petersburg ("EST5EDT,M3.2.0,M11.1.0") +#define TZ_America_Indiana_Tell_City ("CST6CDT,M3.2.0,M11.1.0") +#define TZ_America_Indiana_Vevay ("EST5EDT,M3.2.0,M11.1.0") +#define TZ_America_Indiana_Vincennes ("EST5EDT,M3.2.0,M11.1.0") +#define TZ_America_Indiana_Winamac ("EST5EDT,M3.2.0,M11.1.0") +#define TZ_America_Inuvik ("MST7MDT,M3.2.0,M11.1.0") +#define TZ_America_Iqaluit ("EST5EDT,M3.2.0,M11.1.0") +#define TZ_America_Jamaica ("EST5") +#define TZ_America_Juneau ("AKST9AKDT,M3.2.0,M11.1.0") +#define TZ_America_Kentucky_Louisville ("EST5EDT,M3.2.0,M11.1.0") +#define TZ_America_Kentucky_Monticello ("EST5EDT,M3.2.0,M11.1.0") +#define TZ_America_Kralendijk ("AST4") +#define TZ_America_La_Paz ("<-04>4") +#define TZ_America_Lima ("<-05>5") +#define TZ_America_Los_Angeles ("PST8PDT,M3.2.0,M11.1.0") +#define TZ_America_Lower_Princes ("AST4") +#define TZ_America_Maceio ("<-03>3") +#define TZ_America_Managua ("CST6") +#define TZ_America_Manaus ("<-04>4") +#define TZ_America_Marigot ("AST4") +#define TZ_America_Martinique ("AST4") +#define TZ_America_Matamoros ("CST6CDT,M3.2.0,M11.1.0") +#define TZ_America_Mazatlan ("MST7MDT,M4.1.0,M10.5.0") +#define TZ_America_Menominee ("CST6CDT,M3.2.0,M11.1.0") +#define TZ_America_Merida ("CST6CDT,M4.1.0,M10.5.0") +#define TZ_America_Metlakatla ("AKST9AKDT,M3.2.0,M11.1.0") +#define TZ_America_Mexico_City ("CST6CDT,M4.1.0,M10.5.0") +#define TZ_America_Miquelon ("<-03>3<-02>,M3.2.0,M11.1.0") +#define TZ_America_Moncton ("AST4ADT,M3.2.0,M11.1.0") +#define TZ_America_Monterrey ("CST6CDT,M4.1.0,M10.5.0") +#define TZ_America_Montevideo ("<-03>3") +#define TZ_America_Montreal ("EST5EDT,M3.2.0,M11.1.0") +#define TZ_America_Montserrat ("AST4") +#define TZ_America_Nassau ("EST5EDT,M3.2.0,M11.1.0") +#define TZ_America_New_York ("EST5EDT,M3.2.0,M11.1.0") +#define TZ_America_Nipigon ("EST5EDT,M3.2.0,M11.1.0") +#define TZ_America_Nome ("AKST9AKDT,M3.2.0,M11.1.0") +#define TZ_America_Noronha ("<-02>2") +#define TZ_America_North_Dakota_Beulah ("CST6CDT,M3.2.0,M11.1.0") +#define TZ_America_North_Dakota_Center ("CST6CDT,M3.2.0,M11.1.0") +#define TZ_America_North_Dakota_New_Salem ("CST6CDT,M3.2.0,M11.1.0") +#define TZ_America_Ojinaga ("MST7MDT,M3.2.0,M11.1.0") +#define TZ_America_Panama ("EST5") +#define TZ_America_Pangnirtung ("EST5EDT,M3.2.0,M11.1.0") +#define TZ_America_Paramaribo ("<-03>3") +#define TZ_America_Phoenix ("MST7") +#define TZ_America_PortmaumPrince ("EST5EDT,M3.2.0,M11.1.0") +#define TZ_America_Port_of_Spain ("AST4") +#define TZ_America_Porto_Velho ("<-04>4") +#define TZ_America_Puerto_Rico ("AST4") +#define TZ_America_Punta_Arenas ("<-03>3") +#define TZ_America_Rainy_River ("CST6CDT,M3.2.0,M11.1.0") +#define TZ_America_Rankin_Inlet ("CST6CDT,M3.2.0,M11.1.0") +#define TZ_America_Recife ("<-03>3") +#define TZ_America_Regina ("CST6") +#define TZ_America_Resolute ("CST6CDT,M3.2.0,M11.1.0") +#define TZ_America_Rio_Branco ("<-05>5") +#define TZ_America_Santarem ("<-03>3") +#define TZ_America_Santiago ("<-04>4<-03>,M9.1.6/24,M4.1.6/24") +#define TZ_America_Santo_Domingo ("AST4") +#define TZ_America_Sao_Paulo ("<-03>3") +#define TZ_America_Scoresbysund ("<-01>1<+00>,M3.5.0/0,M10.5.0/1") +#define TZ_America_Sitka ("AKST9AKDT,M3.2.0,M11.1.0") +#define TZ_America_St_Barthelemy ("AST4") +#define TZ_America_St_Johns ("NST3:30NDT,M3.2.0,M11.1.0") +#define TZ_America_St_Kitts ("AST4") +#define TZ_America_St_Lucia ("AST4") +#define TZ_America_St_Thomas ("AST4") +#define TZ_America_St_Vincent ("AST4") +#define TZ_America_Swift_Current ("CST6") +#define TZ_America_Tegucigalpa ("CST6") +#define TZ_America_Thule ("AST4ADT,M3.2.0,M11.1.0") +#define TZ_America_Thunder_Bay ("EST5EDT,M3.2.0,M11.1.0") +#define TZ_America_Tijuana ("PST8PDT,M3.2.0,M11.1.0") +#define TZ_America_Toronto ("EST5EDT,M3.2.0,M11.1.0") +#define TZ_America_Tortola ("AST4") +#define TZ_America_Vancouver ("PST8PDT,M3.2.0,M11.1.0") +#define TZ_America_Whitehorse ("MST7") +#define TZ_America_Winnipeg ("CST6CDT,M3.2.0,M11.1.0") +#define TZ_America_Yakutat ("AKST9AKDT,M3.2.0,M11.1.0") +#define TZ_America_Yellowknife ("MST7MDT,M3.2.0,M11.1.0") +#define TZ_Antarctica_Casey ("<+11>-11") +#define TZ_Antarctica_Davis ("<+07>-7") +#define TZ_Antarctica_DumontDUrville ("<+10>-10") +#define TZ_Antarctica_Macquarie ("AEST-10AEDT,M10.1.0,M4.1.0/3") +#define TZ_Antarctica_Mawson ("<+05>-5") +#define TZ_Antarctica_McMurdo ("NZST-12NZDT,M9.5.0,M4.1.0/3") +#define TZ_Antarctica_Palmer ("<-03>3") +#define TZ_Antarctica_Rothera ("<-03>3") +#define TZ_Antarctica_Syowa ("<+03>-3") +#define TZ_Antarctica_Troll ("<+00>0<+02>-2,M3.5.0/1,M10.5.0/3") +#define TZ_Antarctica_Vostok ("<+06>-6") +#define TZ_Arctic_Longyearbyen ("CET-1CEST,M3.5.0,M10.5.0/3") +#define TZ_Asia_Aden ("<+03>-3") +#define TZ_Asia_Almaty ("<+06>-6") +#define TZ_Asia_Amman ("EET-2EEST,M3.5.4/24,M10.5.5/1") +#define TZ_Asia_Anadyr ("<+12>-12") +#define TZ_Asia_Aqtau ("<+05>-5") +#define TZ_Asia_Aqtobe ("<+05>-5") +#define TZ_Asia_Ashgabat ("<+05>-5") +#define TZ_Asia_Atyrau ("<+05>-5") +#define TZ_Asia_Baghdad ("<+03>-3") +#define TZ_Asia_Bahrain ("<+03>-3") +#define TZ_Asia_Baku ("<+04>-4") +#define TZ_Asia_Bangkok ("<+07>-7") +#define TZ_Asia_Barnaul ("<+07>-7") +#define TZ_Asia_Beirut ("EET-2EEST,M3.5.0/0,M10.5.0/0") +#define TZ_Asia_Bishkek ("<+06>-6") +#define TZ_Asia_Brunei ("<+08>-8") +#define TZ_Asia_Chita ("<+09>-9") +#define TZ_Asia_Choibalsan ("<+08>-8") +#define TZ_Asia_Colombo ("<+0530>-5:30") +#define TZ_Asia_Damascus ("EET-2EEST,M3.5.5/0,M10.5.5/0") +#define TZ_Asia_Dhaka ("<+06>-6") +#define TZ_Asia_Dili ("<+09>-9") +#define TZ_Asia_Dubai ("<+04>-4") +#define TZ_Asia_Dushanbe ("<+05>-5") +#define TZ_Asia_Famagusta ("EET-2EEST,M3.5.0/3,M10.5.0/4") +#define TZ_Asia_Gaza ("EET-2EEST,M3.4.4/48,M10.4.4/49") +#define TZ_Asia_Hebron ("EET-2EEST,M3.4.4/48,M10.4.4/49") +#define TZ_Asia_Ho_Chi_Minh ("<+07>-7") +#define TZ_Asia_Hong_Kong ("HKT-8") +#define TZ_Asia_Hovd ("<+07>-7") +#define TZ_Asia_Irkutsk ("<+08>-8") +#define TZ_Asia_Jakarta ("WIB-7") +#define TZ_Asia_Jayapura ("WIT-9") +#define TZ_Asia_Jerusalem ("IST-2IDT,M3.4.4/26,M10.5.0") +#define TZ_Asia_Kabul ("<+0430>-4:30") +#define TZ_Asia_Kamchatka ("<+12>-12") +#define TZ_Asia_Karachi ("PKT-5") +#define TZ_Asia_Kathmandu ("<+0545>-5:45") +#define TZ_Asia_Khandyga ("<+09>-9") +#define TZ_Asia_Kolkata ("IST-5:30") +#define TZ_Asia_Krasnoyarsk ("<+07>-7") +#define TZ_Asia_Kuala_Lumpur ("<+08>-8") +#define TZ_Asia_Kuching ("<+08>-8") +#define TZ_Asia_Kuwait ("<+03>-3") +#define TZ_Asia_Macau ("CST-8") +#define TZ_Asia_Magadan ("<+11>-11") +#define TZ_Asia_Makassar ("WITA-8") +#define TZ_Asia_Manila ("PST-8") +#define TZ_Asia_Muscat ("<+04>-4") +#define TZ_Asia_Nicosia ("EET-2EEST,M3.5.0/3,M10.5.0/4") +#define TZ_Asia_Novokuznetsk ("<+07>-7") +#define TZ_Asia_Novosibirsk ("<+07>-7") +#define TZ_Asia_Omsk ("<+06>-6") +#define TZ_Asia_Oral ("<+05>-5") +#define TZ_Asia_Phnom_Penh ("<+07>-7") +#define TZ_Asia_Pontianak ("WIB-7") +#define TZ_Asia_Pyongyang ("KST-9") +#define TZ_Asia_Qatar ("<+03>-3") +#define TZ_Asia_Qyzylorda ("<+05>-5") +#define TZ_Asia_Riyadh ("<+03>-3") +#define TZ_Asia_Sakhalin ("<+11>-11") +#define TZ_Asia_Samarkand ("<+05>-5") +#define TZ_Asia_Seoul ("KST-9") +#define TZ_Asia_Shanghai ("CST-8") +#define TZ_Asia_Singapore ("<+08>-8") +#define TZ_Asia_Srednekolymsk ("<+11>-11") +#define TZ_Asia_Taipei ("CST-8") +#define TZ_Asia_Tashkent ("<+05>-5") +#define TZ_Asia_Tbilisi ("<+04>-4") +#define TZ_Asia_Tehran ("<+0330>-3:30<+0430>,J79/24,J263/24") +#define TZ_Asia_Thimphu ("<+06>-6") +#define TZ_Asia_Tokyo ("JST-9") +#define TZ_Asia_Tomsk ("<+07>-7") +#define TZ_Asia_Ulaanbaatar ("<+08>-8") +#define TZ_Asia_Urumqi ("<+06>-6") +#define TZ_Asia_UstmNera ("<+10>-10") +#define TZ_Asia_Vientiane ("<+07>-7") +#define TZ_Asia_Vladivostok ("<+10>-10") +#define TZ_Asia_Yakutsk ("<+09>-9") +#define TZ_Asia_Yangon ("<+0630>-6:30") +#define TZ_Asia_Yekaterinburg ("<+05>-5") +#define TZ_Asia_Yerevan ("<+04>-4") +#define TZ_Atlantic_Azores ("<-01>1<+00>,M3.5.0/0,M10.5.0/1") +#define TZ_Atlantic_Bermuda ("AST4ADT,M3.2.0,M11.1.0") +#define TZ_Atlantic_Canary ("WET0WEST,M3.5.0/1,M10.5.0") +#define TZ_Atlantic_Cape_Verde ("<-01>1") +#define TZ_Atlantic_Faroe ("WET0WEST,M3.5.0/1,M10.5.0") +#define TZ_Atlantic_Madeira ("WET0WEST,M3.5.0/1,M10.5.0") +#define TZ_Atlantic_Reykjavik ("GMT0") +#define TZ_Atlantic_South_Georgia ("<-02>2") +#define TZ_Atlantic_Stanley ("<-03>3") +#define TZ_Atlantic_St_Helena ("GMT0") +#define TZ_Australia_Adelaide ("ACST-9:30ACDT,M10.1.0,M4.1.0/3") +#define TZ_Australia_Brisbane ("AEST-10") +#define TZ_Australia_Broken_Hill ("ACST-9:30ACDT,M10.1.0,M4.1.0/3") +#define TZ_Australia_Currie ("AEST-10AEDT,M10.1.0,M4.1.0/3") +#define TZ_Australia_Darwin ("ACST-9:30") +#define TZ_Australia_Eucla ("<+0845>-8:45") +#define TZ_Australia_Hobart ("AEST-10AEDT,M10.1.0,M4.1.0/3") +#define TZ_Australia_Lindeman ("AEST-10") +#define TZ_Australia_Lord_Howe ("<+1030>-10:30<+11>-11,M10.1.0,M4.1.0") +#define TZ_Australia_Melbourne ("AEST-10AEDT,M10.1.0,M4.1.0/3") +#define TZ_Australia_Perth ("AWST-8") +#define TZ_Australia_Sydney ("AEST-10AEDT,M10.1.0,M4.1.0/3") +#define TZ_Europe_Amsterdam ("CET-1CEST,M3.5.0,M10.5.0/3") +#define TZ_Europe_Andorra ("CET-1CEST,M3.5.0,M10.5.0/3") +#define TZ_Europe_Astrakhan ("<+04>-4") +#define TZ_Europe_Athens ("EET-2EEST,M3.5.0/3,M10.5.0/4") +#define TZ_Europe_Belgrade ("CET-1CEST,M3.5.0,M10.5.0/3") +#define TZ_Europe_Berlin ("CET-1CEST,M3.5.0,M10.5.0/3") +#define TZ_Europe_Bratislava ("CET-1CEST,M3.5.0,M10.5.0/3") +#define TZ_Europe_Brussels ("CET-1CEST,M3.5.0,M10.5.0/3") +#define TZ_Europe_Bucharest ("EET-2EEST,M3.5.0/3,M10.5.0/4") +#define TZ_Europe_Budapest ("CET-1CEST,M3.5.0,M10.5.0/3") +#define TZ_Europe_Busingen ("CET-1CEST,M3.5.0,M10.5.0/3") +#define TZ_Europe_Chisinau ("EET-2EEST,M3.5.0,M10.5.0/3") +#define TZ_Europe_Copenhagen ("CET-1CEST,M3.5.0,M10.5.0/3") +#define TZ_Europe_Dublin ("IST-1GMT0,M10.5.0,M3.5.0/1") +#define TZ_Europe_Gibraltar ("CET-1CEST,M3.5.0,M10.5.0/3") +#define TZ_Europe_Guernsey ("GMT0BST,M3.5.0/1,M10.5.0") +#define TZ_Europe_Helsinki ("EET-2EEST,M3.5.0/3,M10.5.0/4") +#define TZ_Europe_Isle_of_Man ("GMT0BST,M3.5.0/1,M10.5.0") +#define TZ_Europe_Istanbul ("<+03>-3") +#define TZ_Europe_Jersey ("GMT0BST,M3.5.0/1,M10.5.0") +#define TZ_Europe_Kaliningrad ("EET-2") +#define TZ_Europe_Kiev ("EET-2EEST,M3.5.0/3,M10.5.0/4") +#define TZ_Europe_Kirov ("<+03>-3") +#define TZ_Europe_Lisbon ("WET0WEST,M3.5.0/1,M10.5.0") +#define TZ_Europe_Ljubljana ("CET-1CEST,M3.5.0,M10.5.0/3") +#define TZ_Europe_London ("GMT0BST,M3.5.0/1,M10.5.0") +#define TZ_Europe_Luxembourg ("CET-1CEST,M3.5.0,M10.5.0/3") +#define TZ_Europe_Madrid ("CET-1CEST,M3.5.0,M10.5.0/3") +#define TZ_Europe_Malta ("CET-1CEST,M3.5.0,M10.5.0/3") +#define TZ_Europe_Mariehamn ("EET-2EEST,M3.5.0/3,M10.5.0/4") +#define TZ_Europe_Minsk ("<+03>-3") +#define TZ_Europe_Monaco ("CET-1CEST,M3.5.0,M10.5.0/3") +#define TZ_Europe_Moscow ("MSK-3") +#define TZ_Europe_Oslo ("CET-1CEST,M3.5.0,M10.5.0/3") +#define TZ_Europe_Paris ("CET-1CEST,M3.5.0,M10.5.0/3") +#define TZ_Europe_Podgorica ("CET-1CEST,M3.5.0,M10.5.0/3") +#define TZ_Europe_Prague ("CET-1CEST,M3.5.0,M10.5.0/3") +#define TZ_Europe_Riga ("EET-2EEST,M3.5.0/3,M10.5.0/4") +#define TZ_Europe_Rome ("CET-1CEST,M3.5.0,M10.5.0/3") +#define TZ_Europe_Samara ("<+04>-4") +#define TZ_Europe_San_Marino ("CET-1CEST,M3.5.0,M10.5.0/3") +#define TZ_Europe_Sarajevo ("CET-1CEST,M3.5.0,M10.5.0/3") +#define TZ_Europe_Saratov ("<+04>-4") +#define TZ_Europe_Simferopol ("MSK-3") +#define TZ_Europe_Skopje ("CET-1CEST,M3.5.0,M10.5.0/3") +#define TZ_Europe_Sofia ("EET-2EEST,M3.5.0/3,M10.5.0/4") +#define TZ_Europe_Stockholm ("CET-1CEST,M3.5.0,M10.5.0/3") +#define TZ_Europe_Tallinn ("EET-2EEST,M3.5.0/3,M10.5.0/4") +#define TZ_Europe_Tirane ("CET-1CEST,M3.5.0,M10.5.0/3") +#define TZ_Europe_Ulyanovsk ("<+04>-4") +#define TZ_Europe_Uzhgorod ("EET-2EEST,M3.5.0/3,M10.5.0/4") +#define TZ_Europe_Vaduz ("CET-1CEST,M3.5.0,M10.5.0/3") +#define TZ_Europe_Vatican ("CET-1CEST,M3.5.0,M10.5.0/3") +#define TZ_Europe_Vienna ("CET-1CEST,M3.5.0,M10.5.0/3") +#define TZ_Europe_Vilnius ("EET-2EEST,M3.5.0/3,M10.5.0/4") +#define TZ_Europe_Volgograd ("<+04>-4") +#define TZ_Europe_Warsaw ("CET-1CEST,M3.5.0,M10.5.0/3") +#define TZ_Europe_Zagreb ("CET-1CEST,M3.5.0,M10.5.0/3") +#define TZ_Europe_Zaporozhye ("EET-2EEST,M3.5.0/3,M10.5.0/4") +#define TZ_Europe_Zurich ("CET-1CEST,M3.5.0,M10.5.0/3") +#define TZ_Indian_Antananarivo ("EAT-3") +#define TZ_Indian_Chagos ("<+06>-6") +#define TZ_Indian_Christmas ("<+07>-7") +#define TZ_Indian_Cocos ("<+0630>-6:30") +#define TZ_Indian_Comoro ("EAT-3") +#define TZ_Indian_Kerguelen ("<+05>-5") +#define TZ_Indian_Mahe ("<+04>-4") +#define TZ_Indian_Maldives ("<+05>-5") +#define TZ_Indian_Mauritius ("<+04>-4") +#define TZ_Indian_Mayotte ("EAT-3") +#define TZ_Indian_Reunion ("<+04>-4") +#define TZ_Pacific_Apia ("<+13>-13<+14>,M9.5.0/3,M4.1.0/4") +#define TZ_Pacific_Auckland ("NZST-12NZDT,M9.5.0,M4.1.0/3") +#define TZ_Pacific_Bougainville ("<+11>-11") +#define TZ_Pacific_Chatham ("<+1245>-12:45<+1345>,M9.5.0/2:45,M4.1.0/3:45") +#define TZ_Pacific_Chuuk ("<+10>-10") +#define TZ_Pacific_Easter ("<-06>6<-05>,M9.1.6/22,M4.1.6/22") +#define TZ_Pacific_Efate ("<+11>-11") +#define TZ_Pacific_Enderbury ("<+13>-13") +#define TZ_Pacific_Fakaofo ("<+13>-13") +#define TZ_Pacific_Fiji ("<+12>-12<+13>,M11.2.0,M1.2.3/99") +#define TZ_Pacific_Funafuti ("<+12>-12") +#define TZ_Pacific_Galapagos ("<-06>6") +#define TZ_Pacific_Gambier ("<-09>9") +#define TZ_Pacific_Guadalcanal ("<+11>-11") +#define TZ_Pacific_Guam ("ChST-10") +#define TZ_Pacific_Honolulu ("HST10") +#define TZ_Pacific_Kiritimati ("<+14>-14") +#define TZ_Pacific_Kosrae ("<+11>-11") +#define TZ_Pacific_Kwajalein ("<+12>-12") +#define TZ_Pacific_Majuro ("<+12>-12") +#define TZ_Pacific_Marquesas ("<-0930>9:30") +#define TZ_Pacific_Midway ("SST11") +#define TZ_Pacific_Nauru ("<+12>-12") +#define TZ_Pacific_Niue ("<-11>11") +#define TZ_Pacific_Norfolk ("<+11>-11<+12>,M10.1.0,M4.1.0/3") +#define TZ_Pacific_Noumea ("<+11>-11") +#define TZ_Pacific_Pago_Pago ("SST11") +#define TZ_Pacific_Palau ("<+09>-9") +#define TZ_Pacific_Pitcairn ("<-08>8") +#define TZ_Pacific_Pohnpei ("<+11>-11") +#define TZ_Pacific_Port_Moresby ("<+10>-10") +#define TZ_Pacific_Rarotonga ("<-10>10") +#define TZ_Pacific_Saipan ("ChST-10") +#define TZ_Pacific_Tahiti ("<-10>10") +#define TZ_Pacific_Tarawa ("<+12>-12") +#define TZ_Pacific_Tongatapu ("<+13>-13") +#define TZ_Pacific_Wake ("<+12>-12") +#define TZ_Pacific_Wallis ("<+12>-12") +#define TZ_Etc_GMT ("GMT0") +#define TZ_Etc_GMTm0 ("GMT0") +#define TZ_Etc_GMTm1 ("<+01>-1") +#define TZ_Etc_GMTm2 ("<+02>-2") +#define TZ_Etc_GMTm3 ("<+03>-3") +#define TZ_Etc_GMTm4 ("<+04>-4") +#define TZ_Etc_GMTm5 ("<+05>-5") +#define TZ_Etc_GMTm6 ("<+06>-6") +#define TZ_Etc_GMTm7 ("<+07>-7") +#define TZ_Etc_GMTm8 ("<+08>-8") +#define TZ_Etc_GMTm9 ("<+09>-9") +#define TZ_Etc_GMTm10 ("<+10>-10") +#define TZ_Etc_GMTm11 ("<+11>-11") +#define TZ_Etc_GMTm12 ("<+12>-12") +#define TZ_Etc_GMTm13 ("<+13>-13") +#define TZ_Etc_GMTm14 ("<+14>-14") +#define TZ_Etc_GMT0 ("GMT0") +#define TZ_Etc_GMTp0 ("GMT0") +#define TZ_Etc_GMTp1 ("<-01>1") +#define TZ_Etc_GMTp2 ("<-02>2") +#define TZ_Etc_GMTp3 ("<-03>3") +#define TZ_Etc_GMTp4 ("<-04>4") +#define TZ_Etc_GMTp5 ("<-05>5") +#define TZ_Etc_GMTp6 ("<-06>6") +#define TZ_Etc_GMTp7 ("<-07>7") +#define TZ_Etc_GMTp8 ("<-08>8") +#define TZ_Etc_GMTp9 ("<-09>9") +#define TZ_Etc_GMTp10 ("<-10>10") +#define TZ_Etc_GMTp11 ("<-11>11") +#define TZ_Etc_GMTp12 ("<-12>12") +#define TZ_Etc_UCT ("UTC0") +#define TZ_Etc_UTC ("UTC0") +#define TZ_Etc_Greenwich ("GMT0") +#define TZ_Etc_Universal ("UTC0") +#define TZ_Etc_Zulu ("UTC0") + +//////////////////////////////////////////////////////////// + +#define TIMEZONE_MAX_LEN 50 + +static const char TZ_NAME[][TIMEZONE_MAX_LEN] /*PROGMEM*/ = +{ +#if USING_AFRICA + "Africa/Abidjan", //PSTR("GMT0") + "Africa/Accra", //PSTR("GMT0") + "Africa/Addis_Ababa", //PSTR("EAT-3") + "Africa/Algiers", //PSTR("CET-1") + "Africa/Asmara", //PSTR("EAT-3") + "Africa/Bamako", //PSTR("GMT0") + "Africa/Bangui", //PSTR("WAT-1") + "Africa/Banjul", //PSTR("GMT0") + "Africa/Bissau", //PSTR("GMT0") + "Africa/Blantyre", //PSTR("CAT-2") + "Africa/Brazzaville", //PSTR("WAT-1") + "Africa/Bujumbura", //PSTR("CAT-2") + "Africa/Cairo", //PSTR("EET-2") + "Africa/Casablanca", //PSTR("<+01>-1") + "Africa/Ceuta", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3") + "Africa/Conakry", //PSTR("GMT0") + "Africa/Dakar", //PSTR("GMT0") + "Africa/Dar_es_Salaam", //PSTR("EAT-3") + "Africa/Djibouti", //PSTR("EAT-3") + "Africa/Douala", //PSTR("WAT-1") + "Africa/El_Aaiun", //PSTR("<+01>-1") + "Africa/Freetown", //PSTR("GMT0") + "Africa/Gaborone", //PSTR("CAT-2") + "Africa/Harare", //PSTR("CAT-2") + "Africa/Johannesburg", //PSTR("SAST-2") + "Africa/Juba", //PSTR("EAT-3") + "Africa/Kampala", //PSTR("EAT-3") + "Africa/Khartoum", //PSTR("CAT-2") + "Africa/Kigali", //PSTR("CAT-2") + "Africa/Kinshasa", //PSTR("WAT-1") + "Africa/Lagos", //PSTR("WAT-1") + "Africa/Libreville", //PSTR("WAT-1") + "Africa/Lome", //PSTR("GMT0") + "Africa/Luanda", //PSTR("WAT-1") + "Africa/Lubumbashi", //PSTR("CAT-2") + "Africa/Lusaka", //PSTR("CAT-2") + "Africa/Malabo", //PSTR("WAT-1") + "Africa/Maputo", //PSTR("CAT-2") + "Africa/Maseru", //PSTR("SAST-2") + "Africa/Mbabane", //PSTR("SAST-2") + "Africa/Mogadishu", //PSTR("EAT-3") + "Africa/Monrovia", //PSTR("GMT0") + "Africa/Nairobi", //PSTR("EAT-3") + "Africa/Ndjamena", //PSTR("WAT-1") + "Africa/Niamey", //PSTR("WAT-1") + "Africa/Nouakchott", //PSTR("GMT0") + "Africa/Ouagadougou", //PSTR("GMT0") + "Africa/PortomNovo", //PSTR("WAT-1") + "Africa/Sao_Tome", //PSTR("GMT0") + "Africa/Tripoli", //PSTR("EET-2") + "Africa/Tunis", //PSTR("CET-1") + "Africa/Windhoek", //PSTR("CAT-2") +#endif + + +#if USING_AMERICA + "America/Adak", //PSTR("HST10HDT",M3.2.0",M11.1.0") + "America/Anchorage", //PSTR("AKST9AKDT",M3.2.0",M11.1.0") + "America/Anguilla", //PSTR("AST4") + "America/Antigua", //PSTR("AST4") + "America/Araguaina", //PSTR("<-03>3") + "America/Argentina/Buenos_Aires", //PSTR("<-03>3") + "America/Argentina/Catamarca", //PSTR("<-03>3") + "America/Argentina/Cordoba", //PSTR("<-03>3") + "America/Argentina/Jujuy", //PSTR("<-03>3") + "America/Argentina/La_Rioja", //PSTR("<-03>3") + "America/Argentina/Mendoza", //PSTR("<-03>3") + "America/Argentina/Rio_Gallegos", //PSTR("<-03>3") + "America/Argentina/Salta", //PSTR("<-03>3") + "America/Argentina/San_Juan", //PSTR("<-03>3") + "America/Argentina/San_Luis", //PSTR("<-03>3") + "America/Argentina/Tucuman", //PSTR("<-03>3") + "America/Argentina/Ushuaia", //PSTR("<-03>3") + "America/Aruba", //PSTR("AST4") + "America/Asuncion", //PSTR("<-04>4<-03>",M10.1.0/0",M3.4.0/0") + "America/Atikokan", //PSTR("EST5") + "America/Bahia", //PSTR("<-03>3") + "America/Bahia_Banderas", //PSTR("CST6CDT",M4.1.0",M10.5.0") + "America/Barbados", //PSTR("AST4") + "America/Belem", //PSTR("<-03>3") + "America/Belize", //PSTR("CST6") + "America/BlancmSablon", //PSTR("AST4") + "America/Boa_Vista", //PSTR("<-04>4") + "America/Bogota", //PSTR("<-05>5") + "America/Boise", //PSTR("MST7MDT",M3.2.0",M11.1.0") + "America/Cambridge_Bay", //PSTR("MST7MDT",M3.2.0",M11.1.0") + "America/Campo_Grande", //PSTR("<-04>4") + "America/Cancun", //PSTR("EST5") + "America/Caracas", //PSTR("<-04>4") + "America/Cayenne", //PSTR("<-03>3") + "America/Cayman", //PSTR("EST5") + "America/Chicago", //PSTR("CST6CDT",M3.2.0",M11.1.0") + "America/Chihuahua", //PSTR("MST7MDT",M4.1.0",M10.5.0") + "America/Costa_Rica", //PSTR("CST6") + "America/Creston", //PSTR("MST7") + "America/Cuiaba", //PSTR("<-04>4") + "America/Curacao", //PSTR("AST4") + "America/Danmarkshavn", //PSTR("GMT0") + "America/Dawson", //PSTR("MST7") + "America/Dawson_Creek", //PSTR("MST7") + "America/Denver", //PSTR("MST7MDT",M3.2.0",M11.1.0") + "America/Detroit", //PSTR("EST5EDT",M3.2.0",M11.1.0") + "America/Dominica", //PSTR("AST4") + "America/Edmonton", //PSTR("MST7MDT",M3.2.0",M11.1.0") + "America/Eirunepe", //PSTR("<-05>5") + "America/El_Salvador", //PSTR("CST6") + "America/Fortaleza", //PSTR("<-03>3") + "America/Fort_Nelson", //PSTR("MST7") + "America/Glace_Bay", //PSTR("AST4ADT",M3.2.0",M11.1.0") + "America/Godthab", //PSTR("<-03>3<-02>",M3.5.0/-2",M10.5.0/-1") + "America/Goose_Bay", //PSTR("AST4ADT",M3.2.0",M11.1.0") + "America/Grand_Turk", //PSTR("EST5EDT",M3.2.0",M11.1.0") + "America/Grenada", //PSTR("AST4") + "America/Guadeloupe", //PSTR("AST4") + "America/Guatemala", //PSTR("CST6") + "America/Guayaquil", //PSTR("<-05>5") + "America/Guyana", //PSTR("<-04>4") + "America/Halifax", //PSTR("AST4ADT",M3.2.0",M11.1.0") + "America/Havana", //PSTR("CST5CDT",M3.2.0/0",M11.1.0/1") + "America/Hermosillo", //PSTR("MST7") + "America/Indiana_Indianapolis", //PSTR("EST5EDT",M3.2.0",M11.1.0") + "America/Indiana_Knox", //PSTR("CST6CDT",M3.2.0",M11.1.0") + "America/Indiana_Marengo", //PSTR("EST5EDT",M3.2.0",M11.1.0") + "America/Indiana_Petersburg", //PSTR("EST5EDT",M3.2.0",M11.1.0") + "America/Indiana_Tell_City", //PSTR("CST6CDT",M3.2.0",M11.1.0") + "America/Indiana_Vevay", //PSTR("EST5EDT",M3.2.0",M11.1.0") + "America/Indiana_Vincennes", //PSTR("EST5EDT",M3.2.0",M11.1.0") + "America/Indiana_Winamac", //PSTR("EST5EDT",M3.2.0",M11.1.0") + "America/Inuvik", //PSTR("MST7MDT",M3.2.0",M11.1.0") + "America/Iqaluit", //PSTR("EST5EDT",M3.2.0",M11.1.0") + "America/Jamaica", //PSTR("EST5") + "America/Juneau", //PSTR("AKST9AKDT",M3.2.0",M11.1.0") + "America/Kentucky_Louisville", //PSTR("EST5EDT",M3.2.0",M11.1.0") + "America/Kentucky_Monticello", //PSTR("EST5EDT",M3.2.0",M11.1.0") + "America/Kralendijk", //PSTR("AST4") + "America/La_Paz", //PSTR("<-04>4") + "America/Lima", //PSTR("<-05>5") + "America/Los_Angeles", //PSTR("PST8PDT",M3.2.0",M11.1.0") + "America/Lower_Princes", //PSTR("AST4") + "America/Maceio", //PSTR("<-03>3") + "America/Managua", //PSTR("CST6") + "America/Manaus", //PSTR("<-04>4") + "America/Marigot", //PSTR("AST4") + "America/Martinique", //PSTR("AST4") + "America/Matamoros", //PSTR("CST6CDT",M3.2.0",M11.1.0") + "America/Mazatlan", //PSTR("MST7MDT",M4.1.0",M10.5.0") + "America/Menominee", //PSTR("CST6CDT",M3.2.0",M11.1.0") + "America/Merida", //PSTR("CST6CDT",M4.1.0",M10.5.0") + "America/Metlakatla", //PSTR("AKST9AKDT",M3.2.0",M11.1.0") + "America/Mexico_City", //PSTR("CST6CDT",M4.1.0",M10.5.0") + "America/Miquelon", //PSTR("<-03>3<-02>",M3.2.0",M11.1.0") + "America/Moncton", //PSTR("AST4ADT",M3.2.0",M11.1.0") + "America/Monterrey", //PSTR("CST6CDT",M4.1.0",M10.5.0") + "America/Montevideo", //PSTR("<-03>3") + "America/Montreal", //PSTR("EST5EDT",M3.2.0",M11.1.0") + "America/Montserrat", //PSTR("AST4") + "America/Nassau", //PSTR("EST5EDT",M3.2.0",M11.1.0") + "America/New_York", //PSTR("EST5EDT",M3.2.0",M11.1.0") + "America/Nipigon", //PSTR("EST5EDT",M3.2.0",M11.1.0") + "America/Nome", //PSTR("AKST9AKDT",M3.2.0",M11.1.0") + "America/Noronha", //PSTR("<-02>2") + "America/North_Dakota_Beulah", //PSTR("CST6CDT",M3.2.0",M11.1.0") + "America/North_Dakota_Center", //PSTR("CST6CDT",M3.2.0",M11.1.0") + "America/North_Dakota_New_Salem", //PSTR("CST6CDT",M3.2.0",M11.1.0") + "America/Ojinaga", //PSTR("MST7MDT",M3.2.0",M11.1.0") + "America/Panama", //PSTR("EST5") + "America/Pangnirtung", //PSTR("EST5EDT",M3.2.0",M11.1.0") + "America/Paramaribo", //PSTR("<-03>3") + "America/Phoenix", //PSTR("MST7") + "America/PortmaumPrince", //PSTR("EST5EDT",M3.2.0",M11.1.0") + "America/Port_of_Spain", //PSTR("AST4") + "America/Porto_Velho", //PSTR("<-04>4") + "America/Puerto_Rico", //PSTR("AST4") + "America/Punta_Arenas", //PSTR("<-03>3") + "America/Rainy_River", //PSTR("CST6CDT",M3.2.0",M11.1.0") + "America/Rankin_Inlet", //PSTR("CST6CDT",M3.2.0",M11.1.0") + "America/Recife", //PSTR("<-03>3") + "America/Regina", //PSTR("CST6") + "America/Resolute", //PSTR("CST6CDT",M3.2.0",M11.1.0") + "America/Rio_Branco", //PSTR("<-05>5") + "America/Santarem", //PSTR("<-03>3") + "America/Santiago", //PSTR("<-04>4<-03>",M9.1.6/24",M4.1.6/24") + "America/Santo_Domingo", //PSTR("AST4") + "America/Sao_Paulo", //PSTR("<-03>3") + "America/Scoresbysund", //PSTR("<-01>1<+00>",M3.5.0/0",M10.5.0/1") + "America/Sitka", //PSTR("AKST9AKDT",M3.2.0",M11.1.0") + "America/St_Barthelemy", //PSTR("AST4") + "America/St_Johns", //PSTR("NST3:30NDT",M3.2.0",M11.1.0") + "America/St_Kitts", //PSTR("AST4") + "America/St_Lucia", //PSTR("AST4") + "America/St_Thomas", //PSTR("AST4") + "America/St_Vincent", //PSTR("AST4") + "America/Swift_Current", //PSTR("CST6") + "America/Tegucigalpa", //PSTR("CST6") + "America/Thule", //PSTR("AST4ADT",M3.2.0",M11.1.0") + "America/Thunder_Bay", //PSTR("EST5EDT",M3.2.0",M11.1.0") + "America/Tijuana", //PSTR("PST8PDT",M3.2.0",M11.1.0") + "America/Toronto", //PSTR("EST5EDT",M3.2.0",M11.1.0") + "America/Tortola", //PSTR("AST4") + "America/Vancouver", //PSTR("PST8PDT",M3.2.0",M11.1.0") + "America/Whitehorse", //PSTR("MST7") + "America/Winnipeg", //PSTR("CST6CDT",M3.2.0",M11.1.0") + "America/Yakutat", //PSTR("AKST9AKDT",M3.2.0",M11.1.0") + "America/Yellowknife", //PSTR("MST7MDT",M3.2.0",M11.1.0") +#endif + +#if USING_ANTARCTICA + "Antarctica/Casey", //PSTR("<+11>-11") + "Antarctica/Davis", //PSTR("<+07>-7") + "Antarctica/DumontDUrville", //PSTR("<+10>-10") + "Antarctica/Macquarie", //PSTR("AEST-10AEDT",M10.1.0",M4.1.0/3") + "Antarctica/Mawson", //PSTR("<+05>-5") + "Antarctica/McMurdo", //PSTR("NZST-12NZDT",M9.5.0",M4.1.0/3") + "Antarctica/Palmer", //PSTR("<-03>3") + "Antarctica/Rothera", //PSTR("<-03>3") + "Antarctica/Syowa", //PSTR("<+03>-3") + "Antarctica/Troll", //PSTR("<+00>0<+02>-2",M3.5.0/1",M10.5.0/3") + "Antarctica/Vostok", //PSTR("<+06>-6") + "Arctic/Longyearbyen", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3") +#endif + +#if USING_ASIA + "Asia/Aden", //PSTR("<+03>-3") + "Asia/Almaty", //PSTR("<+06>-6") + "Asia/Amman", //PSTR("EET-2EEST",M3.5.4/24",M10.5.5/1") + "Asia/Anadyr", //PSTR("<+12>-12") + "Asia/Aqtau", //PSTR("<+05>-5") + "Asia/Aqtobe", //PSTR("<+05>-5") + "Asia/Ashgabat", //PSTR("<+05>-5") + "Asia/Atyrau", //PSTR("<+05>-5") + "Asia/Baghdad", //PSTR("<+03>-3") + "Asia/Bahrain", //PSTR("<+03>-3") + "Asia/Baku", //PSTR("<+04>-4") + "Asia/Bangkok", //PSTR("<+07>-7") + "Asia/Barnaul", //PSTR("<+07>-7") + "Asia/Beirut", //PSTR("EET-2EEST",M3.5.0/0",M10.5.0/0") + "Asia/Bishkek", //PSTR("<+06>-6") + "Asia/Brunei", //PSTR("<+08>-8") + "Asia/Chita", //PSTR("<+09>-9") + "Asia/Choibalsan", //PSTR("<+08>-8") + "Asia/Colombo", //PSTR("<+0530>-5:30") + "Asia/Damascus", //PSTR("EET-2EEST",M3.5.5/0",M10.5.5/0") + "Asia/Dhaka", //PSTR("<+06>-6") + "Asia/Dili", //PSTR("<+09>-9") + "Asia/Dubai", //PSTR("<+04>-4") + "Asia/Dushanbe", //PSTR("<+05>-5") + "Asia/Famagusta", //PSTR("EET-2EEST",M3.5.0/3",M10.5.0/4") + "Asia/Gaza", //PSTR("EET-2EEST",M3.4.4/48",M10.4.4/49") + "Asia/Hebron", //PSTR("EET-2EEST",M3.4.4/48",M10.4.4/49") + "Asia/Ho_Chi_Minh", //PSTR("<+07>-7") + "Asia/Hong_Kong", //PSTR("HKT-8") + "Asia/Hovd", //PSTR("<+07>-7") + "Asia/Irkutsk", //PSTR("<+08>-8") + "Asia/Jakarta", //PSTR("WIB-7") + "Asia/Jayapura", //PSTR("WIT-9") + "Asia/Jerusalem", //PSTR("IST-2IDT",M3.4.4/26",M10.5.0") + "Asia/Kabul", //PSTR("<+0430>-4:30") + "Asia/Kamchatka", //PSTR("<+12>-12") + "Asia/Karachi", //PSTR("PKT-5") + "Asia/Kathmandu", //PSTR("<+0545>-5:45") + "Asia/Khandyga", //PSTR("<+09>-9") + "Asia/Kolkata", //PSTR("IST-5:30") + "Asia/Krasnoyarsk", //PSTR("<+07>-7") + "Asia/Kuala_Lumpur", //PSTR("<+08>-8") + "Asia/Kuching", //PSTR("<+08>-8") + "Asia/Kuwait", //PSTR("<+03>-3") + "Asia/Macau", //PSTR("CST-8") + "Asia/Magadan", //PSTR("<+11>-11") + "Asia/Makassar", //PSTR("WITA-8") + "Asia/Manila", //PSTR("PST-8") + "Asia/Muscat", //PSTR("<+04>-4") + "Asia/Nicosia", //PSTR("EET-2EEST",M3.5.0/3",M10.5.0/4") + "Asia/Novokuznetsk", //PSTR("<+07>-7") + "Asia/Novosibirsk", //PSTR("<+07>-7") + "Asia/Omsk", //PSTR("<+06>-6") + "Asia/Oral", //PSTR("<+05>-5") + "Asia/Phnom_Penh", //PSTR("<+07>-7") + "Asia/Pontianak", //PSTR("WIB-7") + "Asia/Pyongyang", //PSTR("KST-9") + "Asia/Qatar", //PSTR("<+03>-3") + "Asia/Qyzylorda", //PSTR("<+05>-5") + "Asia/Riyadh", //PSTR("<+03>-3") + "Asia/Sakhalin", //PSTR("<+11>-11") + "Asia/Samarkand", //PSTR("<+05>-5") + "Asia/Seoul", //PSTR("KST-9") + "Asia/Shanghai", //PSTR("CST-8") + "Asia/Singapore", //PSTR("<+08>-8") + "Asia/Srednekolymsk", //PSTR("<+11>-11") + "Asia/Taipei", //PSTR("CST-8") + "Asia/Tashkent", //PSTR("<+05>-5") + "Asia/Tbilisi", //PSTR("<+04>-4") + "Asia/Tehran", //PSTR("<+0330>-3:30<+0430>",J79/24",J263/24") + "Asia/Thimphu", //PSTR("<+06>-6") + "Asia/Tokyo", //PSTR("JST-9") + "Asia/Tomsk", //PSTR("<+07>-7") + "Asia/Ulaanbaatar", //PSTR("<+08>-8") + "Asia/Urumqi", //PSTR("<+06>-6") + "Asia/UstmNera", //PSTR("<+10>-10") + "Asia/Vientiane", //PSTR("<+07>-7") + "Asia/Vladivostok", //PSTR("<+10>-10") + "Asia/Yakutsk", //PSTR("<+09>-9") + "Asia/Yangon", //PSTR("<+0630>-6:30") + "Asia/Yekaterinburg", //PSTR("<+05>-5") + "Asia/Yerevan", //PSTR("<+04>-4") +#endif + +#if USING_ATLANTIC + "Atlantic/Azores", //PSTR("<-01>1<+00>",M3.5.0/0",M10.5.0/1") + "Atlantic/Bermuda", //PSTR("AST4ADT",M3.2.0",M11.1.0") + "Atlantic/Canary", //PSTR("WET0WEST",M3.5.0/1",M10.5.0") + "Atlantic/Cape_Verde", //PSTR("<-01>1") + "Atlantic/Faroe", //PSTR("WET0WEST",M3.5.0/1",M10.5.0") + "Atlantic/Madeira", //PSTR("WET0WEST",M3.5.0/1",M10.5.0") + "Atlantic/Reykjavik", //PSTR("GMT0") + "Atlantic/South_Georgia", //PSTR("<-02>2") + "Atlantic/Stanley", //PSTR("<-03>3") + "Atlantic/St_Helena", //PSTR("GMT0") +#endif + +#if USING_AUSTRALIA + "Australia/Adelaide", //PSTR("ACST-9:30ACDT",M10.1.0",M4.1.0/3") + "Australia/Brisbane", //PSTR("AEST-10") + "Australia/Broken_Hill", //PSTR("ACST-9:30ACDT",M10.1.0",M4.1.0/3") + "Australia/Currie", //PSTR("AEST-10AEDT",M10.1.0",M4.1.0/3") + "Australia/Darwin", //PSTR("ACST-9:30") + "Australia/Eucla", //PSTR("<+0845>-8:45") + "Australia/Hobart", //PSTR("AEST-10AEDT",M10.1.0",M4.1.0/3") + "Australia/Lindeman", //PSTR("AEST-10") + "Australia/Lord_Howe", //PSTR("<+1030>-10:30<+11>-11",M10.1.0",M4.1.0") + "Australia/Melbourne", //PSTR("AEST-10AEDT",M10.1.0",M4.1.0/3") + "Australia/Perth", //PSTR("AWST-8") + "Australia/Sydney", //PSTR("AEST-10AEDT",M10.1.0",M4.1.0/3") +#endif + +#if USING_EUROPE + "Europe/Amsterdam", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3") + "Europe/Andorra", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3") + "Europe/Astrakhan", //PSTR("<+04>-4") + "Europe/Athens", //PSTR("EET-2EEST",M3.5.0/3",M10.5.0/4") + "Europe/Belgrade", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3") + "Europe/Berlin", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3") + "Europe/Bratislava", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3") + "Europe/Brussels", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3") + "Europe/Bucharest", //PSTR("EET-2EEST",M3.5.0/3",M10.5.0/4") + "Europe/Budapest", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3") + "Europe/Busingen", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3") + "Europe/Chisinau", //PSTR("EET-2EEST",M3.5.0",M10.5.0/3") + "Europe/Copenhagen", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3") + "Europe/Dublin", //PSTR("IST-1GMT0",M10.5.0",M3.5.0/1") + "Europe/Gibraltar", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3") + "Europe/Guernsey", //PSTR("GMT0BST",M3.5.0/1",M10.5.0") + "Europe/Helsinki", //PSTR("EET-2EEST",M3.5.0/3",M10.5.0/4") + "Europe/Isle_of_Man", //PSTR("GMT0BST",M3.5.0/1",M10.5.0") + "Europe/Istanbul", //PSTR("<+03>-3") + "Europe/Jersey", //PSTR("GMT0BST",M3.5.0/1",M10.5.0") + "Europe/Kaliningrad", //PSTR("EET-2") + "Europe/Kiev", //PSTR("EET-2EEST",M3.5.0/3",M10.5.0/4") + "Europe/Kirov", //PSTR("<+03>-3") + "Europe/Lisbon", //PSTR("WET0WEST",M3.5.0/1",M10.5.0") + "Europe/Ljubljana", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3") + "Europe/London", //PSTR("GMT0BST",M3.5.0/1",M10.5.0") + "Europe/Luxembourg", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3") + "Europe/Madrid", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3") + "Europe/Malta", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3") + "Europe/Mariehamn", //PSTR("EET-2EEST",M3.5.0/3",M10.5.0/4") + "Europe/Minsk", //PSTR("<+03>-3") + "Europe/Monaco", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3") + "Europe/Moscow", //PSTR("MSK-3") + "Europe/Oslo", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3") + "Europe/Paris", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3") + "Europe/Podgorica", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3") + "Europe/Prague", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3") + "Europe/Riga", //PSTR("EET-2EEST",M3.5.0/3",M10.5.0/4") + "Europe/Rome", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3") + "Europe/Samara", //PSTR("<+04>-4") + "Europe/San_Marino", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3") + "Europe/Sarajevo", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3") + "Europe/Saratov", //PSTR("<+04>-4") + "Europe/Simferopol", //PSTR("MSK-3") + "Europe/Skopje", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3") + "Europe/Sofia", //PSTR("EET-2EEST",M3.5.0/3",M10.5.0/4") + "Europe/Stockholm", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3") + "Europe/Tallinn", //PSTR("EET-2EEST",M3.5.0/3",M10.5.0/4") + "Europe/Tirane", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3") + "Europe/Ulyanovsk", //PSTR("<+04>-4") + "Europe/Uzhgorod", //PSTR("EET-2EEST",M3.5.0/3",M10.5.0/4") + "Europe/Vaduz", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3") + "Europe/Vatican", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3") + "Europe/Vienna", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3") + "Europe/Vilnius", //PSTR("EET-2EEST",M3.5.0/3",M10.5.0/4") + "Europe/Volgograd", //PSTR("<+04>-4") + "Europe/Warsaw", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3") + "Europe/Zagreb", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3") + "Europe/Zaporozhye", //PSTR("EET-2EEST",M3.5.0/3",M10.5.0/4") + "Europe/Zurich", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3") +#endif + +#if USING_INDIAN + "Indian/Antananarivo", //PSTR("EAT-3") + "Indian/Chagos", //PSTR("<+06>-6") + "Indian/Christmas", //PSTR("<+07>-7") + "Indian/Cocos", //PSTR("<+0630>-6:30") + "Indian/Comoro", //PSTR("EAT-3") + "Indian/Kerguelen", //PSTR("<+05>-5") + "Indian/Mahe", //PSTR("<+04>-4") + "Indian/Maldives", //PSTR("<+05>-5") + "Indian/Mauritius", //PSTR("<+04>-4") + "Indian/Mayotte", //PSTR("EAT-3") + "Indian/Reunion", //PSTR("<+04>-4") +#endif + +#if USING_PACIFIC + "Pacific/Apia", //PSTR("<+13>-13<+14>",M9.5.0/3",M4.1.0/4") + "Pacific/Auckland", //PSTR("NZST-12NZDT",M9.5.0",M4.1.0/3") + "Pacific/Bougainville", //PSTR("<+11>-11") + "Pacific/Chatham", //PSTR("<+1245>-12:45<+1345>",M9.5.0/2:45",M4.1.0/3:45") + "Pacific/Chuuk", //PSTR("<+10>-10") + "Pacific/Easter", //PSTR("<-06>6<-05>",M9.1.6/22",M4.1.6/22") + "Pacific/Efate", //PSTR("<+11>-11") + "Pacific/Enderbury", //PSTR("<+13>-13") + "Pacific/Fakaofo", //PSTR("<+13>-13") + "Pacific/Fiji", //PSTR("<+12>-12<+13>",M11.2.0",M1.2.3/99") + "Pacific/Funafuti", //PSTR("<+12>-12") + "Pacific/Galapagos", //PSTR("<-06>6") + "Pacific/Gambier", //PSTR("<-09>9") + "Pacific/Guadalcanal", //PSTR("<+11>-11") + "Pacific/Guam", //PSTR("ChST-10") + "Pacific/Honolulu", //PSTR("HST10") + "Pacific/Kiritimati", //PSTR("<+14>-14") + "Pacific/Kosrae", //PSTR("<+11>-11") + "Pacific/Kwajalein", //PSTR("<+12>-12") + "Pacific/Majuro", //PSTR("<+12>-12") + "Pacific/Marquesas", //PSTR("<-0930>9:30") + "Pacific/Midway", //PSTR("SST11") + "Pacific/Nauru", //PSTR("<+12>-12") + "Pacific/Niue", //PSTR("<-11>11") + "Pacific/Norfolk", //PSTR("<+11>-11<+12>",M10.1.0",M4.1.0/3") + "Pacific/Noumea", //PSTR("<+11>-11") + "Pacific/Pago_Pago", //PSTR("SST11") + "Pacific/Palau", //PSTR("<+09>-9") + "Pacific/Pitcairn", //PSTR("<-08>8") + "Pacific/Pohnpei", //PSTR("<+11>-11") + "Pacific/Port_Moresby", //PSTR("<+10>-10") + "Pacific/Rarotonga", //PSTR("<-10>10") + "Pacific/Saipan", //PSTR("ChST-10") + "Pacific/Tahiti", //PSTR("<-10>10") + "Pacific/Tarawa", //PSTR("<+12>-12") + "Pacific/Tongatapu", //PSTR("<+13>-13") + "Pacific/Wake", //PSTR("<+12>-12") + "Pacific/Wallis", //PSTR("<+12>-12") +#endif + +#if USING_ETC_GMT + "Etc/GMT", //PSTR("GMT0") + "Etc/GMTm0", //PSTR("GMT0") + "Etc/GMTm1", //PSTR("<+01>-1") + "Etc/GMTm2", //PSTR("<+02>-2") + "Etc/GMTm3", //PSTR("<+03>-3") + "Etc/GMTm4", //PSTR("<+04>-4") + "Etc/GMTm5", //PSTR("<+05>-5") + "Etc/GMTm6", //PSTR("<+06>-6") + "Etc/GMTm7", //PSTR("<+07>-7") + "Etc/GMTm8", //PSTR("<+08>-8") + "Etc/GMTm9", //PSTR("<+09>-9") + "Etc/GMTm10", //PSTR("<+10>-10") + "Etc/GMTm11", //PSTR("<+11>-11") + "Etc/GMTm12", //PSTR("<+12>-12") + "Etc/GMTm13", //PSTR("<+13>-13") + "Etc/GMTm14", //PSTR("<+14>-14") + "Etc/GMT0", //PSTR("GMT0") + "Etc/GMTp0", //PSTR("GMT0") + "Etc/GMTp1", //PSTR("<-01>1") + "Etc/GMTp2", //PSTR("<-02>2") + "Etc/GMTp3", //PSTR("<-03>3") + "Etc/GMTp4", //PSTR("<-04>4") + "Etc/GMTp5", //PSTR("<-05>5") + "Etc/GMTp6", //PSTR("<-06>6") + "Etc/GMTp7", //PSTR("<-07>7") + "Etc/GMTp8", //PSTR("<-08>8") + "Etc/GMTp9", //PSTR("<-09>9") + "Etc/GMTp10", //PSTR("<-10>10") + "Etc/GMTp11", //PSTR("<-11>11") + "Etc/GMTp12", //PSTR("<-12>12") + "Etc/UCT", //PSTR("UTC0") + "Etc/UTC", //PSTR("UTC0") + "Etc/Greenwich", //PSTR("GMT0") + "Etc/Universal", //PSTR("UTC0") + "Etc/Zulu", //PSTR("UTC0") +#endif +}; + +//////////////////////////////////////////////////////////// + +static const char ESP_TZ_NAME[][TIMEZONE_MAX_LEN] /*PROGMEM*/ = +{ +#if USING_AFRICA + TZ_Africa_Abidjan, //PSTR("GMT0") + TZ_Africa_Accra, //PSTR("GMT0") + TZ_Africa_Addis_Ababa, //PSTR("EAT-3") + TZ_Africa_Algiers, //PSTR("CET-1") + TZ_Africa_Asmara, //PSTR("EAT-3") + TZ_Africa_Bamako, //PSTR("GMT0") + TZ_Africa_Bangui, //PSTR("WAT-1") + TZ_Africa_Banjul, //PSTR("GMT0") + TZ_Africa_Bissau, //PSTR("GMT0") + TZ_Africa_Blantyre, //PSTR("CAT-2") + TZ_Africa_Brazzaville, //PSTR("WAT-1") + TZ_Africa_Bujumbura, //PSTR("CAT-2") + TZ_Africa_Cairo, //PSTR("EET-2") + TZ_Africa_Casablanca, //PSTR("<+01>-1") + TZ_Africa_Ceuta, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3") + TZ_Africa_Conakry, //PSTR("GMT0") + TZ_Africa_Dakar, //PSTR("GMT0") + TZ_Africa_Dar_es_Salaam, //PSTR("EAT-3") + TZ_Africa_Djibouti, //PSTR("EAT-3") + TZ_Africa_Douala, //PSTR("WAT-1") + TZ_Africa_El_Aaiun, //PSTR("<+01>-1") + TZ_Africa_Freetown, //PSTR("GMT0") + TZ_Africa_Gaborone, //PSTR("CAT-2") + TZ_Africa_Harare, //PSTR("CAT-2") + TZ_Africa_Johannesburg, //PSTR("SAST-2") + TZ_Africa_Juba, //PSTR("EAT-3") + TZ_Africa_Kampala, //PSTR("EAT-3") + TZ_Africa_Khartoum, //PSTR("CAT-2") + TZ_Africa_Kigali, //PSTR("CAT-2") + TZ_Africa_Kinshasa, //PSTR("WAT-1") + TZ_Africa_Lagos, //PSTR("WAT-1") + TZ_Africa_Libreville, //PSTR("WAT-1") + TZ_Africa_Lome, //PSTR("GMT0") + TZ_Africa_Luanda, //PSTR("WAT-1") + TZ_Africa_Lubumbashi, //PSTR("CAT-2") + TZ_Africa_Lusaka, //PSTR("CAT-2") + TZ_Africa_Malabo, //PSTR("WAT-1") + TZ_Africa_Maputo, //PSTR("CAT-2") + TZ_Africa_Maseru, //PSTR("SAST-2") + TZ_Africa_Mbabane, //PSTR("SAST-2") + TZ_Africa_Mogadishu, //PSTR("EAT-3") + TZ_Africa_Monrovia, //PSTR("GMT0") + TZ_Africa_Nairobi, //PSTR("EAT-3") + TZ_Africa_Ndjamena, //PSTR("WAT-1") + TZ_Africa_Niamey, //PSTR("WAT-1") + TZ_Africa_Nouakchott, //PSTR("GMT0") + TZ_Africa_Ouagadougou, //PSTR("GMT0") + TZ_Africa_PortomNovo, //PSTR("WAT-1") + TZ_Africa_Sao_Tome, //PSTR("GMT0") + TZ_Africa_Tripoli, //PSTR("EET-2") + TZ_Africa_Tunis, //PSTR("CET-1") + TZ_Africa_Windhoek, //PSTR("CAT-2") +#endif + +#if USING_AMERICA + TZ_America_Adak, //PSTR("HST10HDT,M3.2.0,M11.1.0") + TZ_America_Anchorage, //PSTR("AKST9AKDT,M3.2.0,M11.1.0") + TZ_America_Anguilla, //PSTR("AST4") + TZ_America_Antigua, //PSTR("AST4") + TZ_America_Araguaina, //PSTR("<-03>3") + TZ_America_Argentina_Buenos_Aires, //PSTR("<-03>3") + TZ_America_Argentina_Catamarca, //PSTR("<-03>3") + TZ_America_Argentina_Cordoba, //PSTR("<-03>3") + TZ_America_Argentina_Jujuy, //PSTR("<-03>3") + TZ_America_Argentina_La_Rioja, //PSTR("<-03>3") + TZ_America_Argentina_Mendoza, //PSTR("<-03>3") + TZ_America_Argentina_Rio_Gallegos, //PSTR("<-03>3") + TZ_America_Argentina_Salta, //PSTR("<-03>3") + TZ_America_Argentina_San_Juan, //PSTR("<-03>3") + TZ_America_Argentina_San_Luis, //PSTR("<-03>3") + TZ_America_Argentina_Tucuman, //PSTR("<-03>3") + TZ_America_Argentina_Ushuaia, //PSTR("<-03>3") + TZ_America_Aruba, //PSTR("AST4") + TZ_America_Asuncion, //PSTR("<-04>4<-03>,M10.1.0/0,M3.4.0/0") + TZ_America_Atikokan, //PSTR("EST5") + TZ_America_Bahia, //PSTR("<-03>3") + TZ_America_Bahia_Banderas, //PSTR("CST6CDT,M4.1.0,M10.5.0") + TZ_America_Barbados, //PSTR("AST4") + TZ_America_Belem, //PSTR("<-03>3") + TZ_America_Belize, //PSTR("CST6") + TZ_America_BlancmSablon, //PSTR("AST4") + TZ_America_Boa_Vista, //PSTR("<-04>4") + TZ_America_Bogota, //PSTR("<-05>5") + TZ_America_Boise, //PSTR("MST7MDT,M3.2.0,M11.1.0") + TZ_America_Cambridge_Bay, //PSTR("MST7MDT,M3.2.0,M11.1.0") + TZ_America_Campo_Grande, //PSTR("<-04>4") + TZ_America_Cancun, //PSTR("EST5") + TZ_America_Caracas, //PSTR("<-04>4") + TZ_America_Cayenne, //PSTR("<-03>3") + TZ_America_Cayman, //PSTR("EST5") + TZ_America_Chicago, //PSTR("CST6CDT,M3.2.0,M11.1.0") + TZ_America_Chihuahua, //PSTR("MST7MDT,M4.1.0,M10.5.0") + TZ_America_Costa_Rica, //PSTR("CST6") + TZ_America_Creston, //PSTR("MST7") + TZ_America_Cuiaba, //PSTR("<-04>4") + TZ_America_Curacao, //PSTR("AST4") + TZ_America_Danmarkshavn, //PSTR("GMT0") + TZ_America_Dawson, //PSTR("MST7") + TZ_America_Dawson_Creek, //PSTR("MST7") + TZ_America_Denver, //PSTR("MST7MDT,M3.2.0,M11.1.0") + TZ_America_Detroit, //PSTR("EST5EDT,M3.2.0,M11.1.0") + TZ_America_Dominica, //PSTR("AST4") + TZ_America_Edmonton, //PSTR("MST7MDT,M3.2.0,M11.1.0") + TZ_America_Eirunepe, //PSTR("<-05>5") + TZ_America_El_Salvador, //PSTR("CST6") + TZ_America_Fortaleza, //PSTR("<-03>3") + TZ_America_Fort_Nelson, //PSTR("MST7") + TZ_America_Glace_Bay, //PSTR("AST4ADT,M3.2.0,M11.1.0") + TZ_America_Godthab, //PSTR("<-03>3<-02>,M3.5.0/-2,M10.5.0/-1") + TZ_America_Goose_Bay, //PSTR("AST4ADT,M3.2.0,M11.1.0") + TZ_America_Grand_Turk, //PSTR("EST5EDT,M3.2.0,M11.1.0") + TZ_America_Grenada, //PSTR("AST4") + TZ_America_Guadeloupe, //PSTR("AST4") + TZ_America_Guatemala, //PSTR("CST6") + TZ_America_Guayaquil, //PSTR("<-05>5") + TZ_America_Guyana, //PSTR("<-04>4") + TZ_America_Halifax, //PSTR("AST4ADT,M3.2.0,M11.1.0") + TZ_America_Havana, //PSTR("CST5CDT,M3.2.0/0,M11.1.0/1") + TZ_America_Hermosillo, //PSTR("MST7") + TZ_America_Indiana_Indianapolis, //PSTR("EST5EDT,M3.2.0,M11.1.0") + TZ_America_Indiana_Knox, //PSTR("CST6CDT,M3.2.0,M11.1.0") + TZ_America_Indiana_Marengo, //PSTR("EST5EDT,M3.2.0,M11.1.0") + TZ_America_Indiana_Petersburg, //PSTR("EST5EDT,M3.2.0,M11.1.0") + TZ_America_Indiana_Tell_City, //PSTR("CST6CDT,M3.2.0,M11.1.0") + TZ_America_Indiana_Vevay, //PSTR("EST5EDT,M3.2.0,M11.1.0") + TZ_America_Indiana_Vincennes, //PSTR("EST5EDT,M3.2.0,M11.1.0") + TZ_America_Indiana_Winamac, //PSTR("EST5EDT,M3.2.0,M11.1.0") + TZ_America_Inuvik, //PSTR("MST7MDT,M3.2.0,M11.1.0") + TZ_America_Iqaluit, //PSTR("EST5EDT,M3.2.0,M11.1.0") + TZ_America_Jamaica, //PSTR("EST5") + TZ_America_Juneau, //PSTR("AKST9AKDT,M3.2.0,M11.1.0") + TZ_America_Kentucky_Louisville, //PSTR("EST5EDT,M3.2.0,M11.1.0") + TZ_America_Kentucky_Monticello, //PSTR("EST5EDT,M3.2.0,M11.1.0") + TZ_America_Kralendijk, //PSTR("AST4") + TZ_America_La_Paz, //PSTR("<-04>4") + TZ_America_Lima, //PSTR("<-05>5") + TZ_America_Los_Angeles, //PSTR("PST8PDT,M3.2.0,M11.1.0") + TZ_America_Lower_Princes, //PSTR("AST4") + TZ_America_Maceio, //PSTR("<-03>3") + TZ_America_Managua, //PSTR("CST6") + TZ_America_Manaus, //PSTR("<-04>4") + TZ_America_Marigot, //PSTR("AST4") + TZ_America_Martinique, //PSTR("AST4") + TZ_America_Matamoros, //PSTR("CST6CDT,M3.2.0,M11.1.0") + TZ_America_Mazatlan, //PSTR("MST7MDT,M4.1.0,M10.5.0") + TZ_America_Menominee, //PSTR("CST6CDT,M3.2.0,M11.1.0") + TZ_America_Merida, //PSTR("CST6CDT,M4.1.0,M10.5.0") + TZ_America_Metlakatla, //PSTR("AKST9AKDT,M3.2.0,M11.1.0") + TZ_America_Mexico_City, //PSTR("CST6CDT,M4.1.0,M10.5.0") + TZ_America_Miquelon, //PSTR("<-03>3<-02>,M3.2.0,M11.1.0") + TZ_America_Moncton, //PSTR("AST4ADT,M3.2.0,M11.1.0") + TZ_America_Monterrey, //PSTR("CST6CDT,M4.1.0,M10.5.0") + TZ_America_Montevideo, //PSTR("<-03>3") + TZ_America_Montreal, //PSTR("EST5EDT,M3.2.0,M11.1.0") + TZ_America_Montserrat, //PSTR("AST4") + TZ_America_Nassau, //PSTR("EST5EDT,M3.2.0,M11.1.0") + TZ_America_New_York, //PSTR("EST5EDT,M3.2.0,M11.1.0") + TZ_America_Nipigon, //PSTR("EST5EDT,M3.2.0,M11.1.0") + TZ_America_Nome, //PSTR("AKST9AKDT,M3.2.0,M11.1.0") + TZ_America_Noronha, //PSTR("<-02>2") + TZ_America_North_Dakota_Beulah, //PSTR("CST6CDT,M3.2.0,M11.1.0") + TZ_America_North_Dakota_Center, //PSTR("CST6CDT,M3.2.0,M11.1.0") + TZ_America_North_Dakota_New_Salem, //PSTR("CST6CDT,M3.2.0,M11.1.0") + TZ_America_Ojinaga, //PSTR("MST7MDT,M3.2.0,M11.1.0") + TZ_America_Panama, //PSTR("EST5") + TZ_America_Pangnirtung, //PSTR("EST5EDT,M3.2.0,M11.1.0") + TZ_America_Paramaribo, //PSTR("<-03>3") + TZ_America_Phoenix, //PSTR("MST7") + TZ_America_PortmaumPrince, //PSTR("EST5EDT,M3.2.0,M11.1.0") + TZ_America_Port_of_Spain, //PSTR("AST4") + TZ_America_Porto_Velho, //PSTR("<-04>4") + TZ_America_Puerto_Rico, //PSTR("AST4") + TZ_America_Punta_Arenas, //PSTR("<-03>3") + TZ_America_Rainy_River, //PSTR("CST6CDT,M3.2.0,M11.1.0") + TZ_America_Rankin_Inlet, //PSTR("CST6CDT,M3.2.0,M11.1.0") + TZ_America_Recife, //PSTR("<-03>3") + TZ_America_Regina, //PSTR("CST6") + TZ_America_Resolute, //PSTR("CST6CDT,M3.2.0,M11.1.0") + TZ_America_Rio_Branco, //PSTR("<-05>5") + TZ_America_Santarem, //PSTR("<-03>3") + TZ_America_Santiago, //PSTR("<-04>4<-03>,M9.1.6/24,M4.1.6/24") + TZ_America_Santo_Domingo, //PSTR("AST4") + TZ_America_Sao_Paulo, //PSTR("<-03>3") + TZ_America_Scoresbysund, //PSTR("<-01>1<+00>,M3.5.0/0,M10.5.0/1") + TZ_America_Sitka, //PSTR("AKST9AKDT,M3.2.0,M11.1.0") + TZ_America_St_Barthelemy, //PSTR("AST4") + TZ_America_St_Johns, //PSTR("NST3:30NDT,M3.2.0,M11.1.0") + TZ_America_St_Kitts, //PSTR("AST4") + TZ_America_St_Lucia, //PSTR("AST4") + TZ_America_St_Thomas, //PSTR("AST4") + TZ_America_St_Vincent, //PSTR("AST4") + TZ_America_Swift_Current, //PSTR("CST6") + TZ_America_Tegucigalpa, //PSTR("CST6") + TZ_America_Thule, //PSTR("AST4ADT,M3.2.0,M11.1.0") + TZ_America_Thunder_Bay, //PSTR("EST5EDT,M3.2.0,M11.1.0") + TZ_America_Tijuana, //PSTR("PST8PDT,M3.2.0,M11.1.0") + TZ_America_Toronto, //PSTR("EST5EDT,M3.2.0,M11.1.0") + TZ_America_Tortola, //PSTR("AST4") + TZ_America_Vancouver, //PSTR("PST8PDT,M3.2.0,M11.1.0") + TZ_America_Whitehorse, //PSTR("MST7") + TZ_America_Winnipeg, //PSTR("CST6CDT,M3.2.0,M11.1.0") + TZ_America_Yakutat, //PSTR("AKST9AKDT,M3.2.0,M11.1.0") + TZ_America_Yellowknife, //PSTR("MST7MDT,M3.2.0,M11.1.0") +#endif + +#if USING_ANTARCTICA + TZ_Antarctica_Casey, //PSTR("<+11>-11") + TZ_Antarctica_Davis, //PSTR("<+07>-7") + TZ_Antarctica_DumontDUrville, //PSTR("<+10>-10") + TZ_Antarctica_Macquarie, //PSTR("AEST-10AEDT,M10.1.0,M4.1.0/3") + TZ_Antarctica_Mawson, //PSTR("<+05>-5") + TZ_Antarctica_McMurdo, //PSTR("NZST-12NZDT,M9.5.0,M4.1.0/3") + TZ_Antarctica_Palmer, //PSTR("<-03>3") + TZ_Antarctica_Rothera, //PSTR("<-03>3") + TZ_Antarctica_Syowa, //PSTR("<+03>-3") + TZ_Antarctica_Troll, //PSTR("<+00>0<+02>-2,M3.5.0/1,M10.5.0/3") + TZ_Antarctica_Vostok, //PSTR("<+06>-6") + TZ_Arctic_Longyearbyen, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3") +#endif + + +#if USING_ASIA + TZ_Asia_Aden, //PSTR("<+03>-3") + TZ_Asia_Almaty, //PSTR("<+06>-6") + TZ_Asia_Amman, //PSTR("EET-2EEST,M3.5.4/24,M10.5.5/1") + TZ_Asia_Anadyr, //PSTR("<+12>-12") + TZ_Asia_Aqtau, //PSTR("<+05>-5") + TZ_Asia_Aqtobe, //PSTR("<+05>-5") + TZ_Asia_Ashgabat, //PSTR("<+05>-5") + TZ_Asia_Atyrau, //PSTR("<+05>-5") + TZ_Asia_Baghdad, //PSTR("<+03>-3") + TZ_Asia_Bahrain, //PSTR("<+03>-3") + TZ_Asia_Baku, //PSTR("<+04>-4") + TZ_Asia_Bangkok, //PSTR("<+07>-7") + TZ_Asia_Barnaul, //PSTR("<+07>-7") + TZ_Asia_Beirut, //PSTR("EET-2EEST,M3.5.0/0,M10.5.0/0") + TZ_Asia_Bishkek, //PSTR("<+06>-6") + TZ_Asia_Brunei, //PSTR("<+08>-8") + TZ_Asia_Chita, //PSTR("<+09>-9") + TZ_Asia_Choibalsan, //PSTR("<+08>-8") + TZ_Asia_Colombo, //PSTR("<+0530>-5:30") + TZ_Asia_Damascus, //PSTR("EET-2EEST,M3.5.5/0,M10.5.5/0") + TZ_Asia_Dhaka, //PSTR("<+06>-6") + TZ_Asia_Dili, //PSTR("<+09>-9") + TZ_Asia_Dubai, //PSTR("<+04>-4") + TZ_Asia_Dushanbe, //PSTR("<+05>-5") + TZ_Asia_Famagusta, //PSTR("EET-2EEST,M3.5.0/3,M10.5.0/4") + TZ_Asia_Gaza, //PSTR("EET-2EEST,M3.4.4/48,M10.4.4/49") + TZ_Asia_Hebron, //PSTR("EET-2EEST,M3.4.4/48,M10.4.4/49") + TZ_Asia_Ho_Chi_Minh, //PSTR("<+07>-7") + TZ_Asia_Hong_Kong, //PSTR("HKT-8") + TZ_Asia_Hovd, //PSTR("<+07>-7") + TZ_Asia_Irkutsk, //PSTR("<+08>-8") + TZ_Asia_Jakarta, //PSTR("WIB-7") + TZ_Asia_Jayapura, //PSTR("WIT-9") + TZ_Asia_Jerusalem, //PSTR("IST-2IDT,M3.4.4/26,M10.5.0") + TZ_Asia_Kabul, //PSTR("<+0430>-4:30") + TZ_Asia_Kamchatka, //PSTR("<+12>-12") + TZ_Asia_Karachi, //PSTR("PKT-5") + TZ_Asia_Kathmandu, //PSTR("<+0545>-5:45") + TZ_Asia_Khandyga, //PSTR("<+09>-9") + TZ_Asia_Kolkata, //PSTR("IST-5:30") + TZ_Asia_Krasnoyarsk, //PSTR("<+07>-7") + TZ_Asia_Kuala_Lumpur, //PSTR("<+08>-8") + TZ_Asia_Kuching, //PSTR("<+08>-8") + TZ_Asia_Kuwait, //PSTR("<+03>-3") + TZ_Asia_Macau, //PSTR("CST-8") + TZ_Asia_Magadan, //PSTR("<+11>-11") + TZ_Asia_Makassar, //PSTR("WITA-8") + TZ_Asia_Manila, //PSTR("PST-8") + TZ_Asia_Muscat, //PSTR("<+04>-4") + TZ_Asia_Nicosia, //PSTR("EET-2EEST,M3.5.0/3,M10.5.0/4") + TZ_Asia_Novokuznetsk, //PSTR("<+07>-7") + TZ_Asia_Novosibirsk, //PSTR("<+07>-7") + TZ_Asia_Omsk, //PSTR("<+06>-6") + TZ_Asia_Oral, //PSTR("<+05>-5") + TZ_Asia_Phnom_Penh, //PSTR("<+07>-7") + TZ_Asia_Pontianak, //PSTR("WIB-7") + TZ_Asia_Pyongyang, //PSTR("KST-9") + TZ_Asia_Qatar, //PSTR("<+03>-3") + TZ_Asia_Qyzylorda, //PSTR("<+05>-5") + TZ_Asia_Riyadh, //PSTR("<+03>-3") + TZ_Asia_Sakhalin, //PSTR("<+11>-11") + TZ_Asia_Samarkand, //PSTR("<+05>-5") + TZ_Asia_Seoul, //PSTR("KST-9") + TZ_Asia_Shanghai, //PSTR("CST-8") + TZ_Asia_Singapore, //PSTR("<+08>-8") + TZ_Asia_Srednekolymsk, //PSTR("<+11>-11") + TZ_Asia_Taipei, //PSTR("CST-8") + TZ_Asia_Tashkent, //PSTR("<+05>-5") + TZ_Asia_Tbilisi, //PSTR("<+04>-4") + TZ_Asia_Tehran, //PSTR("<+0330>-3:30<+0430>,J79/24,J263/24") + TZ_Asia_Thimphu, //PSTR("<+06>-6") + TZ_Asia_Tokyo, //PSTR("JST-9") + TZ_Asia_Tomsk, //PSTR("<+07>-7") + TZ_Asia_Ulaanbaatar, //PSTR("<+08>-8") + TZ_Asia_Urumqi, //PSTR("<+06>-6") + TZ_Asia_UstmNera, //PSTR("<+10>-10") + TZ_Asia_Vientiane, //PSTR("<+07>-7") + TZ_Asia_Vladivostok, //PSTR("<+10>-10") + TZ_Asia_Yakutsk, //PSTR("<+09>-9") + TZ_Asia_Yangon, //PSTR("<+0630>-6:30") + TZ_Asia_Yekaterinburg, //PSTR("<+05>-5") + TZ_Asia_Yerevan, //PSTR("<+04>-4") +#endif + +#if USING_ATLANTIC + TZ_Atlantic_Azores, //PSTR("<-01>1<+00>,M3.5.0/0,M10.5.0/1") + TZ_Atlantic_Bermuda, //PSTR("AST4ADT,M3.2.0,M11.1.0") + TZ_Atlantic_Canary, //PSTR("WET0WEST,M3.5.0/1,M10.5.0") + TZ_Atlantic_Cape_Verde, //PSTR("<-01>1") + TZ_Atlantic_Faroe, //PSTR("WET0WEST,M3.5.0/1,M10.5.0") + TZ_Atlantic_Madeira, //PSTR("WET0WEST,M3.5.0/1,M10.5.0") + TZ_Atlantic_Reykjavik, //PSTR("GMT0") + TZ_Atlantic_South_Georgia, //PSTR("<-02>2") + TZ_Atlantic_Stanley, //PSTR("<-03>3") + TZ_Atlantic_St_Helena, //PSTR("GMT0") +#endif + +#if USING_AUSTRALIA + TZ_Australia_Adelaide, //PSTR("ACST-9:30ACDT,M10.1.0,M4.1.0/3") + TZ_Australia_Brisbane, //PSTR("AEST-10") + TZ_Australia_Broken_Hill, //PSTR("ACST-9:30ACDT,M10.1.0,M4.1.0/3") + TZ_Australia_Currie, //PSTR("AEST-10AEDT,M10.1.0,M4.1.0/3") + TZ_Australia_Darwin, //PSTR("ACST-9:30") + TZ_Australia_Eucla, //PSTR("<+0845>-8:45") + TZ_Australia_Hobart, //PSTR("AEST-10AEDT,M10.1.0,M4.1.0/3") + TZ_Australia_Lindeman, //PSTR("AEST-10") + TZ_Australia_Lord_Howe, //PSTR("<+1030>-10:30<+11>-11,M10.1.0,M4.1.0") + TZ_Australia_Melbourne, //PSTR("AEST-10AEDT,M10.1.0,M4.1.0/3") + TZ_Australia_Perth, //PSTR("AWST-8") + TZ_Australia_Sydney, //PSTR("AEST-10AEDT,M10.1.0,M4.1.0/3") +#endif + +#if USING_EUROPE + TZ_Europe_Amsterdam, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3") + TZ_Europe_Andorra, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3") + TZ_Europe_Astrakhan, //PSTR("<+04>-4") + TZ_Europe_Athens, //PSTR("EET-2EEST,M3.5.0/3,M10.5.0/4") + TZ_Europe_Belgrade, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3") + TZ_Europe_Berlin, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3") + TZ_Europe_Bratislava, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3") + TZ_Europe_Brussels, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3") + TZ_Europe_Bucharest, //PSTR("EET-2EEST,M3.5.0/3,M10.5.0/4") + TZ_Europe_Budapest, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3") + TZ_Europe_Busingen, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3") + TZ_Europe_Chisinau, //PSTR("EET-2EEST,M3.5.0,M10.5.0/3") + TZ_Europe_Copenhagen, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3") + TZ_Europe_Dublin, //PSTR("IST-1GMT0,M10.5.0,M3.5.0/1") + TZ_Europe_Gibraltar, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3") + TZ_Europe_Guernsey, //PSTR("GMT0BST,M3.5.0/1,M10.5.0") + TZ_Europe_Helsinki, //PSTR("EET-2EEST,M3.5.0/3,M10.5.0/4") + TZ_Europe_Isle_of_Man, //PSTR("GMT0BST,M3.5.0/1,M10.5.0") + TZ_Europe_Istanbul, //PSTR("<+03>-3") + TZ_Europe_Jersey, //PSTR("GMT0BST,M3.5.0/1,M10.5.0") + TZ_Europe_Kaliningrad, //PSTR("EET-2") + TZ_Europe_Kiev, //PSTR("EET-2EEST,M3.5.0/3,M10.5.0/4") + TZ_Europe_Kirov, //PSTR("<+03>-3") + TZ_Europe_Lisbon, //PSTR("WET0WEST,M3.5.0/1,M10.5.0") + TZ_Europe_Ljubljana, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3") + TZ_Europe_London, //PSTR("GMT0BST,M3.5.0/1,M10.5.0") + TZ_Europe_Luxembourg, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3") + TZ_Europe_Madrid, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3") + TZ_Europe_Malta, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3") + TZ_Europe_Mariehamn, //PSTR("EET-2EEST,M3.5.0/3,M10.5.0/4") + TZ_Europe_Minsk, //PSTR("<+03>-3") + TZ_Europe_Monaco, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3") + TZ_Europe_Moscow, //PSTR("MSK-3") + TZ_Europe_Oslo, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3") + TZ_Europe_Paris, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3") + TZ_Europe_Podgorica, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3") + TZ_Europe_Prague, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3") + TZ_Europe_Riga, //PSTR("EET-2EEST,M3.5.0/3,M10.5.0/4") + TZ_Europe_Rome, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3") + TZ_Europe_Samara, //PSTR("<+04>-4") + TZ_Europe_San_Marino, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3") + TZ_Europe_Sarajevo, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3") + TZ_Europe_Saratov, //PSTR("<+04>-4") + TZ_Europe_Simferopol, //PSTR("MSK-3") + TZ_Europe_Skopje, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3") + TZ_Europe_Sofia, //PSTR("EET-2EEST,M3.5.0/3,M10.5.0/4") + TZ_Europe_Stockholm, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3") + TZ_Europe_Tallinn, //PSTR("EET-2EEST,M3.5.0/3,M10.5.0/4") + TZ_Europe_Tirane, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3") + TZ_Europe_Ulyanovsk, //PSTR("<+04>-4") + TZ_Europe_Uzhgorod, //PSTR("EET-2EEST,M3.5.0/3,M10.5.0/4") + TZ_Europe_Vaduz, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3") + TZ_Europe_Vatican, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3") + TZ_Europe_Vienna, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3") + TZ_Europe_Vilnius, //PSTR("EET-2EEST,M3.5.0/3,M10.5.0/4") + TZ_Europe_Volgograd, //PSTR("<+04>-4") + TZ_Europe_Warsaw, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3") + TZ_Europe_Zagreb, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3") + TZ_Europe_Zaporozhye, //PSTR("EET-2EEST,M3.5.0/3,M10.5.0/4") + TZ_Europe_Zurich, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3") +#endif + +#if USING_INDIAN + TZ_Indian_Antananarivo, //PSTR("EAT-3") + TZ_Indian_Chagos, //PSTR("<+06>-6") + TZ_Indian_Christmas, //PSTR("<+07>-7") + TZ_Indian_Cocos, //PSTR("<+0630>-6:30") + TZ_Indian_Comoro, //PSTR("EAT-3") + TZ_Indian_Kerguelen, //PSTR("<+05>-5") + TZ_Indian_Mahe, //PSTR("<+04>-4") + TZ_Indian_Maldives, //PSTR("<+05>-5") + TZ_Indian_Mauritius, //PSTR("<+04>-4") + TZ_Indian_Mayotte, //PSTR("EAT-3") + TZ_Indian_Reunion, //PSTR("<+04>-4") +#endif + +#if USING_PACIFIC + TZ_Pacific_Apia, //PSTR("<+13>-13<+14>,M9.5.0/3,M4.1.0/4") + TZ_Pacific_Auckland, //PSTR("NZST-12NZDT,M9.5.0,M4.1.0/3") + TZ_Pacific_Bougainville, //PSTR("<+11>-11") + TZ_Pacific_Chatham, //PSTR("<+1245>-12:45<+1345>,M9.5.0/2:45,M4.1.0/3:45") + TZ_Pacific_Chuuk, //PSTR("<+10>-10") + TZ_Pacific_Easter, //PSTR("<-06>6<-05>,M9.1.6/22,M4.1.6/22") + TZ_Pacific_Efate, //PSTR("<+11>-11") + TZ_Pacific_Enderbury, //PSTR("<+13>-13") + TZ_Pacific_Fakaofo, //PSTR("<+13>-13") + TZ_Pacific_Fiji, //PSTR("<+12>-12<+13>,M11.2.0,M1.2.3/99") + TZ_Pacific_Funafuti, //PSTR("<+12>-12") + TZ_Pacific_Galapagos, //PSTR("<-06>6") + TZ_Pacific_Gambier, //PSTR("<-09>9") + TZ_Pacific_Guadalcanal, //PSTR("<+11>-11") + TZ_Pacific_Guam, //PSTR("ChST-10") + TZ_Pacific_Honolulu, //PSTR("HST10") + TZ_Pacific_Kiritimati, //PSTR("<+14>-14") + TZ_Pacific_Kosrae, //PSTR("<+11>-11") + TZ_Pacific_Kwajalein, //PSTR("<+12>-12") + TZ_Pacific_Majuro, //PSTR("<+12>-12") + TZ_Pacific_Marquesas, //PSTR("<-0930>9:30") + TZ_Pacific_Midway, //PSTR("SST11") + TZ_Pacific_Nauru, //PSTR("<+12>-12") + TZ_Pacific_Niue, //PSTR("<-11>11") + TZ_Pacific_Norfolk, //PSTR("<+11>-11<+12>,M10.1.0,M4.1.0/3") + TZ_Pacific_Noumea, //PSTR("<+11>-11") + TZ_Pacific_Pago_Pago, //PSTR("SST11") + TZ_Pacific_Palau, //PSTR("<+09>-9") + TZ_Pacific_Pitcairn, //PSTR("<-08>8") + TZ_Pacific_Pohnpei, //PSTR("<+11>-11") + TZ_Pacific_Port_Moresby, //PSTR("<+10>-10") + TZ_Pacific_Rarotonga, //PSTR("<-10>10") + TZ_Pacific_Saipan, //PSTR("ChST-10") + TZ_Pacific_Tahiti, //PSTR("<-10>10") + TZ_Pacific_Tarawa, //PSTR("<+12>-12") + TZ_Pacific_Tongatapu, //PSTR("<+13>-13") + TZ_Pacific_Wake, //PSTR("<+12>-12") + TZ_Pacific_Wallis, //PSTR("<+12>-12") +#endif + +#if USING_ETC_GMT + TZ_Etc_GMT, //PSTR("GMT0") + TZ_Etc_GMTm0, //PSTR("GMT0") + TZ_Etc_GMTm1, //PSTR("<+01>-1") + TZ_Etc_GMTm2, //PSTR("<+02>-2") + TZ_Etc_GMTm3, //PSTR("<+03>-3") + TZ_Etc_GMTm4, //PSTR("<+04>-4") + TZ_Etc_GMTm5, //PSTR("<+05>-5") + TZ_Etc_GMTm6, //PSTR("<+06>-6") + TZ_Etc_GMTm7, //PSTR("<+07>-7") + TZ_Etc_GMTm8, //PSTR("<+08>-8") + TZ_Etc_GMTm9, //PSTR("<+09>-9") + TZ_Etc_GMTm10, //PSTR("<+10>-10") + TZ_Etc_GMTm11, //PSTR("<+11>-11") + TZ_Etc_GMTm12, //PSTR("<+12>-12") + TZ_Etc_GMTm13, //PSTR("<+13>-13") + TZ_Etc_GMTm14, //PSTR("<+14>-14") + TZ_Etc_GMT0, //PSTR("GMT0") + TZ_Etc_GMTp0, //PSTR("GMT0") + TZ_Etc_GMTp1, //PSTR("<-01>1") + TZ_Etc_GMTp2, //PSTR("<-02>2") + TZ_Etc_GMTp3, //PSTR("<-03>3") + TZ_Etc_GMTp4, //PSTR("<-04>4") + TZ_Etc_GMTp5, //PSTR("<-05>5") + TZ_Etc_GMTp6, //PSTR("<-06>6") + TZ_Etc_GMTp7, //PSTR("<-07>7") + TZ_Etc_GMTp8, //PSTR("<-08>8") + TZ_Etc_GMTp9, //PSTR("<-09>9") + TZ_Etc_GMTp10, //PSTR("<-10>10") + TZ_Etc_GMTp11, //PSTR("<-11>11") + TZ_Etc_GMTp12, //PSTR("<-12>12") + TZ_Etc_UCT, //PSTR("UTC0") + TZ_Etc_UTC, //PSTR("UTC0") + TZ_Etc_Greenwich, //PSTR("GMT0") + TZ_Etc_Universal, //PSTR("UTC0") + TZ_Etc_Zulu, //PSTR("UTC0") +#endif +}; + +#endif // TZDB_H diff --git a/travis/common.sh b/travis/common.sh new file mode 100644 index 0000000..d115085 --- /dev/null +++ b/travis/common.sh @@ -0,0 +1,51 @@ +#!/bin/bash + +function build_examples() +{ + # track the exit code for this platform + local exit_code=0 + # loop through results and add them to the array + examples=($(find $PWD/examples/ -name "*.pde" -o -name "*.ino")) + + # get the last example in the array + local last="${examples[@]:(-1)}" + + # loop through example sketches + for example in "${examples[@]}"; do + + # store the full path to the example's sketch directory + local example_dir=$(dirname $example) + + # store the filename for the example without the path + local example_file=$(basename $example) + + echo "$example_file: " + local sketch="$example_dir/$example_file" + echo "$sketch" + #arduino -v --verbose-build --verify $sketch + + # verify the example, and save stdout & stderr to a variable + # we have to avoid reading the exit code of local: + # "when declaring a local variable in a function, the local acts as a command in its own right" + local build_stdout + build_stdout=$(arduino --verify $sketch 2>&1) + + # echo output if the build failed + if [ $? -ne 0 ]; then + # heavy X + echo -e "\xe2\x9c\x96" + echo -e "----------------------------- DEBUG OUTPUT -----------------------------\n" + echo "$build_stdout" + echo -e "\n------------------------------------------------------------------------\n" + + # mark as fail + exit_code=1 + + else + # heavy checkmark + echo -e "\xe2\x9c\x93" + fi + done + + return $exit_code +} diff --git a/utils/astyle_library.conf b/utils/astyle_library.conf new file mode 100644 index 0000000..8a73bc2 --- /dev/null +++ b/utils/astyle_library.conf @@ -0,0 +1,70 @@ +# Code formatting rules for Arduino libraries, modified from for KH libraries: +# +# https://github.com/arduino/Arduino/blob/master/build/shared/examples_formatter.conf +# + +# astyle --style=allman -s2 -t2 -C -S -xW -Y -M120 -f -p -xg -H -xb -c --xC120 -xL *.h *.cpp *.ino + +--mode=c +--lineend=linux +--style=allman + +# -r or -R +#--recursive + +# -c => Converts tabs into spaces +convert-tabs + +# -s2 => 2 spaces indentation +--indent=spaces=2 + +# -t2 => tab =2 spaces +#--indent=tab=2 + +# -C +--indent-classes + +# -S +--indent-switches + +# -xW +--indent-preproc-block + +# -Y => indent classes, switches (and cases), comments starting at column 1 +--indent-col1-comments + +# -M120 => maximum of 120 spaces to indent a continuation line +--max-continuation-indent=120 + +# -xC120 => max‑code‑length will break a line if the code exceeds # characters +--max-code-length=120 + +# -f => +--break-blocks + +# -p => put a space around operators +--pad-oper + +# -xg => Insert space padding after commas +--pad-comma + +# -H => put a space after if/for/while +pad-header + +# -xb => Break one line headers (e.g. if/for/while) +--break-one-line-headers + +# -c => Converts tabs into spaces +#--convert-tabs + +# if you like one-liners, keep them +#keep-one-line-statements + +# -xV +--attach-closing-while + +#unpad-paren + +# -xp +remove-comment-prefix + diff --git a/utils/restyle.sh b/utils/restyle.sh new file mode 100644 index 0000000..bcd846f --- /dev/null +++ b/utils/restyle.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +for dir in . ; do + find $dir -type f \( -name "*.c" -o -name "*.h" -o -name "*.cpp" -o -name "*.ino" \) -exec astyle --suffix=none --options=./utils/astyle_library.conf \{\} \; +done +