From 1b4a5b295206da9d3d68ea4b6d6d3bd6f42e98bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20M=C3=BChl?= Date: Fri, 31 Mar 2023 14:29:48 +0200 Subject: [PATCH 1/7] add http_api --- lib/MatrixUI/{ => Fonts}/AwtrixFont.h | 946 ++++++++++++------------- lib/MatrixUI/Fonts/fallout.h | 320 +++++++++ lib/MatrixUI/MatrixDisplayUi.cpp | 2 +- lib/webserver/src/esp-fs-webserver.cpp | 8 +- lib/webserver/src/esp-fs-webserver.h | 1 + src/Apps.h | 63 ++ src/DisplayManager.cpp | 148 +++- src/DisplayManager.h | 4 +- src/Globals.cpp | 49 +- src/Globals.h | 3 +- src/MQTTManager.cpp | 72 +- src/MenuManager.cpp | 23 +- src/PeripheryManager.cpp | 43 +- src/PeripheryManager.h | 1 + src/ServerManager.cpp | 103 ++- src/ServerManager.h | 1 - 16 files changed, 1217 insertions(+), 570 deletions(-) rename lib/MatrixUI/{ => Fonts}/AwtrixFont.h (98%) create mode 100644 lib/MatrixUI/Fonts/fallout.h diff --git a/lib/MatrixUI/AwtrixFont.h b/lib/MatrixUI/Fonts/AwtrixFont.h similarity index 98% rename from lib/MatrixUI/AwtrixFont.h rename to lib/MatrixUI/Fonts/AwtrixFont.h index edbfe24..939857b 100644 --- a/lib/MatrixUI/AwtrixFont.h +++ b/lib/MatrixUI/Fonts/AwtrixFont.h @@ -1,473 +1,473 @@ -/** -** The original 3x5 font is licensed under the 3-clause BSD license: -** -** Copyright 1999 Brian J. Swetland -** Copyright 1999 Vassilii Khachaturov -** Portions (of vt100.c/vt100.h) copyright Dan Marks -** Modifications for Awtrix for improved readability and LaMetric Style Copyright 2023 Blueforcer -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions, and the following disclaimer. -** 2. Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions, and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** 3. The name of the authors may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -** -** Modifications to TomThumb for improved readability are from Robey Pointer, -** see: -** http://robey.lag.net/2010/01/23/tiny-monospace-font.html -** -** Modifications for Awtrix for improved readability and LaMetric Style are from -** Blueforcer, Yann and hollyghost -** -** The original author does not have any objection to relicensing of Robey -** Pointer's modifications (in this file) in a more permissive license. See -** the discussion at the above blog, and also here: -** http://opengameart.org/forumtopic/how-to-submit-art-using-the-3-clause-bsd-license -** -** Feb 21, 2016: Conversion from Linux BDF --> Adafruit GFX font, -** with the help of this Python script: -** https://gist.github.com/skelliam/322d421f028545f16f6d -** William Skellenger (williamj@skellenger.net) -** Twitter: @skelliam -** -*/ -// AwtrixFont Version 20230215 - -const uint8_t AwtrixBitmaps[] PROGMEM = { - 0x00, /*[0] 0x20 space */ - 0x80, 0x80, 0x80, 0x00, 0x80, /*[1] 0x21 exclam */ - 0xA0, 0xA0, /*[2] 0x22 quotedbl */ - 0xA0, 0xE0, 0xA0, 0xE0, 0xA0, /*[3] 0x23 numbersign */ - 0x60, 0xC0, 0x60, 0xC0, 0x40, /*[4] 0x24 dollar */ - 0xA0, 0x20, 0x40, 0x80, 0xA0, /*[5] 0x25 percent */ - 0xC0, 0xC0, 0xE0, 0xA0, 0x60, /*[6] 0x26 ampersand */ - 0x80, 0x80, /*[7] 0x27 quotesingle */ - 0x40, 0x80, 0x80, 0x80, 0x40, /*[8] 0x28 parenleft */ - 0x80, 0x40, 0x40, 0x40, 0x80, /*[9] 0x29 parenright */ - 0xA0, 0x40, 0xA0, /*[10] 0x2A asterisk */ - 0x40, 0xE0, 0x40, /*[11] 0x2B plus */ - 0x40, 0x80, /*[12] 0x2C comma */ - 0xE0, /*[13] 0x2D hyphen */ - 0x80, /*[14] 0x2E period */ - 0x20, 0x20, 0x40, 0x80, 0x80, /*[15] 0x2F slash */ - 0xE0, 0xA0, 0xA0, 0xA0, 0xE0, /*[16] 0x30 zero */ - 0x40, 0xC0, 0x40, 0x40, 0xE0, /*[17] 0x31 one */ - 0xE0, 0x20, 0xE0, 0x80, 0xE0, /*[18] 0x32 two */ - 0xE0, 0x20, 0xE0, 0x20, 0xE0, /*[19] 0x33 three */ - 0xA0, 0xA0, 0xE0, 0x20, 0x20, /*[20] 0x34 four */ - 0xE0, 0x80, 0xE0, 0x20, 0xE0, /*[21] 0x35 five */ - 0xE0, 0x80, 0xE0, 0xA0, 0xE0, /*[22] 0x36 six */ - 0xE0, 0x20, 0x20, 0x20, 0x20, /*[23] 0x37 seven */ - 0xE0, 0xA0, 0xE0, 0xA0, 0xE0, /*[24] 0x38 eight */ - 0xE0, 0xA0, 0xE0, 0x20, 0xE0, /*[25] 0x39 nine */ - 0x80, 0x00, 0x80, /*[26] 0x3A colon */ - 0x40, 0x00, 0x40, 0x80, /*[27] 0x3B semicolon */ - 0x20, 0x40, 0x80, 0x40, 0x20, /*[28] 0x3C less */ - 0xE0, 0x00, 0xE0, /*[29] 0x3D equal */ - 0x80, 0x40, 0x20, 0x40, 0x80, /*[30] 0x3E greater */ - 0xE0, 0x20, 0x40, 0x00, 0x40, /*[31] 0x3F question */ - 0x40, 0xA0, 0xE0, 0x80, 0x60, /*[32] 0x40 at */ - 0xC0, 0xA0, 0xE0, 0xA0, 0xA0, /*[33] 0x41 A */ - 0xC0, 0xA0, 0xC0, 0xA0, 0xC0, /*[34] 0x42 B */ - 0x40, 0xA0, 0x80, 0xA0, 0x40, /*[35] 0x43 C */ - 0xC0, 0xA0, 0xA0, 0xA0, 0xC0, /*[36] 0x44 D */ - 0xE0, 0x80, 0xE0, 0x80, 0xE0, /*[37] 0x45 E */ - 0xE0, 0x80, 0xE0, 0x80, 0x80, /*[38] 0x46 F */ - 0x60, 0x80, 0xA0, 0xA0, 0x60, /*[39] 0x47 G */ - 0xA0, 0xA0, 0xE0, 0xA0, 0xA0, /*[40] 0x48 H */ - 0x80, 0x80, 0x80, 0x80, 0x80, /*[41] 0x49 I */ - 0x20, 0x20, 0x20, 0xA0, 0x40, /*[42] 0x4A J */ - 0xA0, 0xA0, 0xC0, 0xA0, 0xA0, /*[43] 0x4B K */ - 0x80, 0x80, 0x80, 0x80, 0xE0, /*[44] 0x4C L */ - 0x88, 0xD8, 0xA8, 0x88, 0x88, /*[45] 0x4D M */ - 0x90, 0xD0, 0xB0, 0x90, 0x90, /*[46] 0x4E N */ - 0x40, 0xA0, 0xA0, 0xA0, 0x40, /*[47] 0x4F O */ - 0xE0, 0xA0, 0xC0, 0x80, 0x80, /*[48] 0x50 P */ - 0x40, 0xA0, 0xA0, 0xA0, 0x70, /*[49] 0x51 Q */ - 0xE0, 0xA0, 0xC0, 0xA0, 0xA0, /*[50] 0x52 R */ - 0xE0, 0x80, 0xE0, 0x20, 0xE0, /*[51] 0x53 S */ - 0xE0, 0x40, 0x40, 0x40, 0x40, /*[52] 0x54 T */ - 0xA0, 0xA0, 0xA0, 0xA0, 0xE0, /*[53] 0x55 U */ - 0xA0, 0xA0, 0xA0, 0xA0, 0x40, /*[54] 0x56 V */ - 0x88, 0x88, 0x88, 0xA8, 0x50, /*[55] 0x57 W */ - 0xA0, 0xA0, 0x40, 0xA0, 0xA0, /*[56] 0x58 X */ - 0xA0, 0xA0, 0xE0, 0x20, 0xC0, /*[57] 0x59 Y */ - 0xE0, 0x20, 0x40, 0x80, 0xE0, /*[58] 0x5A Z */ - 0xE0, 0x80, 0x80, 0x80, 0xE0, /*[59] 0x5B bracketleft */ - 0x80, 0x40, 0x20, /*[60] 0x5C backslash */ - 0xE0, 0x20, 0x20, 0x20, 0xE0, /*[61] 0x5D bracketright */ - 0x40, 0xA0, /*[62] 0x5E asciicircum */ - 0xE0, /*[63] 0x5F underscore */ - 0x80, 0x40, /*[64] 0x60 grave */ - 0xC0, 0x60, 0xA0, 0xE0, /*[65] 0x61 a */ - 0x80, 0xC0, 0xA0, 0xA0, 0xC0, /*[66] 0x62 b */ - 0x60, 0x80, 0x80, 0x60, /*[67] 0x63 c */ - 0x20, 0x60, 0xA0, 0xA0, 0x60, /*[68] 0x64 d */ - 0x60, 0xA0, 0xC0, 0x60, /*[69] 0x65 e */ - 0x20, 0x40, 0xE0, 0x40, 0x40, /*[70] 0x66 f */ - 0x60, 0xA0, 0xE0, 0x20, 0x40, /*[71] 0x67 g */ - 0x80, 0xC0, 0xA0, 0xA0, 0xA0, /*[72] 0x68 h */ - 0x80, 0x00, 0x80, 0x80, 0x80, /*[73] 0x69 i */ - 0x20, 0x00, 0x20, 0x20, 0xA0, 0x40, /*[74] 0x6A j */ - 0x80, 0xA0, 0xC0, 0xC0, 0xA0, /*[75] 0x6B k */ - 0xC0, 0x40, 0x40, 0x40, 0xE0, /*[76] 0x6C l */ - 0xE0, 0xE0, 0xE0, 0xA0, /*[77] 0x6D m */ - 0xC0, 0xA0, 0xA0, 0xA0, /*[78] 0x6E n */ - 0x40, 0xA0, 0xA0, 0x40, /*[79] 0x6F o */ - 0xC0, 0xA0, 0xA0, 0xC0, 0x80, /*[80] 0x70 p */ - 0x60, 0xA0, 0xA0, 0x60, 0x20, /*[81] 0x71 q */ - 0x60, 0x80, 0x80, 0x80, /*[82] 0x72 r */ - 0x60, 0xC0, 0x60, 0xC0, /*[83] 0x73 s */ - 0x40, 0xE0, 0x40, 0x40, 0x60, /*[84] 0x74 t */ - 0xA0, 0xA0, 0xA0, 0x60, /*[85] 0x75 u */ - 0xA0, 0xA0, 0xE0, 0x40, /*[86] 0x76 v */ - 0xA0, 0xE0, 0xE0, 0xE0, /*[87] 0x77 w */ - 0xA0, 0x40, 0x40, 0xA0, /*[88] 0x78 x */ - 0xA0, 0xA0, 0x60, 0x20, 0x40, /*[89] 0x79 y */ - 0xE0, 0x60, 0xC0, 0xE0, /*[90] 0x7A z */ - 0x60, 0x40, 0x80, 0x40, 0x60, /*[91] 0x7B braceleft */ - 0x80, 0x80, 0x00, 0x80, 0x80, /*[92] 0x7C bar */ - 0xC0, 0x40, 0x20, 0x40, 0xC0, /*[93] 0x7D braceright */ - 0x60, 0xC0, /*[94] 0x7E asciitilde */ - - 0x80, 0x00, 0x80, 0x80, 0x80, /*[95] 0xA1 exclamdown */ - 0x40, 0xE0, 0x80, 0xE0, 0x40, /*[96] 0xA2 cent */ - 0x60, 0x40, 0xE0, 0x40, 0xE0, /*[97] 0xA3 sterling */ - 0xA0, 0x40, 0xE0, 0x40, 0xA0, /*[98] 0xA4 currency */ - 0xA0, 0xA0, 0x40, 0xE0, 0x40, /*[99] 0xA5 yen */ - 0x80, 0x80, 0x00, 0x80, 0x80, /*[100] 0xA6 brokenbar */ - 0x60, 0x40, 0xA0, 0x40, 0xC0, /*[101] 0xA7 section */ - 0xA0, /*[102] 0xA8 dieresis */ - 0x60, 0x80, 0x60, /*[103] 0xA9 copyright */ - 0x60, 0xA0, 0xE0, 0x00, 0xE0, /*[104] 0xAA ordfeminine */ - 0x40, 0x80, 0x40, /*[105] 0xAB guillemotleft */ - 0xE0, 0x20, /*[106] 0xAC logicalnot */ - 0xC0, /*[107] 0xAD softhyphen */ - 0xC0, 0xC0, 0xA0, /*[108] 0xAE registered */ - 0xE0, /*[109] 0xAF macron */ - 0xC0, 0xC0, 0x00, /*[110] 0xB0 degree */ - 0x40, 0xE0, 0x40, 0x00, 0xE0, /*[111] 0xB1 plusminus */ - 0xC0, 0x40, 0x60, /*[112] 0xB2 twosuperior */ - 0xE0, 0x60, 0xE0, /*[113] 0xB3 threesuperior */ - 0x40, 0x80, /*[114] 0xB4 acute */ - 0xA0, 0xA0, 0xA0, 0xC0, 0x80, /*[115] 0xB5 mu */ - 0x60, 0xA0, 0x60, 0x60, 0x60, /*[116] 0xB6 paragraph */ - 0xE0, 0xE0, 0xE0, /*[117] 0xB7 periodcentered */ - 0x40, 0x20, 0xC0, /*[118] 0xB8 cedilla */ - 0x80, 0x80, 0x80, /*[119] 0xB9 onesuperior */ - 0x40, 0xA0, 0x40, 0x00, 0xE0, /*[120] 0xBA ordmasculine */ - 0x80, 0x40, 0x80, /*[121] 0xBB guillemotright */ - 0x80, 0x80, 0x00, 0x60, 0x20, /*[122] 0xBC onequarter */ - 0x80, 0x80, 0x00, 0xC0, 0x60, /*[123] 0xBD onehalf */ - 0xC0, 0xC0, 0x00, 0x60, 0x20, /*[124] 0xBE threequarters */ - 0x40, 0x00, 0x40, 0x80, 0xE0, /*[125] 0xBF questiondown */ - 0x40, 0x20, 0x40, 0xE0, 0xA0, /*[126] 0xC0 Agrave */ - 0x40, 0x80, 0x40, 0xE0, 0xA0, /*[127] 0xC1 Aacute */ - 0xE0, 0x00, 0x40, 0xE0, 0xA0, /*[128] 0xC2 Acircumflex */ - 0x60, 0xC0, 0x40, 0xE0, 0xA0, /*[129] 0xC3 Atilde */ - 0xA0, 0x40, 0xA0, 0xE0, 0xA0, /*[130] 0xC4 Adieresis */ - 0xC0, 0xC0, 0xA0, 0xE0, 0xA0, /*[131] 0xC5 Aring */ - 0x60, 0xC0, 0xE0, 0xC0, 0xE0, /*[132] 0xC6 AE */ - 0x60, 0x80, 0x80, 0x60, 0x20, 0x40, /*[133] 0xC7 Ccedilla */ - 0x40, 0x20, 0xE0, 0xC0, 0xE0, /*[134] 0xC8 Egrave */ - 0x40, 0x80, 0xE0, 0xC0, 0xE0, /*[135] 0xC9 Eacute */ - 0xE0, 0x00, 0xE0, 0xC0, 0xE0, /*[136] 0xCA Ecircumflex */ - 0xA0, 0x00, 0xE0, 0xC0, 0xE0, /*[137] 0xCB Edieresis */ - 0x40, 0x20, 0xE0, 0x40, 0xE0, /*[138] 0xCC Igrave */ - 0x40, 0x80, 0xE0, 0x40, 0xE0, /*[139] 0xCD Iacute */ - 0xE0, 0x00, 0xE0, 0x40, 0xE0, /*[140] 0xCE Icircumflex */ - 0xA0, 0x00, 0xE0, 0x40, 0xE0, /*[141] 0xCF Idieresis */ - 0xC0, 0xA0, 0xE0, 0xA0, 0xC0, /*[142] 0xD0 Eth */ - 0xC0, 0x60, 0xA0, 0xE0, 0xA0, /*[143] 0xD1 Ntilde */ - 0x40, 0x20, 0xE0, 0xA0, 0xE0, /*[144] 0xD2 Ograve */ - 0x40, 0x80, 0xE0, 0xA0, 0xE0, /*[145] 0xD3 Oacute */ - 0xE0, 0x00, 0xE0, 0xA0, 0xE0, /*[146] 0xD4 Ocircumflex */ - 0xC0, 0x60, 0xE0, 0xA0, 0xE0, /*[147] 0xD5 Otilde */ - 0xA0, 0x00, 0xE0, 0xA0, 0xE0, /*[148] 0xD6 Odieresis */ - 0xA0, 0x40, 0xA0, /*[149] 0xD7 multiply */ - 0x60, 0xA0, 0xE0, 0xA0, 0xC0, /*[150] 0xD8 Oslash */ - 0x80, 0x40, 0xA0, 0xA0, 0xE0, /*[151] 0xD9 Ugrave */ - 0x20, 0x40, 0xA0, 0xA0, 0xE0, /*[152] 0xDA Uacute */ - 0xE0, 0x00, 0xA0, 0xA0, 0xE0, /*[153] 0xDB Ucircumflex */ - 0xA0, 0x00, 0xA0, 0xA0, 0xE0, /*[154] 0xDC Udieresis */ - 0x20, 0x40, 0xA0, 0xE0, 0x40, /*[155] 0xDD Yacute */ - 0x80, 0xE0, 0xA0, 0xE0, 0x80, /*[156] 0xDE Thorn */ - 0x60, 0xA0, 0xC0, 0xA0, 0xC0, 0x80, /*[157] 0xDF germandbls */ - 0x40, 0x20, 0x60, 0xA0, 0xE0, /*[158] 0xE0 agrave */ - 0x40, 0x80, 0x60, 0xA0, 0xE0, /*[159] 0xE1 aacute */ - 0xE0, 0x00, 0x60, 0xA0, 0xE0, /*[160] 0xE2 acircumflex */ - 0x60, 0xC0, 0x60, 0xA0, 0xE0, /*[161] 0xE3 atilde */ - 0xA0, 0x00, 0x60, 0xA0, 0xE0, /*[162] 0xE4 adieresis */ - 0x60, 0x60, 0x60, 0xA0, 0xE0, /*[163] 0xE5 aring */ - 0x60, 0xE0, 0xE0, 0xC0, /*[164] 0xE6 ae */ - 0x60, 0x80, 0x60, 0x20, 0x40, /*[165] 0xE7 ccedilla */ - 0x40, 0x20, 0x60, 0xE0, 0x60, /*[166] 0xE8 egrave */ - 0x40, 0x80, 0x60, 0xE0, 0x60, /*[167] 0xE9 eacute */ - 0xE0, 0x00, 0x60, 0xE0, 0x60, /*[168] 0xEA ecircumflex */ - 0xA0, 0x00, 0x60, 0xE0, 0x60, /*[169] 0xEB edieresis */ - 0x80, 0x40, 0x80, 0x80, 0x80, /*[170] 0xEC igrave */ - 0x40, 0x80, 0x40, 0x40, 0x40, /*[171] 0xED iacute */ - 0xE0, 0x00, 0x40, 0x40, 0x40, /*[172] 0xEE icircumflex */ - 0xA0, 0x00, 0x40, 0x40, 0x40, /*[173] 0xEF idieresis */ - 0x60, 0xC0, 0x60, 0xA0, 0x60, /*[174] 0xF0 eth */ - 0xC0, 0x60, 0xC0, 0xA0, 0xA0, /*[175] 0xF1 ntilde */ - 0x40, 0x20, 0x40, 0xA0, 0x40, /*[176] 0xF2 ograve */ - 0x40, 0x80, 0x40, 0xA0, 0x40, /*[177] 0xF3 oacute */ - 0xE0, 0x00, 0x40, 0xA0, 0x40, /*[178] 0xF4 ocircumflex */ - 0xC0, 0x60, 0x40, 0xA0, 0x40, /*[179] 0xF5 otilde */ - 0xA0, 0x00, 0x40, 0xA0, 0x40, /*[180] 0xF6 odieresis */ - 0x40, 0x00, 0xE0, 0x00, 0x40, /*[181] 0xF7 divide */ - 0x60, 0xE0, 0xA0, 0xC0, /*[182] 0xF8 oslash */ - 0x80, 0x40, 0xA0, 0xA0, 0x60, /*[183] 0xF9 ugrave */ - 0x20, 0x40, 0xA0, 0xA0, 0x60, /*[184] 0xFA uacute */ - 0xE0, 0x00, 0xA0, 0xA0, 0x60, /*[185] 0xFB ucircumflex */ - 0xA0, 0x00, 0xA0, 0xA0, 0x60, /*[186] 0xFC udieresis */ - 0x20, 0x40, 0xA0, 0x60, 0x20, 0x40, /*[187] 0xFD yacute */ - 0x80, 0xC0, 0xA0, 0xC0, 0x80, /*[188] 0xFE thorn */ - 0xA0, 0x00, 0xA0, 0x60, 0x20, 0x40, /*[189] 0xFF ydieresis */ - 0x00, /*[190] 0x11D gcircumflex */ - 0x60, 0xC0, 0xE0, 0xC0, 0x60, /*[191] 0x152 OE */ - 0x60, 0xE0, 0xC0, 0xE0, /*[192] 0x153 oe */ - 0xA0, 0x60, 0xC0, 0x60, 0xC0, /*[193] 0x160 Scaron */ - 0xA0, 0x60, 0xC0, 0x60, 0xC0, /*[194] 0x161 scaron */ - 0xA0, 0x00, 0xA0, 0x40, 0x40, /*[195] 0x178 Ydieresis */ - 0xA0, 0xE0, 0x60, 0xC0, 0xE0, /*[196] 0x17D Zcaron */ - 0xA0, 0xE0, 0x60, 0xC0, 0xE0, /*[197] 0x17E zcaron */ - 0x00, /*[198] 0xEA4 uni0EA4 */ - 0x00, /*[199] 0x13A0 uni13A0 */ - 0x80, /*[200] 0x2022 bullet */ - 0xA0, /*[201] 0x2026 ellipsis */ - 0x60, 0xE0, 0xE0, 0xC0, 0x60, /*[202] 0x20AC Euro */ - 0xE0, 0xA0, 0xA0, 0xA0, 0xE0, /*[203] 0xFFFD uniFFFD */ -}; - -/* {offset, width, height, advance cursor, x offset, y offset} */ -const GFXglyph AwtrixFontGlyphs[] PROGMEM = { - {0, 8, 1, 2, 0, -5}, /*[0] 0x20 space */ - {1, 8, 5, 2, 0, -5}, /*[1] 0x21 exclam */ - {6, 8, 2, 4, 0, -5}, /*[2] 0x22 quotedbl */ - {8, 8, 5, 4, 0, -5}, /*[3] 0x23 numbersign */ - {13, 8, 5, 4, 0, -5}, /*[4] 0x24 dollar */ - {18, 8, 5, 4, 0, -5}, /*[5] 0x25 percent */ - {23, 8, 5, 4, 0, -5}, /*[6] 0x26 ampersand */ - {28, 8, 2, 2, 0, -5}, /*[7] 0x27 quotesingle */ - {30, 8, 5, 3, 0, -5}, /*[8] 0x28 parenleft */ - {35, 8, 5, 3, 0, -5}, /*[9] 0x29 parenright */ - {40, 8, 3, 4, 0, -5}, /*[10] 0x2A asterisk */ - {43, 8, 3, 4, 0, -4}, /*[11] 0x2B plus */ - {46, 8, 2, 3, 0, -2}, /*[12] 0x2C comma */ - {48, 8, 1, 4, 0, -3}, /*[13] 0x2D hyphen */ - {49, 8, 1, 2, 0, -1}, /*[14] 0x2E period */ - {50, 8, 5, 4, 0, -5}, /*[15] 0x2F slash */ - {55, 8, 5, 4, 0, -5}, /*[16] 0x30 zero */ - {60, 8, 5, 4, 0, -5}, /*[17] 0x31 one */ - {65, 8, 5, 4, 0, -5}, /*[18] 0x32 two */ - {70, 8, 5, 4, 0, -5}, /*[19] 0x33 three */ - {75, 8, 5, 4, 0, -5}, /*[20] 0x34 four */ - {80, 8, 5, 4, 0, -5}, /*[21] 0x35 five */ - {85, 8, 5, 4, 0, -5}, /*[22] 0x36 six */ - {90, 8, 5, 4, 0, -5}, /*[23] 0x37 seven */ - {95, 8, 5, 4, 0, -5}, /*[24] 0x38 eight */ - {100, 8, 5, 4, 0, -5}, /*[25] 0x39 nine */ - {105, 8, 3, 2, 0, -4}, /*[26] 0x3A colon */ - {108, 8, 4, 3, 0, -4}, /*[27] 0x3B semicolon */ - {112, 8, 5, 4, 0, -5}, /*[28] 0x3C less */ - {117, 8, 3, 4, 0, -4}, /*[29] 0x3D equal */ - {120, 8, 5, 4, 0, -5}, /*[30] 0x3E greater */ - {125, 8, 5, 4, 0, -5}, /*[31] 0x3F question */ - {130, 8, 5, 4, 0, -5}, /*[32] 0x40 at */ - {135, 8, 5, 4, 0, -5}, /*[33] 0x41 A */ - {140, 8, 5, 4, 0, -5}, /*[34] 0x42 B */ - {145, 8, 5, 4, 0, -5}, /*[35] 0x43 C */ - {150, 8, 5, 4, 0, -5}, /*[36] 0x44 D */ - {155, 8, 5, 4, 0, -5}, /*[37] 0x45 E */ - {160, 8, 5, 4, 0, -5}, /*[38] 0x46 F */ - {165, 8, 5, 4, 0, -5}, /*[39] 0x47 G */ - {170, 8, 5, 4, 0, -5}, /*[40] 0x48 H */ - {175, 8, 5, 2, 0, -5}, /*[41] 0x49 I */ - {180, 8, 5, 4, 0, -5}, /*[42] 0x4A J */ - {185, 8, 5, 4, 0, -5}, /*[43] 0x4B K */ - {190, 8, 5, 4, 0, -5}, /*[44] 0x4C L */ - {195, 8, 5, 6, 0, -5}, /*[45] 0x4D M */ - {200, 8, 5, 5, 0, -5}, /*[46] 0x4E N */ - {205, 8, 5, 4, 0, -5}, /*[47] 0x4F O */ - {210, 8, 5, 4, 0, -5}, /*[48] 0x50 P */ - {215, 8, 5, 5, 0, -5}, /*[49] 0x51 Q */ - {220, 8, 5, 4, 0, -5}, /*[50] 0x52 R */ - {225, 8, 5, 4, 0, -5}, /*[51] 0x53 S */ - {230, 8, 5, 4, 0, -5}, /*[52] 0x54 T */ - {235, 8, 5, 4, 0, -5}, /*[53] 0x55 U */ - {240, 8, 5, 4, 0, -5}, /*[54] 0x56 V */ - {245, 8, 5, 6, 0, -5}, /*[55] 0x57 W */ - {250, 8, 5, 4, 0, -5}, /*[56] 0x58 X */ - {255, 8, 5, 4, 0, -5}, /*[57] 0x59 Y */ - {260, 8, 5, 4, 0, -5}, /*[58] 0x5A Z */ - {265, 8, 5, 4, 0, -5}, /*[59] 0x5B bracketleft */ - {270, 8, 3, 4, 0, -4}, /*[60] 0x5C backslash */ - {273, 8, 5, 4, 0, -5}, /*[61] 0x5D bracketright */ - {278, 8, 2, 4, 0, -5}, /*[62] 0x5E asciicircum */ - {280, 8, 1, 4, 0, -1}, /*[63] 0x5F underscore */ - {281, 8, 2, 3, 0, -5}, /*[64] 0x60 grave */ - {283, 8, 4, 4, 0, -4}, /*[65] 0x61 a */ - {287, 8, 5, 4, 0, -5}, /*[66] 0x62 b */ - {292, 8, 4, 4, 0, -4}, /*[67] 0x63 c */ - {296, 8, 5, 4, 0, -5}, /*[68] 0x64 d */ - {301, 8, 4, 4, 0, -4}, /*[69] 0x65 e */ - {305, 8, 5, 4, 0, -5}, /*[70] 0x66 f */ - {310, 8, 5, 4, 0, -4}, /*[71] 0x67 g */ - {315, 8, 5, 4, 0, -5}, /*[72] 0x68 h */ - {320, 8, 5, 2, 0, -5}, /*[73] 0x69 i */ - {325, 8, 6, 4, 0, -5}, /*[74] 0x6A j */ - {331, 8, 5, 4, 0, -5}, /*[75] 0x6B k */ - {336, 8, 5, 4, 0, -5}, /*[76] 0x6C l */ - {341, 8, 4, 4, 0, -4}, /*[77] 0x6D m */ - {345, 8, 4, 4, 0, -4}, /*[78] 0x6E n */ - {349, 8, 4, 4, 0, -4}, /*[79] 0x6F o */ - {353, 8, 5, 4, 0, -4}, /*[80] 0x70 p */ - {358, 8, 5, 4, 0, -4}, /*[81] 0x71 q */ - {363, 8, 4, 4, 0, -4}, /*[82] 0x72 r */ - {367, 8, 4, 4, 0, -4}, /*[83] 0x73 s */ - {371, 8, 5, 4, 0, -5}, /*[84] 0x74 t */ - {376, 8, 4, 4, 0, -4}, /*[85] 0x75 u */ - {380, 8, 4, 4, 0, -4}, /*[86] 0x76 v */ - {384, 8, 4, 4, 0, -4}, /*[87] 0x77 w */ - {388, 8, 4, 4, 0, -4}, /*[88] 0x78 x */ - {392, 8, 5, 4, 0, -4}, /*[89] 0x79 y */ - {397, 8, 4, 4, 0, -4}, /*[90] 0x7A z */ - {401, 8, 5, 4, 0, -5}, /*[91] 0x7B braceleft */ - {406, 8, 5, 2, 0, -5}, /*[92] 0x7C bar */ - {411, 8, 5, 4, 0, -5}, /*[93] 0x7D braceright */ - {416, 8, 2, 4, 0, -5}, /*[94] 0x7E asciitilde */ - - {418, 8, 5, 2, 0, -5}, /*[95] 0xA1 exclamdown */ - {423, 8, 5, 4, 0, -5}, /*[96] 0xA2 cent */ - {428, 8, 5, 4, 0, -5}, /*[97] 0xA3 sterling */ - {433, 8, 5, 4, 0, -5}, /*[98] 0xA4 currency */ - {438, 8, 5, 4, 0, -5}, /*[99] 0xA5 yen */ - {443, 8, 5, 2, 0, -5}, /*[100] 0xA6 brokenbar */ - {448, 8, 5, 4, 0, -5}, /*[101] 0xA7 section */ - {453, 8, 1, 4, 0, -5}, /*[102] 0xA8 dieresis */ - {454, 8, 3, 4, 0, -5}, /*[103] 0xA9 copyright */ - {457, 8, 5, 4, 0, -5}, /*[104] 0xAA ordfeminine */ - {462, 8, 3, 3, 0, -5}, /*[105] 0xAB guillemotleft */ - {465, 8, 2, 4, 0, -4}, /*[106] 0xAC logicalnot */ - {467, 8, 1, 3, 0, -3}, /*[107] 0xAD softhyphen */ - {468, 8, 3, 4, 0, -5}, /*[108] 0xAE registered */ - {471, 8, 1, 4, 0, -5}, /*[109] 0xAF macron */ - {472, 8, 3, 4, 0, -5}, /*[110] 0xB0 degree */ - {475, 8, 5, 4, 0, -5}, /*[111] 0xB1 plusminus */ - {480, 8, 3, 4, 0, -5}, /*[112] 0xB2 twosuperior */ - {483, 8, 3, 4, 0, -5}, /*[113] 0xB3 threesuperior */ - {486, 8, 2, 3, 0, -5}, /*[114] 0xB4 acute */ - {488, 8, 5, 4, 0, -5}, /*[115] 0xB5 mu */ - {493, 8, 5, 4, 0, -5}, /*[116] 0xB6 paragraph */ - {498, 8, 3, 4, 0, -4}, /*[117] 0xB7 periodcentered */ - {501, 8, 3, 4, 0, -3}, /*[118] 0xB8 cedilla */ - {504, 8, 3, 2, 0, -5}, /*[119] 0xB9 onesuperior */ - {507, 8, 5, 4, 0, -5}, /*[120] 0xBA ordmasculine */ - {512, 8, 3, 3, 0, -5}, /*[121] 0xBB guillemotright */ - {515, 8, 5, 4, 0, -5}, /*[122] 0xBC onequarter */ - {520, 8, 5, 4, 0, -5}, /*[123] 0xBD onehalf */ - {525, 8, 5, 4, 0, -5}, /*[124] 0xBE threequarters */ - {530, 8, 5, 4, 0, -5}, /*[125] 0xBF questiondown */ - {535, 8, 5, 4, 0, -5}, /*[126] 0xC0 Agrave */ - {540, 8, 5, 4, 0, -5}, /*[127] 0xC1 Aacute */ - {545, 8, 5, 4, 0, -5}, /*[128] 0xC2 Acircumflex */ - {550, 8, 5, 4, 0, -5}, /*[129] 0xC3 Atilde */ - {555, 8, 5, 4, 0, -5}, /*[130] 0xC4 Adieresis */ - {560, 8, 5, 4, 0, -5}, /*[131] 0xC5 Aring */ - {565, 8, 5, 4, 0, -5}, /*[132] 0xC6 AE */ - {570, 8, 6, 4, 0, -5}, /*[133] 0xC7 Ccedilla */ - {576, 8, 5, 4, 0, -5}, /*[134] 0xC8 Egrave */ - {581, 8, 5, 4, 0, -5}, /*[135] 0xC9 Eacute */ - {586, 8, 5, 4, 0, -5}, /*[136] 0xCA Ecircumflex */ - {591, 8, 5, 4, 0, -5}, /*[137] 0xCB Edieresis */ - {596, 8, 5, 4, 0, -5}, /*[138] 0xCC Igrave */ - {601, 8, 5, 4, 0, -5}, /*[139] 0xCD Iacute */ - {606, 8, 5, 4, 0, -5}, /*[140] 0xCE Icircumflex */ - {611, 8, 5, 4, 0, -5}, /*[141] 0xCF Idieresis */ - {616, 8, 5, 4, 0, -5}, /*[142] 0xD0 Eth */ - {621, 8, 5, 4, 0, -5}, /*[143] 0xD1 Ntilde */ - {626, 8, 5, 4, 0, -5}, /*[144] 0xD2 Ograve */ - {631, 8, 5, 4, 0, -5}, /*[145] 0xD3 Oacute */ - {636, 8, 5, 4, 0, -5}, /*[146] 0xD4 Ocircumflex */ - {641, 8, 5, 4, 0, -5}, /*[147] 0xD5 Otilde */ - {646, 8, 5, 4, 0, -5}, /*[148] 0xD6 Odieresis */ - {651, 8, 3, 4, 0, -4}, /*[149] 0xD7 multiply */ - {654, 8, 5, 4, 0, -5}, /*[150] 0xD8 Oslash */ - {659, 8, 5, 4, 0, -5}, /*[151] 0xD9 Ugrave */ - {664, 8, 5, 4, 0, -5}, /*[152] 0xDA Uacute */ - {669, 8, 5, 4, 0, -5}, /*[153] 0xDB Ucircumflex */ - {674, 8, 5, 4, 0, -5}, /*[154] 0xDC Udieresis */ - {679, 8, 5, 4, 0, -5}, /*[155] 0xDD Yacute */ - {684, 8, 5, 4, 0, -5}, /*[156] 0xDE Thorn */ - {689, 8, 6, 4, 0, -5}, /*[157] 0xDF germandbls */ - {695, 8, 5, 4, 0, -5}, /*[158] 0xE0 agrave */ - {700, 8, 5, 4, 0, -5}, /*[159] 0xE1 aacute */ - {705, 8, 5, 4, 0, -5}, /*[160] 0xE2 acircumflex */ - {710, 8, 5, 4, 0, -5}, /*[161] 0xE3 atilde */ - {715, 8, 5, 4, 0, -5}, /*[162] 0xE4 adieresis */ - {720, 8, 5, 4, 0, -5}, /*[163] 0xE5 aring */ - {725, 8, 4, 4, 0, -4}, /*[164] 0xE6 ae */ - {729, 8, 5, 4, 0, -4}, /*[165] 0xE7 ccedilla */ - {734, 8, 5, 4, 0, -5}, /*[166] 0xE8 egrave */ - {739, 8, 5, 4, 0, -5}, /*[167] 0xE9 eacute */ - {744, 8, 5, 4, 0, -5}, /*[168] 0xEA ecircumflex */ - {749, 8, 5, 4, 0, -5}, /*[169] 0xEB edieresis */ - {754, 8, 5, 3, 0, -5}, /*[170] 0xEC igrave */ - {759, 8, 5, 3, 0, -5}, /*[171] 0xED iacute */ - {764, 8, 5, 4, 0, -5}, /*[172] 0xEE icircumflex */ - {769, 8, 5, 4, 0, -5}, /*[173] 0xEF idieresis */ - {774, 8, 5, 4, 0, -5}, /*[174] 0xF0 eth */ - {779, 8, 5, 4, 0, -5}, /*[175] 0xF1 ntilde */ - {784, 8, 5, 4, 0, -5}, /*[176] 0xF2 ograve */ - {789, 8, 5, 4, 0, -5}, /*[177] 0xF3 oacute */ - {794, 8, 5, 4, 0, -5}, /*[178] 0xF4 ocircumflex */ - {799, 8, 5, 4, 0, -5}, /*[179] 0xF5 otilde */ - {804, 8, 5, 4, 0, -5}, /*[180] 0xF6 odieresis */ - {809, 8, 5, 4, 0, -5}, /*[181] 0xF7 divide */ - {814, 8, 4, 4, 0, -4}, /*[182] 0xF8 oslash */ - {818, 8, 5, 4, 0, -5}, /*[183] 0xF9 ugrave */ - {823, 8, 5, 4, 0, -5}, /*[184] 0xFA uacute */ - {828, 8, 5, 4, 0, -5}, /*[185] 0xFB ucircumflex */ - {833, 8, 5, 4, 0, -5}, /*[186] 0xFC udieresis */ - {838, 8, 6, 4, 0, -5}, /*[187] 0xFD yacute */ - {844, 8, 5, 4, 0, -4}, /*[188] 0xFE thorn */ - {849, 8, 6, 4, 0, -5}, /*[189] 0xFF ydieresis */ - {855, 8, 1, 2, 0, -1}, /*[190] 0x11D gcircumflex */ - {856, 8, 5, 4, 0, -5}, /*[191] 0x152 OE */ - {861, 8, 4, 4, 0, -4}, /*[192] 0x153 oe */ - {865, 8, 5, 4, 0, -5}, /*[193] 0x160 Scaron */ - {870, 8, 5, 4, 0, -5}, /*[194] 0x161 scaron */ - {875, 8, 5, 4, 0, -5}, /*[195] 0x178 Ydieresis */ - {880, 8, 5, 4, 0, -5}, /*[196] 0x17D Zcaron */ - {885, 8, 5, 4, 0, -5}, /*[197] 0x17E zcaron */ - {890, 8, 1, 2, 0, -1}, /*[198] 0xEA4 uni0EA4 */ - {891, 8, 1, 2, 0, -1}, /*[199] 0x13A0 uni13A0 */ - {892, 8, 1, 2, 0, -3}, /*[200] 0x2022 bullet */ - {893, 8, 1, 4, 0, -1}, /*[201] 0x2026 ellipsis */ - {894, 8, 5, 4, 0, -5}, /*[202] 0x20AC Euro */ - {899, 8, 5, 4, 0, -5}, /*[203] 0xFFFD uniFFFD */ -}; - -const GFXfont AwtrixFont PROGMEM = { - (uint8_t *)AwtrixBitmaps, - (GFXglyph *)AwtrixFontGlyphs, - 0x20, 0xFF, 6}; +/** +** The original 3x5 font is licensed under the 3-clause BSD license: +** +** Copyright 1999 Brian J. Swetland +** Copyright 1999 Vassilii Khachaturov +** Portions (of vt100.c/vt100.h) copyright Dan Marks +** Modifications for Awtrix for improved readability and LaMetric Style Copyright 2023 Blueforcer +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the authors may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +** +** Modifications to TomThumb for improved readability are from Robey Pointer, +** see: +** http://robey.lag.net/2010/01/23/tiny-monospace-font.html +** +** Modifications for Awtrix for improved readability and LaMetric Style are from +** Blueforcer, Yann and hollyghost +** +** The original author does not have any objection to relicensing of Robey +** Pointer's modifications (in this file) in a more permissive license. See +** the discussion at the above blog, and also here: +** http://opengameart.org/forumtopic/how-to-submit-art-using-the-3-clause-bsd-license +** +** Feb 21, 2016: Conversion from Linux BDF --> Adafruit GFX font, +** with the help of this Python script: +** https://gist.github.com/skelliam/322d421f028545f16f6d +** William Skellenger (williamj@skellenger.net) +** Twitter: @skelliam +** +*/ +// AwtrixFont Version 20230215 + +const uint8_t AwtrixBitmaps[] PROGMEM = { + 0x00, /*[0] 0x20 space */ + 0x80, 0x80, 0x80, 0x00, 0x80, /*[1] 0x21 exclam */ + 0xA0, 0xA0, /*[2] 0x22 quotedbl */ + 0xA0, 0xE0, 0xA0, 0xE0, 0xA0, /*[3] 0x23 numbersign */ + 0x60, 0xC0, 0x60, 0xC0, 0x40, /*[4] 0x24 dollar */ + 0xA0, 0x20, 0x40, 0x80, 0xA0, /*[5] 0x25 percent */ + 0xC0, 0xC0, 0xE0, 0xA0, 0x60, /*[6] 0x26 ampersand */ + 0x80, 0x80, /*[7] 0x27 quotesingle */ + 0x40, 0x80, 0x80, 0x80, 0x40, /*[8] 0x28 parenleft */ + 0x80, 0x40, 0x40, 0x40, 0x80, /*[9] 0x29 parenright */ + 0xA0, 0x40, 0xA0, /*[10] 0x2A asterisk */ + 0x40, 0xE0, 0x40, /*[11] 0x2B plus */ + 0x40, 0x80, /*[12] 0x2C comma */ + 0xE0, /*[13] 0x2D hyphen */ + 0x80, /*[14] 0x2E period */ + 0x20, 0x20, 0x40, 0x80, 0x80, /*[15] 0x2F slash */ + 0xE0, 0xA0, 0xA0, 0xA0, 0xE0, /*[16] 0x30 zero */ + 0x40, 0xC0, 0x40, 0x40, 0xE0, /*[17] 0x31 one */ + 0xE0, 0x20, 0xE0, 0x80, 0xE0, /*[18] 0x32 two */ + 0xE0, 0x20, 0xE0, 0x20, 0xE0, /*[19] 0x33 three */ + 0xA0, 0xA0, 0xE0, 0x20, 0x20, /*[20] 0x34 four */ + 0xE0, 0x80, 0xE0, 0x20, 0xE0, /*[21] 0x35 five */ + 0xE0, 0x80, 0xE0, 0xA0, 0xE0, /*[22] 0x36 six */ + 0xE0, 0x20, 0x20, 0x20, 0x20, /*[23] 0x37 seven */ + 0xE0, 0xA0, 0xE0, 0xA0, 0xE0, /*[24] 0x38 eight */ + 0xE0, 0xA0, 0xE0, 0x20, 0xE0, /*[25] 0x39 nine */ + 0x80, 0x00, 0x80, /*[26] 0x3A colon */ + 0x40, 0x00, 0x40, 0x80, /*[27] 0x3B semicolon */ + 0x20, 0x40, 0x80, 0x40, 0x20, /*[28] 0x3C less */ + 0xE0, 0x00, 0xE0, /*[29] 0x3D equal */ + 0x80, 0x40, 0x20, 0x40, 0x80, /*[30] 0x3E greater */ + 0xE0, 0x20, 0x40, 0x00, 0x40, /*[31] 0x3F question */ + 0x40, 0xA0, 0xE0, 0x80, 0x60, /*[32] 0x40 at */ + 0xC0, 0xA0, 0xE0, 0xA0, 0xA0, /*[33] 0x41 A */ + 0xC0, 0xA0, 0xC0, 0xA0, 0xC0, /*[34] 0x42 B */ + 0x40, 0xA0, 0x80, 0xA0, 0x40, /*[35] 0x43 C */ + 0xC0, 0xA0, 0xA0, 0xA0, 0xC0, /*[36] 0x44 D */ + 0xE0, 0x80, 0xE0, 0x80, 0xE0, /*[37] 0x45 E */ + 0xE0, 0x80, 0xE0, 0x80, 0x80, /*[38] 0x46 F */ + 0x60, 0x80, 0xA0, 0xA0, 0x60, /*[39] 0x47 G */ + 0xA0, 0xA0, 0xE0, 0xA0, 0xA0, /*[40] 0x48 H */ + 0x80, 0x80, 0x80, 0x80, 0x80, /*[41] 0x49 I */ + 0x20, 0x20, 0x20, 0xA0, 0x40, /*[42] 0x4A J */ + 0xA0, 0xA0, 0xC0, 0xA0, 0xA0, /*[43] 0x4B K */ + 0x80, 0x80, 0x80, 0x80, 0xE0, /*[44] 0x4C L */ + 0x88, 0xD8, 0xA8, 0x88, 0x88, /*[45] 0x4D M */ + 0x90, 0xD0, 0xB0, 0x90, 0x90, /*[46] 0x4E N */ + 0x40, 0xA0, 0xA0, 0xA0, 0x40, /*[47] 0x4F O */ + 0xE0, 0xA0, 0xC0, 0x80, 0x80, /*[48] 0x50 P */ + 0x40, 0xA0, 0xA0, 0xA0, 0x70, /*[49] 0x51 Q */ + 0xE0, 0xA0, 0xC0, 0xA0, 0xA0, /*[50] 0x52 R */ + 0xE0, 0x80, 0xE0, 0x20, 0xE0, /*[51] 0x53 S */ + 0xE0, 0x40, 0x40, 0x40, 0x40, /*[52] 0x54 T */ + 0xA0, 0xA0, 0xA0, 0xA0, 0xE0, /*[53] 0x55 U */ + 0xA0, 0xA0, 0xA0, 0xA0, 0x40, /*[54] 0x56 V */ + 0x88, 0x88, 0x88, 0xA8, 0x50, /*[55] 0x57 W */ + 0xA0, 0xA0, 0x40, 0xA0, 0xA0, /*[56] 0x58 X */ + 0xA0, 0xA0, 0xE0, 0x20, 0xC0, /*[57] 0x59 Y */ + 0xE0, 0x20, 0x40, 0x80, 0xE0, /*[58] 0x5A Z */ + 0xE0, 0x80, 0x80, 0x80, 0xE0, /*[59] 0x5B bracketleft */ + 0x80, 0x40, 0x20, /*[60] 0x5C backslash */ + 0xE0, 0x20, 0x20, 0x20, 0xE0, /*[61] 0x5D bracketright */ + 0x40, 0xA0, /*[62] 0x5E asciicircum */ + 0xE0, /*[63] 0x5F underscore */ + 0x80, 0x40, /*[64] 0x60 grave */ + 0xC0, 0x60, 0xA0, 0xE0, /*[65] 0x61 a */ + 0x80, 0xC0, 0xA0, 0xA0, 0xC0, /*[66] 0x62 b */ + 0x60, 0x80, 0x80, 0x60, /*[67] 0x63 c */ + 0x20, 0x60, 0xA0, 0xA0, 0x60, /*[68] 0x64 d */ + 0x60, 0xA0, 0xC0, 0x60, /*[69] 0x65 e */ + 0x20, 0x40, 0xE0, 0x40, 0x40, /*[70] 0x66 f */ + 0x60, 0xA0, 0xE0, 0x20, 0x40, /*[71] 0x67 g */ + 0x80, 0xC0, 0xA0, 0xA0, 0xA0, /*[72] 0x68 h */ + 0x80, 0x00, 0x80, 0x80, 0x80, /*[73] 0x69 i */ + 0x20, 0x00, 0x20, 0x20, 0xA0, 0x40, /*[74] 0x6A j */ + 0x80, 0xA0, 0xC0, 0xC0, 0xA0, /*[75] 0x6B k */ + 0xC0, 0x40, 0x40, 0x40, 0xE0, /*[76] 0x6C l */ + 0xE0, 0xE0, 0xE0, 0xA0, /*[77] 0x6D m */ + 0xC0, 0xA0, 0xA0, 0xA0, /*[78] 0x6E n */ + 0x40, 0xA0, 0xA0, 0x40, /*[79] 0x6F o */ + 0xC0, 0xA0, 0xA0, 0xC0, 0x80, /*[80] 0x70 p */ + 0x60, 0xA0, 0xA0, 0x60, 0x20, /*[81] 0x71 q */ + 0x60, 0x80, 0x80, 0x80, /*[82] 0x72 r */ + 0x60, 0xC0, 0x60, 0xC0, /*[83] 0x73 s */ + 0x40, 0xE0, 0x40, 0x40, 0x60, /*[84] 0x74 t */ + 0xA0, 0xA0, 0xA0, 0x60, /*[85] 0x75 u */ + 0xA0, 0xA0, 0xE0, 0x40, /*[86] 0x76 v */ + 0xA0, 0xE0, 0xE0, 0xE0, /*[87] 0x77 w */ + 0xA0, 0x40, 0x40, 0xA0, /*[88] 0x78 x */ + 0xA0, 0xA0, 0x60, 0x20, 0x40, /*[89] 0x79 y */ + 0xE0, 0x60, 0xC0, 0xE0, /*[90] 0x7A z */ + 0x60, 0x40, 0x80, 0x40, 0x60, /*[91] 0x7B braceleft */ + 0x80, 0x80, 0x00, 0x80, 0x80, /*[92] 0x7C bar */ + 0xC0, 0x40, 0x20, 0x40, 0xC0, /*[93] 0x7D braceright */ + 0x60, 0xC0, /*[94] 0x7E asciitilde */ + + 0x80, 0x00, 0x80, 0x80, 0x80, /*[95] 0xA1 exclamdown */ + 0x40, 0xE0, 0x80, 0xE0, 0x40, /*[96] 0xA2 cent */ + 0x60, 0x40, 0xE0, 0x40, 0xE0, /*[97] 0xA3 sterling */ + 0xA0, 0x40, 0xE0, 0x40, 0xA0, /*[98] 0xA4 currency */ + 0xA0, 0xA0, 0x40, 0xE0, 0x40, /*[99] 0xA5 yen */ + 0x80, 0x80, 0x00, 0x80, 0x80, /*[100] 0xA6 brokenbar */ + 0x60, 0x40, 0xA0, 0x40, 0xC0, /*[101] 0xA7 section */ + 0xA0, /*[102] 0xA8 dieresis */ + 0x60, 0x80, 0x60, /*[103] 0xA9 copyright */ + 0x60, 0xA0, 0xE0, 0x00, 0xE0, /*[104] 0xAA ordfeminine */ + 0x40, 0x80, 0x40, /*[105] 0xAB guillemotleft */ + 0xE0, 0x20, /*[106] 0xAC logicalnot */ + 0xC0, /*[107] 0xAD softhyphen */ + 0xC0, 0xC0, 0xA0, /*[108] 0xAE registered */ + 0xE0, /*[109] 0xAF macron */ + 0xC0, 0xC0, 0x00, /*[110] 0xB0 degree */ + 0x40, 0xE0, 0x40, 0x00, 0xE0, /*[111] 0xB1 plusminus */ + 0xC0, 0x40, 0x60, /*[112] 0xB2 twosuperior */ + 0xE0, 0x60, 0xE0, /*[113] 0xB3 threesuperior */ + 0x40, 0x80, /*[114] 0xB4 acute */ + 0xA0, 0xA0, 0xA0, 0xC0, 0x80, /*[115] 0xB5 mu */ + 0x60, 0xA0, 0x60, 0x60, 0x60, /*[116] 0xB6 paragraph */ + 0xE0, 0xE0, 0xE0, /*[117] 0xB7 periodcentered */ + 0x40, 0x20, 0xC0, /*[118] 0xB8 cedilla */ + 0x80, 0x80, 0x80, /*[119] 0xB9 onesuperior */ + 0x40, 0xA0, 0x40, 0x00, 0xE0, /*[120] 0xBA ordmasculine */ + 0x80, 0x40, 0x80, /*[121] 0xBB guillemotright */ + 0x80, 0x80, 0x00, 0x60, 0x20, /*[122] 0xBC onequarter */ + 0x80, 0x80, 0x00, 0xC0, 0x60, /*[123] 0xBD onehalf */ + 0xC0, 0xC0, 0x00, 0x60, 0x20, /*[124] 0xBE threequarters */ + 0x40, 0x00, 0x40, 0x80, 0xE0, /*[125] 0xBF questiondown */ + 0x40, 0x20, 0x40, 0xE0, 0xA0, /*[126] 0xC0 Agrave */ + 0x40, 0x80, 0x40, 0xE0, 0xA0, /*[127] 0xC1 Aacute */ + 0xE0, 0x00, 0x40, 0xE0, 0xA0, /*[128] 0xC2 Acircumflex */ + 0x60, 0xC0, 0x40, 0xE0, 0xA0, /*[129] 0xC3 Atilde */ + 0xA0, 0x40, 0xA0, 0xE0, 0xA0, /*[130] 0xC4 Adieresis */ + 0xC0, 0xC0, 0xA0, 0xE0, 0xA0, /*[131] 0xC5 Aring */ + 0x60, 0xC0, 0xE0, 0xC0, 0xE0, /*[132] 0xC6 AE */ + 0x60, 0x80, 0x80, 0x60, 0x20, 0x40, /*[133] 0xC7 Ccedilla */ + 0x40, 0x20, 0xE0, 0xC0, 0xE0, /*[134] 0xC8 Egrave */ + 0x40, 0x80, 0xE0, 0xC0, 0xE0, /*[135] 0xC9 Eacute */ + 0xE0, 0x00, 0xE0, 0xC0, 0xE0, /*[136] 0xCA Ecircumflex */ + 0xA0, 0x00, 0xE0, 0xC0, 0xE0, /*[137] 0xCB Edieresis */ + 0x40, 0x20, 0xE0, 0x40, 0xE0, /*[138] 0xCC Igrave */ + 0x40, 0x80, 0xE0, 0x40, 0xE0, /*[139] 0xCD Iacute */ + 0xE0, 0x00, 0xE0, 0x40, 0xE0, /*[140] 0xCE Icircumflex */ + 0xA0, 0x00, 0xE0, 0x40, 0xE0, /*[141] 0xCF Idieresis */ + 0xC0, 0xA0, 0xE0, 0xA0, 0xC0, /*[142] 0xD0 Eth */ + 0xC0, 0x60, 0xA0, 0xE0, 0xA0, /*[143] 0xD1 Ntilde */ + 0x40, 0x20, 0xE0, 0xA0, 0xE0, /*[144] 0xD2 Ograve */ + 0x40, 0x80, 0xE0, 0xA0, 0xE0, /*[145] 0xD3 Oacute */ + 0xE0, 0x00, 0xE0, 0xA0, 0xE0, /*[146] 0xD4 Ocircumflex */ + 0xC0, 0x60, 0xE0, 0xA0, 0xE0, /*[147] 0xD5 Otilde */ + 0xA0, 0x00, 0xE0, 0xA0, 0xE0, /*[148] 0xD6 Odieresis */ + 0xA0, 0x40, 0xA0, /*[149] 0xD7 multiply */ + 0x60, 0xA0, 0xE0, 0xA0, 0xC0, /*[150] 0xD8 Oslash */ + 0x80, 0x40, 0xA0, 0xA0, 0xE0, /*[151] 0xD9 Ugrave */ + 0x20, 0x40, 0xA0, 0xA0, 0xE0, /*[152] 0xDA Uacute */ + 0xE0, 0x00, 0xA0, 0xA0, 0xE0, /*[153] 0xDB Ucircumflex */ + 0xA0, 0x00, 0xA0, 0xA0, 0xE0, /*[154] 0xDC Udieresis */ + 0x20, 0x40, 0xA0, 0xE0, 0x40, /*[155] 0xDD Yacute */ + 0x80, 0xE0, 0xA0, 0xE0, 0x80, /*[156] 0xDE Thorn */ + 0x60, 0xA0, 0xC0, 0xA0, 0xC0, 0x80, /*[157] 0xDF germandbls */ + 0x40, 0x20, 0x60, 0xA0, 0xE0, /*[158] 0xE0 agrave */ + 0x40, 0x80, 0x60, 0xA0, 0xE0, /*[159] 0xE1 aacute */ + 0xE0, 0x00, 0x60, 0xA0, 0xE0, /*[160] 0xE2 acircumflex */ + 0x60, 0xC0, 0x60, 0xA0, 0xE0, /*[161] 0xE3 atilde */ + 0xA0, 0x00, 0x60, 0xA0, 0xE0, /*[162] 0xE4 adieresis */ + 0x60, 0x60, 0x60, 0xA0, 0xE0, /*[163] 0xE5 aring */ + 0x60, 0xE0, 0xE0, 0xC0, /*[164] 0xE6 ae */ + 0x60, 0x80, 0x60, 0x20, 0x40, /*[165] 0xE7 ccedilla */ + 0x40, 0x20, 0x60, 0xE0, 0x60, /*[166] 0xE8 egrave */ + 0x40, 0x80, 0x60, 0xE0, 0x60, /*[167] 0xE9 eacute */ + 0xE0, 0x00, 0x60, 0xE0, 0x60, /*[168] 0xEA ecircumflex */ + 0xA0, 0x00, 0x60, 0xE0, 0x60, /*[169] 0xEB edieresis */ + 0x80, 0x40, 0x80, 0x80, 0x80, /*[170] 0xEC igrave */ + 0x40, 0x80, 0x40, 0x40, 0x40, /*[171] 0xED iacute */ + 0xE0, 0x00, 0x40, 0x40, 0x40, /*[172] 0xEE icircumflex */ + 0xA0, 0x00, 0x40, 0x40, 0x40, /*[173] 0xEF idieresis */ + 0x60, 0xC0, 0x60, 0xA0, 0x60, /*[174] 0xF0 eth */ + 0xC0, 0x60, 0xC0, 0xA0, 0xA0, /*[175] 0xF1 ntilde */ + 0x40, 0x20, 0x40, 0xA0, 0x40, /*[176] 0xF2 ograve */ + 0x40, 0x80, 0x40, 0xA0, 0x40, /*[177] 0xF3 oacute */ + 0xE0, 0x00, 0x40, 0xA0, 0x40, /*[178] 0xF4 ocircumflex */ + 0xC0, 0x60, 0x40, 0xA0, 0x40, /*[179] 0xF5 otilde */ + 0xA0, 0x00, 0x40, 0xA0, 0x40, /*[180] 0xF6 odieresis */ + 0x40, 0x00, 0xE0, 0x00, 0x40, /*[181] 0xF7 divide */ + 0x60, 0xE0, 0xA0, 0xC0, /*[182] 0xF8 oslash */ + 0x80, 0x40, 0xA0, 0xA0, 0x60, /*[183] 0xF9 ugrave */ + 0x20, 0x40, 0xA0, 0xA0, 0x60, /*[184] 0xFA uacute */ + 0xE0, 0x00, 0xA0, 0xA0, 0x60, /*[185] 0xFB ucircumflex */ + 0xA0, 0x00, 0xA0, 0xA0, 0x60, /*[186] 0xFC udieresis */ + 0x20, 0x40, 0xA0, 0x60, 0x20, 0x40, /*[187] 0xFD yacute */ + 0x80, 0xC0, 0xA0, 0xC0, 0x80, /*[188] 0xFE thorn */ + 0xA0, 0x00, 0xA0, 0x60, 0x20, 0x40, /*[189] 0xFF ydieresis */ + 0x00, /*[190] 0x11D gcircumflex */ + 0x60, 0xC0, 0xE0, 0xC0, 0x60, /*[191] 0x152 OE */ + 0x60, 0xE0, 0xC0, 0xE0, /*[192] 0x153 oe */ + 0xA0, 0x60, 0xC0, 0x60, 0xC0, /*[193] 0x160 Scaron */ + 0xA0, 0x60, 0xC0, 0x60, 0xC0, /*[194] 0x161 scaron */ + 0xA0, 0x00, 0xA0, 0x40, 0x40, /*[195] 0x178 Ydieresis */ + 0xA0, 0xE0, 0x60, 0xC0, 0xE0, /*[196] 0x17D Zcaron */ + 0xA0, 0xE0, 0x60, 0xC0, 0xE0, /*[197] 0x17E zcaron */ + 0x00, /*[198] 0xEA4 uni0EA4 */ + 0x00, /*[199] 0x13A0 uni13A0 */ + 0x80, /*[200] 0x2022 bullet */ + 0xA0, /*[201] 0x2026 ellipsis */ + 0x60, 0xE0, 0xE0, 0xC0, 0x60, /*[202] 0x20AC Euro */ + 0xE0, 0xA0, 0xA0, 0xA0, 0xE0, /*[203] 0xFFFD uniFFFD */ +}; + +/* {offset, width, height, advance cursor, x offset, y offset} */ +const GFXglyph AwtrixFontGlyphs[] PROGMEM = { + {0, 8, 1, 2, 0, -5}, /*[0] 0x20 space */ + {1, 8, 5, 2, 0, -5}, /*[1] 0x21 exclam */ + {6, 8, 2, 4, 0, -5}, /*[2] 0x22 quotedbl */ + {8, 8, 5, 4, 0, -5}, /*[3] 0x23 numbersign */ + {13, 8, 5, 4, 0, -5}, /*[4] 0x24 dollar */ + {18, 8, 5, 4, 0, -5}, /*[5] 0x25 percent */ + {23, 8, 5, 4, 0, -5}, /*[6] 0x26 ampersand */ + {28, 8, 2, 2, 0, -5}, /*[7] 0x27 quotesingle */ + {30, 8, 5, 3, 0, -5}, /*[8] 0x28 parenleft */ + {35, 8, 5, 3, 0, -5}, /*[9] 0x29 parenright */ + {40, 8, 3, 4, 0, -5}, /*[10] 0x2A asterisk */ + {43, 8, 3, 4, 0, -4}, /*[11] 0x2B plus */ + {46, 8, 2, 3, 0, -2}, /*[12] 0x2C comma */ + {48, 8, 1, 4, 0, -3}, /*[13] 0x2D hyphen */ + {49, 8, 1, 2, 0, -1}, /*[14] 0x2E period */ + {50, 8, 5, 4, 0, -5}, /*[15] 0x2F slash */ + {55, 8, 5, 4, 0, -5}, /*[16] 0x30 zero */ + {60, 8, 5, 4, 0, -5}, /*[17] 0x31 one */ + {65, 8, 5, 4, 0, -5}, /*[18] 0x32 two */ + {70, 8, 5, 4, 0, -5}, /*[19] 0x33 three */ + {75, 8, 5, 4, 0, -5}, /*[20] 0x34 four */ + {80, 8, 5, 4, 0, -5}, /*[21] 0x35 five */ + {85, 8, 5, 4, 0, -5}, /*[22] 0x36 six */ + {90, 8, 5, 4, 0, -5}, /*[23] 0x37 seven */ + {95, 8, 5, 4, 0, -5}, /*[24] 0x38 eight */ + {100, 8, 5, 4, 0, -5}, /*[25] 0x39 nine */ + {105, 8, 3, 2, 0, -4}, /*[26] 0x3A colon */ + {108, 8, 4, 3, 0, -4}, /*[27] 0x3B semicolon */ + {112, 8, 5, 4, 0, -5}, /*[28] 0x3C less */ + {117, 8, 3, 4, 0, -4}, /*[29] 0x3D equal */ + {120, 8, 5, 4, 0, -5}, /*[30] 0x3E greater */ + {125, 8, 5, 4, 0, -5}, /*[31] 0x3F question */ + {130, 8, 5, 4, 0, -5}, /*[32] 0x40 at */ + {135, 8, 5, 4, 0, -5}, /*[33] 0x41 A */ + {140, 8, 5, 4, 0, -5}, /*[34] 0x42 B */ + {145, 8, 5, 4, 0, -5}, /*[35] 0x43 C */ + {150, 8, 5, 4, 0, -5}, /*[36] 0x44 D */ + {155, 8, 5, 4, 0, -5}, /*[37] 0x45 E */ + {160, 8, 5, 4, 0, -5}, /*[38] 0x46 F */ + {165, 8, 5, 4, 0, -5}, /*[39] 0x47 G */ + {170, 8, 5, 4, 0, -5}, /*[40] 0x48 H */ + {175, 8, 5, 2, 0, -5}, /*[41] 0x49 I */ + {180, 8, 5, 4, 0, -5}, /*[42] 0x4A J */ + {185, 8, 5, 4, 0, -5}, /*[43] 0x4B K */ + {190, 8, 5, 4, 0, -5}, /*[44] 0x4C L */ + {195, 8, 5, 6, 0, -5}, /*[45] 0x4D M */ + {200, 8, 5, 5, 0, -5}, /*[46] 0x4E N */ + {205, 8, 5, 4, 0, -5}, /*[47] 0x4F O */ + {210, 8, 5, 4, 0, -5}, /*[48] 0x50 P */ + {215, 8, 5, 5, 0, -5}, /*[49] 0x51 Q */ + {220, 8, 5, 4, 0, -5}, /*[50] 0x52 R */ + {225, 8, 5, 4, 0, -5}, /*[51] 0x53 S */ + {230, 8, 5, 4, 0, -5}, /*[52] 0x54 T */ + {235, 8, 5, 4, 0, -5}, /*[53] 0x55 U */ + {240, 8, 5, 4, 0, -5}, /*[54] 0x56 V */ + {245, 8, 5, 6, 0, -5}, /*[55] 0x57 W */ + {250, 8, 5, 4, 0, -5}, /*[56] 0x58 X */ + {255, 8, 5, 4, 0, -5}, /*[57] 0x59 Y */ + {260, 8, 5, 4, 0, -5}, /*[58] 0x5A Z */ + {265, 8, 5, 4, 0, -5}, /*[59] 0x5B bracketleft */ + {270, 8, 3, 4, 0, -4}, /*[60] 0x5C backslash */ + {273, 8, 5, 4, 0, -5}, /*[61] 0x5D bracketright */ + {278, 8, 2, 4, 0, -5}, /*[62] 0x5E asciicircum */ + {280, 8, 1, 4, 0, -1}, /*[63] 0x5F underscore */ + {281, 8, 2, 3, 0, -5}, /*[64] 0x60 grave */ + {283, 8, 4, 4, 0, -4}, /*[65] 0x61 a */ + {287, 8, 5, 4, 0, -5}, /*[66] 0x62 b */ + {292, 8, 4, 4, 0, -4}, /*[67] 0x63 c */ + {296, 8, 5, 4, 0, -5}, /*[68] 0x64 d */ + {301, 8, 4, 4, 0, -4}, /*[69] 0x65 e */ + {305, 8, 5, 4, 0, -5}, /*[70] 0x66 f */ + {310, 8, 5, 4, 0, -4}, /*[71] 0x67 g */ + {315, 8, 5, 4, 0, -5}, /*[72] 0x68 h */ + {320, 8, 5, 2, 0, -5}, /*[73] 0x69 i */ + {325, 8, 6, 4, 0, -5}, /*[74] 0x6A j */ + {331, 8, 5, 4, 0, -5}, /*[75] 0x6B k */ + {336, 8, 5, 4, 0, -5}, /*[76] 0x6C l */ + {341, 8, 4, 4, 0, -4}, /*[77] 0x6D m */ + {345, 8, 4, 4, 0, -4}, /*[78] 0x6E n */ + {349, 8, 4, 4, 0, -4}, /*[79] 0x6F o */ + {353, 8, 5, 4, 0, -4}, /*[80] 0x70 p */ + {358, 8, 5, 4, 0, -4}, /*[81] 0x71 q */ + {363, 8, 4, 4, 0, -4}, /*[82] 0x72 r */ + {367, 8, 4, 4, 0, -4}, /*[83] 0x73 s */ + {371, 8, 5, 4, 0, -5}, /*[84] 0x74 t */ + {376, 8, 4, 4, 0, -4}, /*[85] 0x75 u */ + {380, 8, 4, 4, 0, -4}, /*[86] 0x76 v */ + {384, 8, 4, 4, 0, -4}, /*[87] 0x77 w */ + {388, 8, 4, 4, 0, -4}, /*[88] 0x78 x */ + {392, 8, 5, 4, 0, -4}, /*[89] 0x79 y */ + {397, 8, 4, 4, 0, -4}, /*[90] 0x7A z */ + {401, 8, 5, 4, 0, -5}, /*[91] 0x7B braceleft */ + {406, 8, 5, 2, 0, -5}, /*[92] 0x7C bar */ + {411, 8, 5, 4, 0, -5}, /*[93] 0x7D braceright */ + {416, 8, 2, 4, 0, -5}, /*[94] 0x7E asciitilde */ + + {418, 8, 5, 2, 0, -5}, /*[95] 0xA1 exclamdown */ + {423, 8, 5, 4, 0, -5}, /*[96] 0xA2 cent */ + {428, 8, 5, 4, 0, -5}, /*[97] 0xA3 sterling */ + {433, 8, 5, 4, 0, -5}, /*[98] 0xA4 currency */ + {438, 8, 5, 4, 0, -5}, /*[99] 0xA5 yen */ + {443, 8, 5, 2, 0, -5}, /*[100] 0xA6 brokenbar */ + {448, 8, 5, 4, 0, -5}, /*[101] 0xA7 section */ + {453, 8, 1, 4, 0, -5}, /*[102] 0xA8 dieresis */ + {454, 8, 3, 4, 0, -5}, /*[103] 0xA9 copyright */ + {457, 8, 5, 4, 0, -5}, /*[104] 0xAA ordfeminine */ + {462, 8, 3, 3, 0, -5}, /*[105] 0xAB guillemotleft */ + {465, 8, 2, 4, 0, -4}, /*[106] 0xAC logicalnot */ + {467, 8, 1, 3, 0, -3}, /*[107] 0xAD softhyphen */ + {468, 8, 3, 4, 0, -5}, /*[108] 0xAE registered */ + {471, 8, 1, 4, 0, -5}, /*[109] 0xAF macron */ + {472, 8, 3, 4, 0, -5}, /*[110] 0xB0 degree */ + {475, 8, 5, 4, 0, -5}, /*[111] 0xB1 plusminus */ + {480, 8, 3, 4, 0, -5}, /*[112] 0xB2 twosuperior */ + {483, 8, 3, 4, 0, -5}, /*[113] 0xB3 threesuperior */ + {486, 8, 2, 3, 0, -5}, /*[114] 0xB4 acute */ + {488, 8, 5, 4, 0, -5}, /*[115] 0xB5 mu */ + {493, 8, 5, 4, 0, -5}, /*[116] 0xB6 paragraph */ + {498, 8, 3, 4, 0, -4}, /*[117] 0xB7 periodcentered */ + {501, 8, 3, 4, 0, -3}, /*[118] 0xB8 cedilla */ + {504, 8, 3, 2, 0, -5}, /*[119] 0xB9 onesuperior */ + {507, 8, 5, 4, 0, -5}, /*[120] 0xBA ordmasculine */ + {512, 8, 3, 3, 0, -5}, /*[121] 0xBB guillemotright */ + {515, 8, 5, 4, 0, -5}, /*[122] 0xBC onequarter */ + {520, 8, 5, 4, 0, -5}, /*[123] 0xBD onehalf */ + {525, 8, 5, 4, 0, -5}, /*[124] 0xBE threequarters */ + {530, 8, 5, 4, 0, -5}, /*[125] 0xBF questiondown */ + {535, 8, 5, 4, 0, -5}, /*[126] 0xC0 Agrave */ + {540, 8, 5, 4, 0, -5}, /*[127] 0xC1 Aacute */ + {545, 8, 5, 4, 0, -5}, /*[128] 0xC2 Acircumflex */ + {550, 8, 5, 4, 0, -5}, /*[129] 0xC3 Atilde */ + {555, 8, 5, 4, 0, -5}, /*[130] 0xC4 Adieresis */ + {560, 8, 5, 4, 0, -5}, /*[131] 0xC5 Aring */ + {565, 8, 5, 4, 0, -5}, /*[132] 0xC6 AE */ + {570, 8, 6, 4, 0, -5}, /*[133] 0xC7 Ccedilla */ + {576, 8, 5, 4, 0, -5}, /*[134] 0xC8 Egrave */ + {581, 8, 5, 4, 0, -5}, /*[135] 0xC9 Eacute */ + {586, 8, 5, 4, 0, -5}, /*[136] 0xCA Ecircumflex */ + {591, 8, 5, 4, 0, -5}, /*[137] 0xCB Edieresis */ + {596, 8, 5, 4, 0, -5}, /*[138] 0xCC Igrave */ + {601, 8, 5, 4, 0, -5}, /*[139] 0xCD Iacute */ + {606, 8, 5, 4, 0, -5}, /*[140] 0xCE Icircumflex */ + {611, 8, 5, 4, 0, -5}, /*[141] 0xCF Idieresis */ + {616, 8, 5, 4, 0, -5}, /*[142] 0xD0 Eth */ + {621, 8, 5, 4, 0, -5}, /*[143] 0xD1 Ntilde */ + {626, 8, 5, 4, 0, -5}, /*[144] 0xD2 Ograve */ + {631, 8, 5, 4, 0, -5}, /*[145] 0xD3 Oacute */ + {636, 8, 5, 4, 0, -5}, /*[146] 0xD4 Ocircumflex */ + {641, 8, 5, 4, 0, -5}, /*[147] 0xD5 Otilde */ + {646, 8, 5, 4, 0, -5}, /*[148] 0xD6 Odieresis */ + {651, 8, 3, 4, 0, -4}, /*[149] 0xD7 multiply */ + {654, 8, 5, 4, 0, -5}, /*[150] 0xD8 Oslash */ + {659, 8, 5, 4, 0, -5}, /*[151] 0xD9 Ugrave */ + {664, 8, 5, 4, 0, -5}, /*[152] 0xDA Uacute */ + {669, 8, 5, 4, 0, -5}, /*[153] 0xDB Ucircumflex */ + {674, 8, 5, 4, 0, -5}, /*[154] 0xDC Udieresis */ + {679, 8, 5, 4, 0, -5}, /*[155] 0xDD Yacute */ + {684, 8, 5, 4, 0, -5}, /*[156] 0xDE Thorn */ + {689, 8, 6, 4, 0, -5}, /*[157] 0xDF germandbls */ + {695, 8, 5, 4, 0, -5}, /*[158] 0xE0 agrave */ + {700, 8, 5, 4, 0, -5}, /*[159] 0xE1 aacute */ + {705, 8, 5, 4, 0, -5}, /*[160] 0xE2 acircumflex */ + {710, 8, 5, 4, 0, -5}, /*[161] 0xE3 atilde */ + {715, 8, 5, 4, 0, -5}, /*[162] 0xE4 adieresis */ + {720, 8, 5, 4, 0, -5}, /*[163] 0xE5 aring */ + {725, 8, 4, 4, 0, -4}, /*[164] 0xE6 ae */ + {729, 8, 5, 4, 0, -4}, /*[165] 0xE7 ccedilla */ + {734, 8, 5, 4, 0, -5}, /*[166] 0xE8 egrave */ + {739, 8, 5, 4, 0, -5}, /*[167] 0xE9 eacute */ + {744, 8, 5, 4, 0, -5}, /*[168] 0xEA ecircumflex */ + {749, 8, 5, 4, 0, -5}, /*[169] 0xEB edieresis */ + {754, 8, 5, 3, 0, -5}, /*[170] 0xEC igrave */ + {759, 8, 5, 3, 0, -5}, /*[171] 0xED iacute */ + {764, 8, 5, 4, 0, -5}, /*[172] 0xEE icircumflex */ + {769, 8, 5, 4, 0, -5}, /*[173] 0xEF idieresis */ + {774, 8, 5, 4, 0, -5}, /*[174] 0xF0 eth */ + {779, 8, 5, 4, 0, -5}, /*[175] 0xF1 ntilde */ + {784, 8, 5, 4, 0, -5}, /*[176] 0xF2 ograve */ + {789, 8, 5, 4, 0, -5}, /*[177] 0xF3 oacute */ + {794, 8, 5, 4, 0, -5}, /*[178] 0xF4 ocircumflex */ + {799, 8, 5, 4, 0, -5}, /*[179] 0xF5 otilde */ + {804, 8, 5, 4, 0, -5}, /*[180] 0xF6 odieresis */ + {809, 8, 5, 4, 0, -5}, /*[181] 0xF7 divide */ + {814, 8, 4, 4, 0, -4}, /*[182] 0xF8 oslash */ + {818, 8, 5, 4, 0, -5}, /*[183] 0xF9 ugrave */ + {823, 8, 5, 4, 0, -5}, /*[184] 0xFA uacute */ + {828, 8, 5, 4, 0, -5}, /*[185] 0xFB ucircumflex */ + {833, 8, 5, 4, 0, -5}, /*[186] 0xFC udieresis */ + {838, 8, 6, 4, 0, -5}, /*[187] 0xFD yacute */ + {844, 8, 5, 4, 0, -4}, /*[188] 0xFE thorn */ + {849, 8, 6, 4, 0, -5}, /*[189] 0xFF ydieresis */ + {855, 8, 1, 2, 0, -1}, /*[190] 0x11D gcircumflex */ + {856, 8, 5, 4, 0, -5}, /*[191] 0x152 OE */ + {861, 8, 4, 4, 0, -4}, /*[192] 0x153 oe */ + {865, 8, 5, 4, 0, -5}, /*[193] 0x160 Scaron */ + {870, 8, 5, 4, 0, -5}, /*[194] 0x161 scaron */ + {875, 8, 5, 4, 0, -5}, /*[195] 0x178 Ydieresis */ + {880, 8, 5, 4, 0, -5}, /*[196] 0x17D Zcaron */ + {885, 8, 5, 4, 0, -5}, /*[197] 0x17E zcaron */ + {890, 8, 1, 2, 0, -1}, /*[198] 0xEA4 uni0EA4 */ + {891, 8, 1, 2, 0, -1}, /*[199] 0x13A0 uni13A0 */ + {892, 8, 1, 2, 0, -3}, /*[200] 0x2022 bullet */ + {893, 8, 1, 4, 0, -1}, /*[201] 0x2026 ellipsis */ + {894, 8, 5, 4, 0, -5}, /*[202] 0x20AC Euro */ + {899, 8, 5, 4, 0, -5}, /*[203] 0xFFFD uniFFFD */ +}; + +const GFXfont AwtrixFont PROGMEM = { + (uint8_t *)AwtrixBitmaps, + (GFXglyph *)AwtrixFontGlyphs, + 0x20, 0xFF, 6}; diff --git a/lib/MatrixUI/Fonts/fallout.h b/lib/MatrixUI/Fonts/fallout.h new file mode 100644 index 0000000..fa74475 --- /dev/null +++ b/lib/MatrixUI/Fonts/fallout.h @@ -0,0 +1,320 @@ +const uint8_t Fallout[] PROGMEM = { + 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x1F, 0xF8, + 0xF9, 0xCF, 0x9C, 0xF9, 0xCF, 0x9F, 0xF9, 0xF0, 0x3E, 0x3E, 0x1F, 0x1F, + 0x0F, 0x8F, 0x87, 0xC7, 0xC3, 0xE3, 0xE7, 0xFF, 0xF3, 0xFF, 0xF8, 0x7C, + 0x7C, 0x3E, 0x3E, 0x1F, 0x1F, 0x3F, 0xFF, 0xFF, 0xFF, 0xF3, 0xE3, 0xE1, + 0xF1, 0xF0, 0xF8, 0xF8, 0x7C, 0x7C, 0x3E, 0x3E, 0x00, 0x07, 0xC0, 0x0F, + 0x80, 0xFF, 0xF9, 0xFF, 0xF3, 0xFF, 0xFF, 0x00, 0x3E, 0x00, 0x1F, 0xF8, + 0x3F, 0xF0, 0x7F, 0xE0, 0x00, 0xF8, 0x01, 0xFF, 0xFF, 0x1F, 0xFE, 0x3F, + 0xFC, 0x03, 0xE0, 0x07, 0xC0, 0xF8, 0x01, 0x8F, 0x80, 0x18, 0xF8, 0x0F, + 0x8F, 0x80, 0xF8, 0xF8, 0x0F, 0x80, 0x03, 0xE0, 0x00, 0x3E, 0x00, 0x1F, + 0x00, 0x01, 0xF0, 0x00, 0x1F, 0x00, 0x07, 0xC0, 0x00, 0x7C, 0x00, 0x3E, + 0x01, 0xF3, 0xE0, 0x1F, 0x3E, 0x01, 0xFF, 0x80, 0x1F, 0xF8, 0x01, 0xF0, + 0x07, 0xF0, 0x03, 0xF8, 0x0F, 0x8F, 0x87, 0xC7, 0xC3, 0xE3, 0xE0, 0x3F, + 0x80, 0x1F, 0xC0, 0x7F, 0x9F, 0x3F, 0xCF, 0x9F, 0xE7, 0xFE, 0x7F, 0x9F, + 0x3F, 0xCF, 0x83, 0xE7, 0xC1, 0xF3, 0xE0, 0xF8, 0x7F, 0x9F, 0x3F, 0xCF, + 0x80, 0xFF, 0xFF, 0xFF, 0x80, 0x07, 0xC1, 0xF3, 0xE0, 0xF8, 0x3E, 0x3E, + 0x0F, 0x83, 0xE0, 0xF8, 0x3E, 0x0F, 0x83, 0xE0, 0x3E, 0x0F, 0x83, 0xE0, + 0x1F, 0x07, 0xC0, 0xF8, 0x3E, 0x03, 0xE0, 0xF8, 0x3E, 0x01, 0xF0, 0x7C, + 0x1F, 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x3E, 0x0F, 0x83, 0xE3, 0xE0, 0xF8, + 0x00, 0x3E, 0x3E, 0x1F, 0x1F, 0x0F, 0x8F, 0x80, 0xFE, 0x00, 0x7F, 0x07, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xF0, 0x03, 0xF8, 0x0F, 0x8F, + 0x87, 0xC7, 0xC3, 0xE3, 0xE0, 0x07, 0xC0, 0x0F, 0x80, 0x1F, 0x00, 0x3E, + 0x00, 0x7C, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xC0, 0x0F, 0x80, + 0x1F, 0x00, 0x3E, 0x00, 0x7C, 0x00, 0x3E, 0x7C, 0xF9, 0xF3, 0xFF, 0x3E, + 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0x80, 0x00, + 0x0E, 0x00, 0x1C, 0x00, 0xF8, 0x01, 0xF0, 0x03, 0xE0, 0x3E, 0x00, 0x7C, + 0x03, 0xE0, 0x07, 0xC0, 0x0F, 0x80, 0xF8, 0x01, 0xF0, 0x0F, 0x80, 0x1F, + 0x00, 0x3E, 0x00, 0x60, 0x00, 0xC0, 0x00, 0x3F, 0xF0, 0x7F, 0xE3, 0xE0, + 0xFF, 0xC1, 0xFF, 0x83, 0xFF, 0x3F, 0xFE, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xF8, 0xFF, 0xF1, 0xFF, 0x83, 0xFF, 0x07, 0xFE, 0x0F, 0x9F, + 0xF8, 0x3F, 0xF0, 0x07, 0xC1, 0xF3, 0xFC, 0xFF, 0x3F, 0xFF, 0xFF, 0xFC, + 0x1F, 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x07, + 0xC0, 0x3F, 0xF0, 0x7F, 0xE3, 0xE0, 0xFF, 0xC1, 0xFF, 0x83, 0xE0, 0x07, + 0xC0, 0x0F, 0x83, 0xF8, 0x07, 0xF0, 0x0F, 0xE0, 0xF8, 0x01, 0xF0, 0x0F, + 0x80, 0x1F, 0x00, 0x3E, 0x00, 0x7F, 0xFF, 0xFF, 0xFE, 0x3F, 0xF0, 0x7F, + 0xE3, 0xE0, 0xFF, 0xC1, 0xFF, 0x83, 0xE0, 0x07, 0xC0, 0x0F, 0x83, 0xF8, + 0x07, 0xF0, 0x0F, 0xE0, 0x00, 0xF8, 0x01, 0xFF, 0x83, 0xFF, 0x07, 0xFE, + 0x0F, 0x9F, 0xF8, 0x3F, 0xF0, 0x01, 0xFE, 0x03, 0xFC, 0x1F, 0xF8, 0x3F, + 0xF0, 0x7F, 0xE7, 0xC7, 0xCF, 0x8F, 0xFC, 0x1F, 0xF8, 0x3F, 0xF0, 0x7F, + 0xFF, 0xFF, 0xFF, 0xF0, 0x03, 0xE0, 0x07, 0xC0, 0x0F, 0x80, 0x1F, 0x00, + 0x3E, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x07, 0xC0, 0x0F, 0x80, 0x1F, 0xFE, + 0x3F, 0xFC, 0x00, 0x1F, 0x00, 0x3E, 0x00, 0x7C, 0x00, 0xF8, 0x01, 0xFF, + 0x83, 0xFF, 0x07, 0xFE, 0x0F, 0x9F, 0xF8, 0x3F, 0xF0, 0x07, 0xF0, 0x0F, + 0xE0, 0xF8, 0x01, 0xF0, 0x03, 0xE0, 0x1F, 0x00, 0x3E, 0x00, 0x7F, 0xF8, + 0xFF, 0xF1, 0xFF, 0xE3, 0xE0, 0xFF, 0xC1, 0xFF, 0x83, 0xFF, 0x07, 0xFE, + 0x0F, 0x9F, 0xF8, 0x3F, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0xFF, 0xC1, + 0xFF, 0x83, 0xE0, 0x07, 0xC0, 0x0F, 0x80, 0xF8, 0x01, 0xF0, 0x03, 0xE0, + 0x1F, 0x00, 0x3E, 0x00, 0x7C, 0x00, 0xF8, 0x01, 0xF0, 0x03, 0xE0, 0x07, + 0xC0, 0x3F, 0xF0, 0x7F, 0xE3, 0xE0, 0xFF, 0xC1, 0xFF, 0x83, 0xFF, 0x07, + 0xFE, 0x0F, 0x9F, 0xF8, 0x3F, 0xF0, 0x7F, 0xE3, 0xE0, 0xFF, 0xC1, 0xFF, + 0x83, 0xFF, 0x07, 0xFE, 0x0F, 0x9F, 0xF8, 0x3F, 0xF0, 0x3F, 0xF0, 0x7F, + 0xE3, 0xE0, 0xFF, 0xC1, 0xFF, 0x83, 0xFF, 0x07, 0xFE, 0x0F, 0x9F, 0xFF, + 0x3F, 0xFE, 0x7F, 0xFC, 0x00, 0xF8, 0x01, 0xF0, 0x1F, 0x00, 0x3E, 0x00, + 0x7C, 0x1F, 0xE0, 0x3F, 0xC0, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x3F, + 0xFF, 0xFF, 0xE0, 0x3E, 0x7C, 0xF9, 0xF3, 0xE0, 0x00, 0x00, 0x00, 0x00, + 0xF9, 0xF3, 0xE7, 0xCF, 0xFC, 0xF8, 0x01, 0xF0, 0x1F, 0x07, 0xC0, 0x7C, + 0x07, 0xC3, 0xE0, 0x3E, 0x0F, 0x80, 0xF8, 0x0F, 0x80, 0x3E, 0x03, 0xE0, + 0x07, 0xC0, 0x7C, 0x07, 0xC0, 0x1F, 0x01, 0xF0, 0xFF, 0xFF, 0xFF, 0xFC, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFC, 0xF8, 0x0F, 0x80, 0x3E, 0x03, 0xE0, 0x3E, 0x00, 0x7C, + 0x07, 0xC0, 0x1F, 0x01, 0xF0, 0x1F, 0x07, 0xC0, 0x7C, 0x3E, 0x03, 0xE0, + 0x3E, 0x0F, 0x80, 0xF8, 0x00, 0x3F, 0xF0, 0x7F, 0xE3, 0xE0, 0xFF, 0xC1, + 0xFF, 0x83, 0xE0, 0x07, 0xC0, 0x0F, 0x80, 0xF8, 0x01, 0xF0, 0x03, 0xE0, + 0x1F, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xE0, 0x07, + 0xC0, 0x3F, 0xFE, 0x1F, 0xFF, 0x3E, 0x03, 0x9F, 0x01, 0xCF, 0x80, 0xE7, + 0xCF, 0xFF, 0xE7, 0xFF, 0xF3, 0xFF, 0xF9, 0xFF, 0xFC, 0xFF, 0xFE, 0x7F, + 0xFF, 0x3F, 0xFF, 0x80, 0x07, 0xC0, 0x03, 0xE0, 0x00, 0x7F, 0xE0, 0x3F, + 0xF0, 0x00, 0x00, 0x01, 0x80, 0x00, 0x18, 0x00, 0x0F, 0xF0, 0x00, 0xFF, + 0x00, 0x0F, 0xF0, 0x03, 0xFF, 0x00, 0x3F, 0xF0, 0x1F, 0x1F, 0x01, 0xF1, + 0xF0, 0x1F, 0x1F, 0x07, 0xFF, 0xF0, 0x7F, 0xFF, 0x3E, 0x01, 0xF3, 0xE0, + 0x1F, 0x3E, 0x01, 0xFF, 0x80, 0x1F, 0xF8, 0x01, 0xF0, 0xFF, 0xFE, 0x7F, + 0xFF, 0x3E, 0x03, 0x9F, 0x01, 0xCF, 0x80, 0xE7, 0xC0, 0x7F, 0xE0, 0x3F, + 0xFF, 0xFC, 0xFF, 0xFE, 0x7F, 0xFF, 0x3E, 0x03, 0xFF, 0x01, 0xFF, 0x80, + 0xFF, 0xC0, 0x7F, 0xE0, 0x3F, 0xFF, 0xFC, 0xFF, 0xFE, 0x00, 0x3F, 0xFE, + 0x7F, 0xFF, 0xE0, 0x07, 0xC0, 0x0F, 0x80, 0x1F, 0x00, 0x3E, 0x00, 0x7C, + 0x00, 0xF8, 0x01, 0xF0, 0x03, 0xE0, 0x07, 0xC0, 0x0F, 0x80, 0x1F, 0x00, + 0x3E, 0x00, 0x1F, 0xFF, 0x3F, 0xFE, 0xFF, 0xFE, 0x7F, 0xFF, 0x3E, 0x03, + 0x9F, 0x01, 0xCF, 0x80, 0xE7, 0xC0, 0x7F, 0xE0, 0x3F, 0xF0, 0x1F, 0xF8, + 0x0F, 0xFC, 0x07, 0xFE, 0x03, 0xFF, 0x01, 0xFF, 0x80, 0xFF, 0xC0, 0x7F, + 0xE0, 0x3F, 0xFF, 0xFC, 0xFF, 0xFE, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, + 0x07, 0xC0, 0x0F, 0x80, 0x1F, 0x00, 0x3E, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xE0, 0x07, 0xC0, 0x0F, 0x80, 0x1F, 0x00, 0x3E, 0x00, 0x7F, + 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x07, 0xC0, 0x0F, 0x80, + 0x1F, 0x00, 0x3E, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x07, + 0xC0, 0x0F, 0x80, 0x1F, 0x00, 0x3E, 0x00, 0x7C, 0x00, 0xF8, 0x00, 0x3F, + 0xFE, 0x1F, 0xFF, 0x3E, 0x00, 0x1F, 0x00, 0x0F, 0x80, 0x07, 0xC0, 0x03, + 0xE0, 0x01, 0xF0, 0x7F, 0xF8, 0x3F, 0xFC, 0x1F, 0xFE, 0x03, 0xFF, 0x01, + 0xFF, 0x80, 0xFF, 0xC0, 0x7F, 0xE0, 0x3E, 0x7F, 0xFC, 0x3F, 0xFE, 0x00, + 0xF8, 0x0E, 0x7C, 0x07, 0x3E, 0x03, 0xFF, 0x01, 0xFF, 0x80, 0xFF, 0xC0, + 0x7F, 0xE0, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x03, 0xFF, + 0x01, 0xFF, 0x80, 0xFF, 0xC0, 0x7F, 0xE0, 0x3F, 0xF0, 0x1F, 0xF8, 0x0F, + 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, + 0x00, 0x0E, 0x00, 0x07, 0x00, 0x03, 0xE0, 0x01, 0xF0, 0x00, 0xF8, 0x00, + 0x7C, 0x00, 0x3E, 0x00, 0x1F, 0x00, 0x0F, 0x80, 0x07, 0xFE, 0x03, 0xFF, + 0x01, 0xFF, 0x80, 0xFF, 0xC0, 0x7F, 0xE0, 0x3E, 0x7F, 0xFC, 0x3F, 0xFE, + 0x00, 0xF8, 0x0E, 0x7C, 0x07, 0x3E, 0x0F, 0x9F, 0x07, 0xCF, 0x83, 0xE7, + 0xCF, 0x83, 0xE7, 0xC1, 0xFF, 0x80, 0xFF, 0xC0, 0x7F, 0xE0, 0x3E, 0x7C, + 0x1F, 0x3E, 0x0F, 0x83, 0xE7, 0xC1, 0xF3, 0xE0, 0xF9, 0xF0, 0x1F, 0xF8, + 0x0F, 0x80, 0xF8, 0x01, 0xF0, 0x03, 0xE0, 0x07, 0xC0, 0x0F, 0x80, 0x1F, + 0x00, 0x3E, 0x00, 0x7C, 0x00, 0xF8, 0x01, 0xF0, 0x03, 0xE0, 0x07, 0xC0, + 0x0F, 0x80, 0x1F, 0x00, 0x3E, 0x00, 0x7F, 0xFF, 0xFF, 0xFE, 0xFF, 0xFE, + 0x7F, 0xFF, 0x3E, 0x73, 0x9F, 0x39, 0xCF, 0x9C, 0xE7, 0xCE, 0x7F, 0xE7, + 0x3F, 0xF3, 0x9F, 0xF9, 0xCF, 0xFC, 0xE7, 0xFE, 0x73, 0xFF, 0x39, 0xFF, + 0x9C, 0xFF, 0xCE, 0x7F, 0xE7, 0x3F, 0xF3, 0x9F, 0xF9, 0xCF, 0x80, 0xF8, + 0x0E, 0x7C, 0x07, 0x3F, 0x83, 0xFF, 0xC1, 0xFF, 0xE0, 0xFF, 0xFE, 0x7F, + 0xFF, 0x3F, 0xF3, 0xFF, 0xF9, 0xFF, 0xFC, 0xFF, 0xFE, 0x0F, 0xFF, 0x07, + 0xFF, 0x80, 0xFF, 0xC0, 0x7F, 0xE0, 0x3F, 0xF0, 0x1F, 0xF8, 0x0F, 0x80, + 0x3F, 0xFE, 0x1F, 0xFF, 0x3E, 0x03, 0x9F, 0x01, 0xCF, 0x80, 0xE7, 0xC0, + 0x7F, 0xE0, 0x3F, 0xF0, 0x1F, 0xF8, 0x0F, 0xFC, 0x07, 0xFE, 0x03, 0xFF, + 0x01, 0xFF, 0x80, 0xFF, 0xC0, 0x7F, 0xE0, 0x3E, 0x7F, 0xFC, 0x3F, 0xFE, + 0x00, 0xFF, 0xFE, 0x7F, 0xFF, 0x3E, 0x03, 0x9F, 0x01, 0xCF, 0x80, 0xE7, + 0xC0, 0x7F, 0xE0, 0x3F, 0xFF, 0xFC, 0xFF, 0xFE, 0x7F, 0xFF, 0x3E, 0x00, + 0x1F, 0x00, 0x0F, 0x80, 0x07, 0xC0, 0x03, 0xE0, 0x01, 0xF0, 0x00, 0xF8, + 0x00, 0x00, 0x3F, 0xFE, 0x1F, 0xFF, 0x3E, 0x03, 0x9F, 0x01, 0xCF, 0x80, + 0xE7, 0xC0, 0x7F, 0xE0, 0x3F, 0xF0, 0x1F, 0xF8, 0x0F, 0xFC, 0x07, 0xFE, + 0x03, 0xFF, 0x01, 0xFF, 0x9C, 0xFF, 0xCE, 0x7F, 0xE7, 0x3E, 0x7F, 0xFC, + 0x3F, 0xFE, 0x00, 0x1F, 0xC0, 0x0F, 0xE0, 0xFF, 0xFE, 0x7F, 0xFF, 0x3E, + 0x03, 0x9F, 0x01, 0xCF, 0x80, 0xE7, 0xC0, 0x7F, 0xE0, 0x3F, 0xFF, 0xFC, + 0xFF, 0xFE, 0x7F, 0xFF, 0x3E, 0x03, 0xFF, 0x01, 0xFF, 0x80, 0xFF, 0xC0, + 0x7F, 0xE0, 0x3F, 0xF0, 0x1F, 0xF8, 0x0F, 0x80, 0x3F, 0xFE, 0x1F, 0xFF, + 0x3E, 0x00, 0x1F, 0x00, 0x0F, 0x80, 0x07, 0xC0, 0x03, 0xE0, 0x00, 0x7F, + 0xFC, 0x3F, 0xFE, 0x1F, 0xFF, 0x00, 0x03, 0xE0, 0x01, 0xF0, 0x00, 0xF8, + 0x00, 0x7C, 0x00, 0x3F, 0xFF, 0xFC, 0xFF, 0xFE, 0x00, 0xFF, 0xFF, 0xFF, + 0xFC, 0x1F, 0x00, 0x3E, 0x00, 0x7C, 0x00, 0xF8, 0x01, 0xF0, 0x03, 0xE0, + 0x07, 0xC0, 0x0F, 0x80, 0x1F, 0x00, 0x3E, 0x00, 0x7C, 0x00, 0xF8, 0x01, + 0xF0, 0x03, 0xE0, 0x07, 0xC0, 0xF8, 0x0E, 0x7C, 0x07, 0x3E, 0x03, 0xFF, + 0x01, 0xFF, 0x80, 0xFF, 0xC0, 0x7F, 0xE0, 0x3F, 0xF0, 0x1F, 0xF8, 0x0F, + 0xFC, 0x07, 0xFE, 0x03, 0xFF, 0x01, 0xFF, 0x80, 0xFF, 0xC0, 0x7F, 0xE0, + 0x3E, 0x7F, 0xFF, 0x3F, 0xFF, 0x80, 0xF8, 0x01, 0x8F, 0x80, 0x18, 0xF8, + 0x01, 0xFF, 0x80, 0x1F, 0xF8, 0x01, 0xF3, 0xE0, 0xF8, 0x3E, 0x0F, 0x83, + 0xE0, 0xF8, 0x3E, 0x0F, 0x83, 0xE0, 0xF8, 0x07, 0xFE, 0x00, 0x7F, 0xE0, + 0x07, 0xFE, 0x00, 0x7F, 0xE0, 0x07, 0xFE, 0x00, 0x1F, 0x00, 0x01, 0xF0, + 0x00, 0xF9, 0xCE, 0x7C, 0xE7, 0x3E, 0x73, 0xFF, 0x39, 0xFF, 0x9C, 0xFF, + 0xCE, 0x7F, 0xE7, 0x3F, 0xF3, 0x9F, 0xF9, 0xCF, 0xFC, 0xE7, 0xFE, 0x73, + 0xFF, 0x39, 0xFF, 0x9C, 0xFF, 0xCE, 0x7F, 0xE7, 0x3F, 0xFF, 0xFC, 0xFF, + 0xFE, 0x00, 0xF8, 0x01, 0x8F, 0x80, 0x18, 0xF8, 0x01, 0xFF, 0x80, 0x1F, + 0xF8, 0x01, 0xF3, 0xE0, 0xF8, 0x3E, 0x0F, 0x80, 0x7F, 0xE0, 0x07, 0xFE, + 0x00, 0x7F, 0xE0, 0x3E, 0x0F, 0x83, 0xE0, 0xF8, 0xF8, 0x01, 0xFF, 0x80, + 0x1F, 0xF8, 0x01, 0xFF, 0x80, 0x1F, 0xF8, 0x01, 0xF0, 0xF8, 0x01, 0xFC, + 0x00, 0xCF, 0x83, 0xE7, 0xC1, 0xF3, 0xE0, 0xF8, 0x3F, 0xF0, 0x1F, 0xF8, + 0x03, 0xE0, 0x01, 0xF0, 0x00, 0xF8, 0x00, 0x7C, 0x00, 0x3E, 0x00, 0x1F, + 0x00, 0x0F, 0x80, 0x07, 0xC0, 0x03, 0xE0, 0x01, 0xF0, 0x00, 0xFF, 0xFE, + 0x7F, 0xFF, 0x00, 0x03, 0xE0, 0x01, 0xF0, 0x00, 0xF8, 0x01, 0xF0, 0x00, + 0xF8, 0x0F, 0xE0, 0x07, 0xF0, 0x03, 0xF8, 0x0F, 0x80, 0x07, 0xC0, 0x0F, + 0x80, 0x07, 0xC0, 0x03, 0xE0, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0xFF, + 0xFF, 0xFF, 0x83, 0xE0, 0xF8, 0x3E, 0x0F, 0x83, 0xE0, 0xF8, 0x3E, 0x0F, + 0x83, 0xE0, 0xF8, 0x3E, 0x0F, 0x83, 0xFF, 0xFF, 0xC0, 0xC0, 0x00, 0x60, + 0x00, 0x3E, 0x00, 0x1F, 0x00, 0x0F, 0x80, 0x01, 0xF0, 0x00, 0xF8, 0x00, + 0x0F, 0x80, 0x07, 0xC0, 0x03, 0xE0, 0x00, 0x7C, 0x00, 0x3E, 0x00, 0x03, + 0xE0, 0x01, 0xF0, 0x00, 0xF8, 0x00, 0x1F, 0x00, 0x0F, 0x80, 0xFF, 0xFF, + 0xF0, 0x7C, 0x1F, 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xC1, 0xF0, 0x7C, + 0x1F, 0x07, 0xC1, 0xF0, 0x7F, 0xFF, 0xFF, 0xC0, 0x01, 0xC0, 0x00, 0xE0, + 0x01, 0xFC, 0x00, 0xFE, 0x00, 0x7F, 0x01, 0xF1, 0xF0, 0xF8, 0xF9, 0xF0, + 0x1F, 0xF8, 0x0F, 0xFC, 0x07, 0xC0, 0xFF, 0xFF, 0xFF, 0xFC, 0xF9, 0xF3, + 0xE7, 0xCF, 0x87, 0xCF, 0x80, 0x3F, 0xFE, 0x7F, 0xFF, 0xE0, 0xFF, 0xC1, + 0xFF, 0x83, 0xFF, 0x07, 0xFE, 0x0F, 0xFC, 0x1F, 0xF8, 0x3F, 0xF0, 0x7C, + 0xFF, 0xF9, 0xFF, 0xF0, 0xF8, 0x01, 0xF0, 0x03, 0xE0, 0x07, 0xC0, 0x0F, + 0x80, 0x1F, 0xFE, 0x3F, 0xFC, 0x7C, 0x1F, 0xF8, 0x3F, 0xF0, 0x7F, 0xE0, + 0xFF, 0xC1, 0xFF, 0x83, 0xFF, 0x07, 0xFE, 0x0F, 0xFF, 0xF8, 0xFF, 0xF0, + 0x3F, 0xF3, 0xFF, 0xF8, 0x0F, 0x80, 0xF8, 0x0F, 0x80, 0xF8, 0x0F, 0x80, + 0xF8, 0x0F, 0x80, 0x3F, 0xF3, 0xFF, 0x00, 0x3E, 0x00, 0x7C, 0x00, 0xF8, + 0x01, 0xF0, 0x03, 0xE7, 0xFF, 0xCF, 0xFF, 0xFC, 0x1F, 0xF8, 0x3F, 0xF0, + 0x7F, 0xE0, 0xFF, 0xC1, 0xFF, 0x83, 0xFF, 0x07, 0xFE, 0x0F, 0x9F, 0xFF, + 0x3F, 0xFE, 0x3F, 0xF0, 0x7F, 0xE3, 0xE0, 0xFF, 0xC1, 0xFF, 0x83, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0xF8, 0x01, 0xF0, 0x00, 0xFF, 0xC1, 0xFF, + 0x80, 0x07, 0xF0, 0x7F, 0x3E, 0x03, 0xE0, 0x3E, 0x0F, 0xFF, 0xFF, 0xF3, + 0xE0, 0x3E, 0x03, 0xE0, 0x3E, 0x03, 0xE0, 0x3E, 0x03, 0xE0, 0x3E, 0x03, + 0xE0, 0x3E, 0x00, 0x3F, 0xFE, 0x7F, 0xFF, 0xE0, 0xFF, 0xC1, 0xFF, 0x83, + 0xFF, 0x07, 0xFE, 0x0F, 0xFC, 0x1F, 0xF8, 0x3F, 0xF0, 0x7C, 0xFF, 0xF9, + 0xFF, 0xF0, 0x03, 0xE0, 0x07, 0xCF, 0xFC, 0x1F, 0xF8, 0x3F, 0xF0, 0xF8, + 0x01, 0xF0, 0x03, 0xE0, 0x07, 0xC0, 0x0F, 0x80, 0x1F, 0xFE, 0x3F, 0xFC, + 0x7C, 0x1F, 0xF8, 0x3F, 0xF0, 0x7F, 0xE0, 0xFF, 0xC1, 0xFF, 0x83, 0xFF, + 0x07, 0xFE, 0x0F, 0xFC, 0x1F, 0xF8, 0x3E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xF0, 0x01, 0xF0, 0x1F, 0x01, 0xF0, 0x1F, 0x01, 0xF0, 0x1F, + 0x01, 0xF0, 0x1F, 0x01, 0xF0, 0x1F, 0x01, 0xF0, 0x1F, 0xF9, 0xFF, 0x9F, + 0x3F, 0xC3, 0xFC, 0x3F, 0xC0, 0xF8, 0x01, 0xF0, 0x03, 0xE0, 0x07, 0xC0, + 0x0F, 0x80, 0x1F, 0x07, 0xFE, 0x0F, 0xFC, 0xF8, 0xF9, 0xF1, 0xF3, 0xE3, + 0xFF, 0x07, 0xFE, 0x0F, 0x9F, 0x1F, 0x3E, 0x3E, 0x7C, 0x7C, 0x1F, 0xF8, + 0x3E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, + 0xFF, 0xFE, 0x7F, 0xFF, 0x3E, 0x73, 0xFF, 0x39, 0xFF, 0x9C, 0xFF, 0xCE, + 0x7F, 0xE7, 0x3F, 0xF3, 0x9F, 0xF9, 0xCF, 0xFC, 0xE7, 0xFE, 0x73, 0xFF, + 0x39, 0xF0, 0xFF, 0xF1, 0xFF, 0xE3, 0xE0, 0xFF, 0xC1, 0xFF, 0x83, 0xFF, + 0x07, 0xFE, 0x0F, 0xFC, 0x1F, 0xF8, 0x3F, 0xF0, 0x7F, 0xE0, 0xFF, 0xC1, + 0xF0, 0x3F, 0xF0, 0x7F, 0xE3, 0xE0, 0xFF, 0xC1, 0xFF, 0x83, 0xFF, 0x07, + 0xFE, 0x0F, 0xFC, 0x1F, 0xF8, 0x3F, 0xF0, 0x7C, 0xFF, 0xC1, 0xFF, 0x80, + 0xFF, 0xF1, 0xFF, 0xE3, 0xE0, 0xFF, 0xC1, 0xFF, 0x83, 0xFF, 0x07, 0xFE, + 0x0F, 0xFC, 0x1F, 0xF8, 0x3F, 0xF0, 0x7F, 0xFF, 0xC7, 0xFF, 0x8F, 0x80, + 0x1F, 0x00, 0x3E, 0x00, 0x7C, 0x00, 0xF8, 0x00, 0x3F, 0xFE, 0x7F, 0xFF, + 0xE0, 0xFF, 0xC1, 0xFF, 0x83, 0xFF, 0x07, 0xFE, 0x0F, 0xFC, 0x1F, 0xF8, + 0x3F, 0xF0, 0x7C, 0xFF, 0xF9, 0xFF, 0xF0, 0x03, 0xE0, 0x07, 0xC0, 0x0F, + 0x80, 0x1F, 0x00, 0x3E, 0xF9, 0xFF, 0x9F, 0xFF, 0xCF, 0xFC, 0xFF, 0xCF, + 0x80, 0xF8, 0x0F, 0x80, 0xF8, 0x0F, 0x80, 0xF8, 0x0F, 0x80, 0x3F, 0xF0, + 0x7F, 0xE3, 0xE0, 0x07, 0xC0, 0x0F, 0x80, 0x07, 0xFE, 0x0F, 0xFC, 0x00, + 0x1F, 0x00, 0x3E, 0x00, 0x7C, 0xFF, 0xC1, 0xFF, 0x80, 0x07, 0xC0, 0x0F, + 0x80, 0x1F, 0x00, 0x3E, 0x00, 0x7C, 0x1F, 0xFF, 0xFF, 0xFF, 0x83, 0xE0, + 0x07, 0xC0, 0x0F, 0x80, 0x1F, 0x00, 0x3E, 0x00, 0x7C, 0x00, 0xF8, 0x01, + 0xF0, 0x03, 0xE0, 0x07, 0xC0, 0xF8, 0x3F, 0xF0, 0x7F, 0xE0, 0xFF, 0xC1, + 0xFF, 0x83, 0xFF, 0x07, 0xFE, 0x0F, 0xFC, 0x1F, 0xF8, 0x3F, 0xF0, 0x7C, + 0xFF, 0xF9, 0xFF, 0xF0, 0xF8, 0x0E, 0x7C, 0x07, 0x3E, 0x03, 0xFF, 0x01, + 0xFF, 0x80, 0xF9, 0xF1, 0xF0, 0xF8, 0xF8, 0x7C, 0x7C, 0x3E, 0x3E, 0x1F, + 0x1F, 0x01, 0xFC, 0x00, 0xFE, 0x00, 0xF9, 0xCE, 0x7C, 0xE7, 0x3E, 0x73, + 0xFF, 0x39, 0xFF, 0x9C, 0xFF, 0xCE, 0x7F, 0xE7, 0x3F, 0xF3, 0x9F, 0xF9, + 0xCF, 0xFC, 0xE7, 0xFF, 0xFF, 0x9F, 0xFF, 0xC0, 0xF8, 0x3F, 0xF0, 0x7C, + 0xFF, 0xC1, 0xFF, 0x83, 0xFF, 0x00, 0xF8, 0x01, 0xF0, 0x1F, 0xF8, 0x3F, + 0xF0, 0x7F, 0xE3, 0xE0, 0xFF, 0xC1, 0xF0, 0xF8, 0x3F, 0xF0, 0x7F, 0xE0, + 0xFF, 0xC1, 0xFF, 0x83, 0xFF, 0x07, 0xFE, 0x0F, 0xFC, 0x1F, 0xF8, 0x3F, + 0xF0, 0x7C, 0xFF, 0xF9, 0xFF, 0xF0, 0x03, 0xE0, 0x07, 0xCF, 0xFC, 0x1F, + 0xF8, 0x3F, 0xF0, 0xFF, 0xFF, 0xFF, 0xFC, 0x07, 0xC0, 0x0F, 0x80, 0x1F, + 0x00, 0xF8, 0x01, 0xF0, 0x1F, 0x00, 0x3E, 0x00, 0x7C, 0x03, 0xFF, 0xFF, + 0xFF, 0xF0, 0x07, 0xF0, 0x7F, 0x3E, 0x03, 0xE0, 0x3E, 0x03, 0xE0, 0x3E, + 0x0F, 0x80, 0xF8, 0x0F, 0x80, 0x3E, 0x03, 0xE0, 0x3E, 0x03, 0xE0, 0x3E, + 0x00, 0x7F, 0x07, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFE, 0x0F, 0xE0, 0x07, 0xC0, 0x7C, + 0x07, 0xC0, 0x7C, 0x07, 0xC0, 0x1F, 0x01, 0xF0, 0x1F, 0x07, 0xC0, 0x7C, + 0x07, 0xC0, 0x7C, 0x07, 0xCF, 0xE0, 0xFE, 0x00, 0x3E, 0x0E, 0x7C, 0x1F, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x3E, 0x30, 0x7C, 0x00 }; + +const GFXglyph FalloutGlyphs[] PROGMEM = { + { 0, 1, 1, 12, 0, 0 }, // 0x20 ' ' + { 1, 5, 17, 7, 0, -16 }, // 0x21 '!' + { 12, 12, 5, 15, 0, -19 }, // 0x22 '"' + { 20, 17, 17, 20, 0, -16 }, // 0x23 '#' + { 57, 15, 17, 17, 0, -16 }, // 0x24 '$' + { 89, 20, 17, 22, 0, -16 }, // 0x25 '%' + { 132, 17, 17, 20, 0, -16 }, // 0x26 '&' + { 169, 5, 5, 7, 0, -19 }, // 0x27 ''' + { 173, 10, 17, 12, 0, -16 }, // 0x28 '(' + { 195, 10, 17, 12, 0, -16 }, // 0x29 ')' + { 217, 17, 13, 20, 0, -14 }, // 0x2A '*' + { 245, 15, 13, 17, 0, -14 }, // 0x2B '+' + { 270, 7, 7, 10, 0, -4 }, // 0x2C ',' + { 277, 15, 3, 17, 0, -9 }, // 0x2D '-' + { 283, 5, 5, 7, 0, -4 }, // 0x2E '.' + { 287, 15, 17, 17, 0, -16 }, // 0x2F '/' + { 319, 15, 17, 17, 0, -16 }, // 0x30 '0' + { 351, 10, 17, 12, 0, -16 }, // 0x31 '1' + { 373, 15, 17, 17, 0, -16 }, // 0x32 '2' + { 405, 15, 17, 17, 0, -16 }, // 0x33 '3' + { 437, 15, 17, 17, 0, -16 }, // 0x34 '4' + { 469, 15, 17, 17, 0, -16 }, // 0x35 '5' + { 501, 15, 17, 17, 0, -16 }, // 0x36 '6' + { 533, 15, 17, 17, 0, -16 }, // 0x37 '7' + { 565, 15, 17, 17, 0, -16 }, // 0x38 '8' + { 597, 15, 17, 17, 0, -16 }, // 0x39 '9' + { 629, 5, 15, 7, 0, -14 }, // 0x3A ':' + { 639, 7, 17, 10, 0, -14 }, // 0x3B ';' + { 654, 12, 17, 15, 0, -16 }, // 0x3C '<' + { 680, 15, 10, 17, 0, -11 }, // 0x3D '=' + { 699, 12, 17, 15, 0, -16 }, // 0x3E '>' + { 725, 15, 17, 17, 0, -16 }, // 0x3F '?' + { 757, 17, 17, 20, 0, -16 }, // 0x40 '@' + { 794, 20, 17, 22, 0, -16 }, // 0x41 'A' + { 837, 17, 17, 20, 0, -16 }, // 0x42 'B' + { 874, 15, 17, 17, 0, -16 }, // 0x43 'C' + { 906, 17, 17, 20, 0, -16 }, // 0x44 'D' + { 943, 15, 17, 17, 0, -16 }, // 0x45 'E' + { 975, 15, 17, 17, 0, -16 }, // 0x46 'F' + { 1007, 17, 17, 20, 0, -16 }, // 0x47 'G' + { 1044, 17, 17, 20, 0, -16 }, // 0x48 'H' + { 1081, 5, 17, 7, 0, -16 }, // 0x49 'I' + { 1092, 17, 17, 20, 0, -16 }, // 0x4A 'J' + { 1129, 17, 17, 20, 0, -16 }, // 0x4B 'K' + { 1166, 15, 17, 17, 0, -16 }, // 0x4C 'L' + { 1198, 17, 17, 20, 0, -16 }, // 0x4D 'M' + { 1235, 17, 17, 20, 0, -16 }, // 0x4E 'N' + { 1272, 17, 17, 20, 0, -16 }, // 0x4F 'O' + { 1309, 17, 17, 20, 0, -16 }, // 0x50 'P' + { 1346, 17, 19, 20, 0, -16 }, // 0x51 'Q' + { 1387, 17, 17, 20, 0, -16 }, // 0x52 'R' + { 1424, 17, 17, 20, 0, -16 }, // 0x53 'S' + { 1461, 15, 17, 17, 0, -16 }, // 0x54 'T' + { 1493, 17, 17, 20, 0, -16 }, // 0x55 'U' + { 1530, 20, 17, 22, 0, -16 }, // 0x56 'V' + { 1573, 17, 17, 20, 0, -16 }, // 0x57 'W' + { 1610, 20, 17, 22, 0, -16 }, // 0x58 'X' + { 1653, 17, 17, 20, 0, -16 }, // 0x59 'Y' + { 1690, 17, 17, 20, 0, -16 }, // 0x5A 'Z' + { 1727, 10, 17, 12, 0, -16 }, // 0x5B '[' + { 1749, 17, 17, 20, 0, -16 }, // 0x5C '\' + { 1786, 10, 17, 12, 0, -16 }, // 0x5D ']' + { 1808, 17, 10, 20, 0, -16 }, // 0x5E '^' + { 1830, 15, 2, 17, 0, -1 }, // 0x5F '_' + { 1834, 7, 7, 10, 0, -16 }, // 0x60 '`' + { 1841, 15, 12, 17, 0, -11 }, // 0x61 'a' + { 1864, 15, 17, 17, 0, -16 }, // 0x62 'b' + { 1896, 12, 12, 15, 0, -11 }, // 0x63 'c' + { 1914, 15, 17, 17, 0, -16 }, // 0x64 'd' + { 1946, 15, 12, 17, 0, -11 }, // 0x65 'e' + { 1969, 12, 17, 15, 0, -16 }, // 0x66 'f' + { 1995, 15, 17, 17, 0, -11 }, // 0x67 'g' + { 2027, 15, 17, 17, 0, -16 }, // 0x68 'h' + { 2059, 5, 12, 7, 0, -11 }, // 0x69 'i' + { 2067, 12, 17, 15, 0, -11 }, // 0x6A 'j' + { 2093, 15, 17, 17, 0, -16 }, // 0x6B 'k' + { 2125, 5, 17, 7, 0, -16 }, // 0x6C 'l' + { 2136, 17, 12, 20, 0, -11 }, // 0x6D 'm' + { 2162, 15, 12, 17, 0, -11 }, // 0x6E 'n' + { 2185, 15, 12, 17, 0, -11 }, // 0x6F 'o' + { 2208, 15, 17, 17, 0, -11 }, // 0x70 'p' + { 2240, 15, 17, 17, 0, -11 }, // 0x71 'q' + { 2272, 12, 12, 15, 0, -11 }, // 0x72 'r' + { 2290, 15, 12, 17, 0, -11 }, // 0x73 's' + { 2313, 15, 17, 17, 0, -16 }, // 0x74 't' + { 2345, 15, 12, 17, 0, -11 }, // 0x75 'u' + { 2368, 17, 12, 20, 0, -11 }, // 0x76 'v' + { 2394, 17, 12, 20, 0, -11 }, // 0x77 'w' + { 2420, 15, 12, 17, 0, -11 }, // 0x78 'x' + { 2443, 15, 17, 17, 0, -11 }, // 0x79 'y' + { 2475, 15, 12, 17, 0, -11 }, // 0x7A 'z' + { 2498, 12, 17, 15, 0, -16 }, // 0x7B '{' + { 2524, 5, 22, 7, 0, -19 }, // 0x7C '|' + { 2538, 12, 17, 15, 0, -16 }, // 0x7D '}' + { 2564, 15, 7, 17, 0, -11 } }; // 0x7E '~' + +const GFXfont Fallout__1_20pt7b PROGMEM = { + (uint8_t *)Fallout__1_20pt7bBitmaps, + (GFXglyph *)Fallout__1_20pt7bGlyphs, + 0x20, 0x7E, 38 }; + +// Approx. 3250 bytes diff --git a/lib/MatrixUI/MatrixDisplayUi.cpp b/lib/MatrixUI/MatrixDisplayUi.cpp index 473a81e..e159bd9 100644 --- a/lib/MatrixUI/MatrixDisplayUi.cpp +++ b/lib/MatrixUI/MatrixDisplayUi.cpp @@ -28,7 +28,7 @@ */ #include "MatrixDisplayUi.h" -#include "AwtrixFont.h" +#include "Fonts/AwtrixFont.h" MatrixDisplayUi::MatrixDisplayUi(FastLED_NeoMatrix *matrix) { diff --git a/lib/webserver/src/esp-fs-webserver.cpp b/lib/webserver/src/esp-fs-webserver.cpp index a486589..00cd534 100644 --- a/lib/webserver/src/esp-fs-webserver.cpp +++ b/lib/webserver/src/esp-fs-webserver.cpp @@ -29,6 +29,11 @@ void FSWebServer::addHandler(const Uri &uri, WebServerClass::THandlerFunction ha webserver->on(uri, HTTP_ANY, handler); } +void FSWebServer::onNotFound(WebServerClass::THandlerFunction handler) +{ + webserver->onNotFound(handler); +} + // List all files saved in the selected filesystem bool FSWebServer::checkDir(char *dirname, uint8_t levels) { @@ -80,7 +85,7 @@ bool FSWebServer::begin(const char *path) webserver->on("/edit", HTTP_PUT, std::bind(&FSWebServer::handleFileCreate, this)); webserver->on("/edit", HTTP_DELETE, std::bind(&FSWebServer::handleFileDelete, this)); #endif - webserver->onNotFound(std::bind(&FSWebServer::handleRequest, this)); + //webserver->onNotFound(std::bind(&FSWebServer::handleRequest, this)); webserver->on("/favicon.ico", HTTP_GET, std::bind(&FSWebServer::replyOK, this)); webserver->on("/", HTTP_GET, std::bind(&FSWebServer::handleIndex, this)); #ifdef INCLUDE_SETUP_HTM @@ -153,7 +158,6 @@ IPAddress FSWebServer::startWiFi(uint32_t timeout, const char *apSSID, const cha #elif defined(ESP32) wifi_config_t conf; esp_wifi_get_config(WIFI_IF_STA, &conf); - _ssid = reinterpret_cast(conf.sta.ssid); _pass = reinterpret_cast(conf.sta.password); #endif diff --git a/lib/webserver/src/esp-fs-webserver.h b/lib/webserver/src/esp-fs-webserver.h index db092e8..88aab4f 100644 --- a/lib/webserver/src/esp-fs-webserver.h +++ b/lib/webserver/src/esp-fs-webserver.h @@ -86,6 +86,7 @@ public: void addHandler(const Uri &uri, HTTPMethod method, WebServerClass::THandlerFunction fn); void addHandler(const Uri &uri, WebServerClass::THandlerFunction handler); + void onNotFound(WebServerClass::THandlerFunction handler); void setCaptiveWebage(const char *url); diff --git a/src/Apps.h b/src/Apps.h index 24fa508..7a17af7 100644 --- a/src/Apps.h +++ b/src/Apps.h @@ -620,6 +620,9 @@ void NotifyApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state) DisplayManager.getInstance().resetTextColor(); } + +//Unattractive to have a function for every customapp wich does the same, but currently still no other option found TODO + void CApp1(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp) { String name = getAppNameByFunction(CApp1); @@ -680,6 +683,66 @@ void CApp10(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, i ShowCustomApp(name, matrix, state, x, y, firstApp, lastApp); } +void CApp11(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp) +{ + String name = getAppNameByFunction(CApp11); + ShowCustomApp(name, matrix, state, x, y, firstApp, lastApp); +} + +void CApp12(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp) +{ + String name = getAppNameByFunction(CApp12); + ShowCustomApp(name, matrix, state, x, y, firstApp, lastApp); +} + +void CApp13(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp) +{ + String name = getAppNameByFunction(CApp13); + ShowCustomApp(name, matrix, state, x, y, firstApp, lastApp); +} + +void CApp14(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp) +{ + String name = getAppNameByFunction(CApp14); + ShowCustomApp(name, matrix, state, x, y, firstApp, lastApp); +} + +void CApp15(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp) +{ + String name = getAppNameByFunction(CApp15); + ShowCustomApp(name, matrix, state, x, y, firstApp, lastApp); +} + +void CApp16(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp) +{ + String name = getAppNameByFunction(CApp16); + ShowCustomApp(name, matrix, state, x, y, firstApp, lastApp); +} + +void CApp17(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp) +{ + String name = getAppNameByFunction(CApp17); + ShowCustomApp(name, matrix, state, x, y, firstApp, lastApp); +} + +void CApp18(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp) +{ + String name = getAppNameByFunction(CApp18); + ShowCustomApp(name, matrix, state, x, y, firstApp, lastApp); +} + +void CApp19(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp) +{ + String name = getAppNameByFunction(CApp19); + ShowCustomApp(name, matrix, state, x, y, firstApp, lastApp); +} + +void CApp20(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp) +{ + String name = getAppNameByFunction(CApp20); + ShowCustomApp(name, matrix, state, x, y, firstApp, lastApp); +} + const uint16_t *getWeatherIcon(int code) { switch (code) diff --git a/src/DisplayManager.cpp b/src/DisplayManager.cpp index 93e2092..d6e2ebb 100644 --- a/src/DisplayManager.cpp +++ b/src/DisplayManager.cpp @@ -13,6 +13,7 @@ #include "ServerManager.h" #include "MenuManager.h" #include "Apps.h" +#include "Dictionary.h" Ticker AlarmTicker; Ticker TimerTicker; @@ -214,7 +215,7 @@ void pushCustomApp(String name, int position) if (customApps.count(name) == 0) { ++customPagesCount; - void (*customApps[10])(FastLED_NeoMatrix *, MatrixDisplayUiState *, int16_t, int16_t, bool, bool) = {CApp1, CApp2, CApp3, CApp4, CApp5, CApp6, CApp7, CApp8, CApp9, CApp10}; + void (*customApps[20])(FastLED_NeoMatrix *, MatrixDisplayUiState *, int16_t, int16_t, bool, bool) = {CApp1, CApp2, CApp3, CApp4, CApp5, CApp6, CApp7, CApp8, CApp9, CApp10, CApp11, CApp12, CApp13, CApp14, CApp15, CApp16, CApp17, CApp18, CApp19, CApp20}; if (position < 0) // Insert at the end of the vector { @@ -230,6 +231,7 @@ void pushCustomApp(String name, int position) } ui.setApps(Apps); // Add Apps + DisplayManager.getInstance().setAutoTransition(true); } } @@ -714,4 +716,146 @@ void DisplayManager_::drawBarChart(int16_t x, int16_t y, const int data[], byte int y1 = min(8 - barHeight, 7); matrix.fillRect(x1, y1 + y, barWidth, barHeight, color); } -} \ No newline at end of file +} + +void DisplayManager_::updateAppVector(const char *json) +{ + // Parse the JSON input + DynamicJsonDocument doc(1024); + auto error = deserializeJson(doc, json); + if (error) + { + // If parsing fails, print an error message and return + Serial.print("Failed to parse JSON: "); + Serial.println(error.c_str()); + return; + } + + // Create new vectors to store updated apps + std::vector> newApps; + std::vector activeApps; + + // Loop through all apps in the JSON input + for (const auto &app : doc.as()) + { + // Get the app name, active status, and position (if specified) + String name = app["name"].as(); + bool show = true; + int position = -1; + + if (app.containsKey("show")) + { + show = app["show"].as(); + } + if (app.containsKey("pos")) + { + position = app["pos"].as(); + } + + // Find the corresponding AppCallback function based on the app name + AppCallback callback; + if (name == "time") + { + callback = TimeApp; + SHOW_TIME = show; + } + else if (name == "date") + { + callback = DateApp; + SHOW_DATE = show; + } + else if (name == "temp") + { + callback = TempApp; + SHOW_TEMP = show; + } + else if (name == "hum") + { + callback = HumApp; + SHOW_HUM = show; + } + else if (name == "bat") + { + callback = BatApp; + SHOW_BAT = show; + } + else + { + // If the app is not one of the built-in apps, check if it's already in the vector + int appIndex = findAppIndexByName(name); + if (appIndex >= 0) + { + // The app is in the vector, so we can move it to a new position or remove it + auto it = Apps.begin() + appIndex; + if (show) + { + if (position >= 0 && static_cast(position) < newApps.size()) + { + Apps.erase(it); + newApps.insert(newApps.begin() + position, std::make_pair(name, it->second)); + } + } + else + { + // If the app is being removed, also remove it from the customApps map + if (customApps.count(name)) + { + customApps.erase(customApps.find(name)); + removeCustomApp(name); + } + } + } + continue; + } + if (show) + { + // Add the app to the new vector + if (position >= 0 && static_cast(position) < newApps.size()) + { + newApps.insert(newApps.begin() + position, std::make_pair(name, callback)); + } + else + { + newApps.emplace_back(name, callback); + } + } + + activeApps.push_back(name); + } + + // Loop through all apps currently in the vector + for (const auto &app : Apps) + { + // If the app is not in the updated activeApps vector, add it to the newApps vector + if (std::find(activeApps.begin(), activeApps.end(), app.first) == activeApps.end()) + { + newApps.push_back(app); + } + } + + // Update the apps vector, set it in the UI, and save settings + Apps = std::move(newApps); + ui.setApps(Apps); + saveSettings(); +} + +String DisplayManager_::getStat() +{ + StaticJsonDocument<200> doc; + char buffer[5]; + doc[BatKey] = BATTERY_PERCENT; + doc[BatRawKey] = BATTERY_RAW; + snprintf(buffer, 5, "%.0f", CURRENT_LUX); + doc[LuxKey] = buffer; + doc[LDRRawKey] = LDR_RAW; + doc[BrightnessKey] = BRIGHTNESS; + snprintf(buffer, 5, "%.0f", CURRENT_TEMP); + doc[TempKey] = buffer; + snprintf(buffer, 5, "%.0f", CURRENT_HUM); + doc[HumKey] = buffer; + doc[UpTimeKey] = PeripheryManager.readUptime(); + doc[SignalStrengthKey] = WiFi.RSSI(); + String jsonString; + serializeJson(doc, jsonString); + return jsonString; +} diff --git a/src/DisplayManager.h b/src/DisplayManager.h index ce8714d..b8162d6 100644 --- a/src/DisplayManager.h +++ b/src/DisplayManager.h @@ -56,7 +56,9 @@ public: void drawProgressBar(int cur, int total); void drawMenuIndicator(int cur, int total, uint16_t color); void drawBMP(int16_t x, int16_t y, const uint16_t bitmap[], int16_t w, int16_t h); - void drawBarChart(int16_t x, int16_t y,const int data[], byte dataSize, bool withIcon, uint16_t color); + void drawBarChart(int16_t x, int16_t y, const int data[], byte dataSize, bool withIcon, uint16_t color); + void updateAppVector(const char *json); + String getStat(); }; extern DisplayManager_ &DisplayManager; diff --git a/src/Globals.cpp b/src/Globals.cpp index b86fc02..7307162 100644 --- a/src/Globals.cpp +++ b/src/Globals.cpp @@ -1,6 +1,8 @@ #include "Globals.h" #include "Preferences.h" #include +#include +#include Preferences Settings; @@ -13,8 +15,48 @@ char *getID() return macStr; } +void startLittleFS() +{ + if (LittleFS.begin()) + { + LittleFS.mkdir("/MELODIES"); + LittleFS.mkdir("/ICONS"); + } + else + { + Serial.println("ERROR on mounting LittleFS. It will be formmatted!"); + LittleFS.format(); + ESP.restart(); + } +} + +void loadDevSettings() +{ + Serial.println("laodSettings"); + File file = LittleFS.open("/dev.json", "r"); + if (!file) + { + return; + } + DynamicJsonDocument doc(128); + DeserializationError error = deserializeJson(doc, file); + if (error) + { + Serial.println(F("Failed to read dev settings")); + return; + } + + if (doc.containsKey("bootsound")) + { + BOOT_SOUND = doc["bootsound"].as(); + } + + file.close(); +} + void loadSettings() { + startLittleFS(); Settings.begin("awtrix", false); MATRIX_FPS = Settings.getUChar("FPS", 23); BRIGHTNESS = Settings.getUChar("BRI", 120); @@ -32,9 +74,11 @@ void loadSettings() SHOW_TEMP = Settings.getBool("TEMP", true); SHOW_HUM = Settings.getBool("HUM", true); SHOW_BAT = Settings.getBool("BAT", true); + SOUND_ACTIVE = Settings.getBool("SOUND", true); Settings.end(); uniqueID = getID(); MQTT_PREFIX = String(uniqueID); + loadDevSettings(); } void saveSettings() @@ -56,6 +100,7 @@ void saveSettings() Settings.putBool("TEMP", SHOW_TEMP); Settings.putBool("HUM", SHOW_HUM); Settings.putBool("BAT", SHOW_BAT); + Settings.putBool("SOUND", SOUND_ACTIVE); Settings.end(); } @@ -122,4 +167,6 @@ bool AP_MODE; bool MATRIX_OFF; bool TIMER_ACTIVE; bool ALARM_ACTIVE; -uint16_t TEXTCOLOR_565 = 0xFFFF; \ No newline at end of file +uint16_t TEXTCOLOR_565 = 0xFFFF; +bool SOUND_ACTIVE; +String BOOT_SOUND = ""; \ No newline at end of file diff --git a/src/Globals.h b/src/Globals.h index 66f59f5..864d2a5 100644 --- a/src/Globals.h +++ b/src/Globals.h @@ -62,7 +62,8 @@ extern String TIME_FORMAT; extern String DATE_FORMAT; extern bool START_ON_MONDAY; extern bool IS_CELSIUS; - +extern bool SOUND_ACTIVE; +extern String BOOT_SOUND; void loadSettings(); void saveSettings(); #endif // Globals_H \ No newline at end of file diff --git a/src/MQTTManager.cpp b/src/MQTTManager.cpp index 3c81717..3b83101 100644 --- a/src/MQTTManager.cpp +++ b/src/MQTTManager.cpp @@ -6,8 +6,7 @@ #include #include #include "Dictionary.h" - -unsigned long startTime; +#include "PeripheryManager.h" WiFiClient espClient; uint8_t lastBrightness; @@ -193,16 +192,24 @@ void onMqttMessage(const char *topic, const uint8_t *payload, uint16_t length) void onMqttConnected() { String prefix = MQTT_PREFIX; - mqtt.subscribe((prefix + String("/brightness")).c_str()); - mqtt.subscribe((prefix + String("/notify/dismiss")).c_str()); - mqtt.subscribe((prefix + String("/notify")).c_str()); - mqtt.subscribe((prefix + String("/timer")).c_str()); - mqtt.subscribe((prefix + String("/custom/#")).c_str()); - mqtt.subscribe((prefix + String("/switch")).c_str()); - mqtt.subscribe((prefix + String("/settings")).c_str()); - mqtt.subscribe((prefix + String("/previousapp")).c_str()); - mqtt.subscribe((prefix + String("/nextapp")).c_str()); - Serial.println("MQTT Connected"); + const char *topics[] PROGMEM = { + "/brightness", + "/notify/dismiss", + "/notify", + "/timer", + "/custom/#", + "/switch", + "/settings", + "/previousapp", + "/nextapp", + "/nextapp", + "/apps"}; + for (const char *topic : topics) + { + String fullTopic = prefix + topic; + mqtt.subscribe(fullTopic.c_str()); + } + Serial.println(F("MQTT Connected")); } void connect() @@ -227,7 +234,7 @@ char btnAID[40], btnBID[40], btnCID[40], appID[40], tempID[40], humID[40], luxID void MQTTManager_::setup() { - startTime = millis(); + if (HA_DISCOVERY) { Serial.println(F("Starting Homeassistant discorvery")); @@ -242,6 +249,9 @@ void MQTTManager_::setup() device.setManufacturer(HAmanufacturer); device.setModel(HAmodel); device.setAvailability(true); + device.enableSharedAvailability(); + device.enableLastWill(); + String uniqueIDWithSuffix; @@ -396,22 +406,6 @@ void MQTTManager_::setCurrentApp(String value) curApp->setValue(value.c_str()); } -const char *readUptime() -{ - static char uptime[25]; // Make the array static to keep it from being destroyed when the function returns - unsigned long currentTime = millis(); - unsigned long elapsedTime = currentTime - startTime; - unsigned long uptimeSeconds = elapsedTime / 1000; - unsigned long uptimeMinutes = uptimeSeconds / 60; - unsigned long uptimeHours = uptimeMinutes / 60; - unsigned long uptimeDays = uptimeHours / 24; - unsigned long hours = uptimeHours % 24; - unsigned long minutes = uptimeMinutes % 60; - unsigned long seconds = uptimeSeconds % 60; - sprintf(uptime, "P%dDT%dH%dM%dS", uptimeDays, hours, minutes, seconds); - return uptime; -} - void MQTTManager_::sendStats() { if (HA_DISCOVERY) @@ -442,7 +436,7 @@ void MQTTManager_::sendStats() int freeHeapBytes = ESP.getFreeHeap(); itoa(freeHeapBytes, rambuffer, 10); ram->setValue(rambuffer); - uptime->setValue(readUptime()); + uptime->setValue(PeripheryManager.readUptime()); version->setValue(VERSION); transition->setState(AUTO_TRANSITION, false); } @@ -450,23 +444,7 @@ void MQTTManager_::sendStats() { } - StaticJsonDocument<200> doc; - char buffer[5]; - doc[BatKey] = BATTERY_PERCENT; - doc[BatRawKey] = BATTERY_RAW; - snprintf(buffer, 5, "%.0f", CURRENT_LUX); - doc[LuxKey] = buffer; - doc[LDRRawKey] = LDR_RAW; - doc[BrightnessKey] = BRIGHTNESS; - snprintf(buffer, 5, "%.0f", CURRENT_TEMP); - doc[TempKey] = buffer; - snprintf(buffer, 5, "%.0f", CURRENT_HUM); - doc[HumKey] = buffer; - doc[UpTimeKey] = readUptime(); - doc[SignalStrengthKey] = WiFi.RSSI(); - String jsonString; - serializeJson(doc, jsonString); - publish(StatsTopic, jsonString.c_str()); + publish(StatsTopic, DisplayManager.getStat().c_str()); } void MQTTManager_::sendButton(byte btn, bool state) diff --git a/src/MenuManager.cpp b/src/MenuManager.cpp index 798f98e..c047217 100644 --- a/src/MenuManager.cpp +++ b/src/MenuManager.cpp @@ -26,6 +26,7 @@ enum MenuState WeekdayMenu, TempMenu, Appmenu, + SoundMenu }; const char *menuItems[] PROGMEM = { @@ -40,10 +41,11 @@ const char *menuItems[] PROGMEM = { "WEEKDAY", "TEMP", "APPS", + "SOUND", "UPDATE"}; int8_t menuIndex = 0; -uint8_t menuItemCount = 12; +uint8_t menuItemCount = 13; const char *timeFormat[] PROGMEM = { "%H:%M:%S", @@ -71,13 +73,6 @@ const char *dateFormat[] PROGMEM = { int8_t dateFormatIndex; uint8_t dateFormatCount = 9; -const char *appsItems[][2] PROGMEM = { - {"13", "time"}, - {"1158", "date"}, - {"234", "temp"}, - {"2075", "hum"}, - {"1486", "bat"}}; - int8_t appsIndex; uint8_t appsCount = 5; @@ -129,6 +124,8 @@ String MenuManager_::menutext() return "0x" + String(textColors[currentColor], HEX); case SwitchMenu: return AUTO_TRANSITION ? "ON" : "OFF"; + case SoundMenu: + return SOUND_ACTIVE ? "ON" : "OFF"; case TspeedMenu: return String(TIME_PER_TRANSITION / 1000.0, 1) + "s"; case AppTimeMenu: @@ -231,6 +228,9 @@ void MenuManager_::rightButton() case WeekdayMenu: START_ON_MONDAY = !START_ON_MONDAY; break; + case SoundMenu: + SOUND_ACTIVE = !SOUND_ACTIVE; + break; case TempMenu: IS_CELSIUS = !IS_CELSIUS; break; @@ -291,6 +291,9 @@ void MenuManager_::leftButton() case TempMenu: IS_CELSIUS = !IS_CELSIUS; break; + case SoundMenu: + SOUND_ACTIVE = !SOUND_ACTIVE; + break; default: break; } @@ -342,6 +345,9 @@ void MenuManager_::selectButton() currentState = Appmenu; break; case 11: + currentState = SoundMenu; + break; + case 12: if (FirmwareVersionCheck()) { updateFirmware(); @@ -424,6 +430,7 @@ void MenuManager_::selectButtonLong() DATE_FORMAT = dateFormat[dateFormatIndex]; saveSettings(); case WeekdayMenu: + case SoundMenu: case TempMenu: saveSettings(); break; diff --git a/src/PeripheryManager.cpp b/src/PeripheryManager.cpp index f7a183a..e3be9b1 100644 --- a/src/PeripheryManager.cpp +++ b/src/PeripheryManager.cpp @@ -9,8 +9,6 @@ #include #include -#define SOUND_OFF true - #ifdef ULANZI // Pinouts für das ULANZI-Environment #define BATTERY_PIN 34 @@ -50,6 +48,7 @@ unsigned long previousMillis_LDR = 0; const unsigned long interval_BatTempHum = 10000; const unsigned long interval_LDR = 100; int total = 0; +unsigned long startTime; const int LDRReadings = 10; int TotalLDRReadings[LDRReadings]; @@ -105,13 +104,21 @@ void select_button_tripple() void PeripheryManager_::playBootSound() { - if (SOUND_OFF) + if (!SOUND_ACTIVE) return; - const int nNotes = 6; - String notes[nNotes] = {"E5", "C5", "G4", "E4", "G4", "C5"}; - const int timeUnit = 150; - Melody melody = MelodyFactory.load("Nice Melody", timeUnit, notes, nNotes); - player.playAsync(melody); + if (BOOT_SOUND == "") + { + const int nNotes = 6; + String notes[nNotes] = {"E5", "C5", "G4", "E4", "G4", "C5"}; + const int timeUnit = 150; + Melody melody = MelodyFactory.load("Bootsound", timeUnit, notes, nNotes); + player.playAsync(melody); + } + else + + { + playFromFile("/MELODIES/" + BOOT_SOUND + ".txt"); + } } void PeripheryManager_::stopSound() @@ -121,7 +128,7 @@ void PeripheryManager_::stopSound() void PeripheryManager_::playFromFile(String file) { - if (SOUND_OFF) + if (!SOUND_ACTIVE) return; Melody melody = MelodyFactory.loadRtttlFile(file); player.playAsync(melody); @@ -148,6 +155,7 @@ void fistStart() void PeripheryManager_::setup() { + startTime = millis(); pinMode(LDR_PIN, INPUT); pinMode(BUZZER_PIN, OUTPUT); digitalWrite(BUZZER_PIN, LOW); @@ -274,3 +282,20 @@ void PeripheryManager_::checkAlarms() } } } + + +const char *PeripheryManager_::readUptime() +{ + static char uptime[25]; // Make the array static to keep it from being destroyed when the function returns + unsigned long currentTime = millis(); + unsigned long elapsedTime = currentTime - startTime; + unsigned long uptimeSeconds = elapsedTime / 1000; + unsigned long uptimeMinutes = uptimeSeconds / 60; + unsigned long uptimeHours = uptimeMinutes / 60; + unsigned long uptimeDays = uptimeHours / 24; + unsigned long hours = uptimeHours % 24; + unsigned long minutes = uptimeMinutes % 60; + unsigned long seconds = uptimeSeconds % 60; + sprintf(uptime, "P%dDT%dH%dM%dS", uptimeDays, hours, minutes, seconds); + return uptime; +} \ No newline at end of file diff --git a/src/PeripheryManager.h b/src/PeripheryManager.h index 5f180ee..928ec46 100644 --- a/src/PeripheryManager.h +++ b/src/PeripheryManager.h @@ -29,6 +29,7 @@ public: void playFromFile(String file); bool isPlaying(); void stopSound(); + const char *readUptime(); }; extern PeripheryManager_ &PeripheryManager; diff --git a/src/ServerManager.cpp b/src/ServerManager.cpp index f676a5a..3f24a54 100644 --- a/src/ServerManager.cpp +++ b/src/ServerManager.cpp @@ -13,22 +13,6 @@ WebServer server(80); FSWebServer mws(LittleFS, server); bool FSOPEN; -void startLittleFS() -{ - - if (LittleFS.begin()) - { - LittleFS.mkdir("/MELODIES"); - LittleFS.mkdir("/ICONS"); - FSOPEN = true; - } - else - { - Serial.println("ERROR on mounting LittleFS. It will be formmatted!"); - LittleFS.format(); - ESP.restart(); - } -} // The getter for the instantiated singleton instance ServerManager_ &ServerManager_::getInstance() @@ -49,14 +33,90 @@ void versionHandler() void saveHandler() { WebServerClass *webRequest = mws.getRequest(); - Serial.println("Save"); ServerManager.getInstance().loadSettings(); webRequest->send(200); } +void handlePostRequest() +{ + WebServerClass *webRequest = mws.getRequest(); + String url = webRequest->uri(); + url.replace("/api", ""); + if (webRequest->method() == HTTP_POST) + { + String body = webRequest->arg("plain"); + const char *bodyPtr = body.c_str(); + webRequest->send(200); + if (url == "/notify") + { + if (body[0] != '{' || body[strlen(bodyPtr) - 1] != '}') + { + webRequest->send(400, "text/plain", "Invalid payload format"); + return; + } + DisplayManager.generateNotification(bodyPtr); + } + + else if (url == "/timer") + { + DisplayManager.gererateTimer(bodyPtr); + } + + else if (url == "/notify/dismiss") + { + DisplayManager.dismissNotify(); + } + + else if (url == "/apps") + { + DisplayManager.updateAppVector(bodyPtr); + } + + else if (url == "/switch") + { + DisplayManager.switchToApp(bodyPtr); + } + + else if (url == "/settings") + { + DisplayManager.setNewSettings(bodyPtr); + } + + else if (url == "/nextapp") + { + DisplayManager.nextApp(); + } + + else if (url == "/previousapp") + { + DisplayManager.previousApp(); + } + + else if (url.startsWith("/custom")) + { + String topic_str = url.substring(MQTT_PREFIX.length() + 7); + DisplayManager.generateCustomPage(topic_str, bodyPtr); + } + else + { + webRequest->send(400); + } + } + else if (webRequest->method() == HTTP_GET) + { + if (url == "/stats") + { + webRequest->sendContent(DisplayManager.getStat()); + } + else + { + webRequest->send(400); + } + } +} + void ServerManager_::setup() { - if (!local_IP.fromString(NET_IP) || !gateway.fromString(NET_GW) || !subnet.fromString(NET_SN) || !primaryDNS.fromString(NET_PDNS) || !secondaryDNS.fromString(NET_SDNS)) NET_STATIC = false; if (NET_STATIC) @@ -69,6 +129,7 @@ void ServerManager_::setup() if (isConnected) { + mws.onNotFound(handlePostRequest); mws.addOptionBox("Network"); mws.addOption("Static IP", NET_STATIC); mws.addOption("Local IP", NET_IP); @@ -96,7 +157,6 @@ void ServerManager_::setup() mws.addHandler("/save", HTTP_GET, saveHandler); } - mws.addHandler("/version", HTTP_GET, versionHandler); mws.begin(); if (!MDNS.begin(uniqueID)) @@ -129,12 +189,10 @@ uint16_t stringToColor(const String &str) String gStr = str.substring(comma1 + 1, comma2); String bStr = str.substring(comma2 + 1); - int r = rStr.toInt(); int g = gStr.toInt(); int b = bStr.toInt(); - if (r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255) { return 0xFFFF; @@ -164,9 +222,6 @@ String colorToString(uint16_t color) void ServerManager_::loadSettings() { - if (!FSOPEN) - startLittleFS(); - if (LittleFS.exists("/config.json")) { File file = LittleFS.open("/config.json", "r"); diff --git a/src/ServerManager.h b/src/ServerManager.h index 0951221..5c898fe 100644 --- a/src/ServerManager.h +++ b/src/ServerManager.h @@ -14,7 +14,6 @@ public: void tick(); void loadSettings(); bool isConnected; - void SaveSettings(); }; extern ServerManager_ &ServerManager; From 055d54d099802c8dff4b8a1a5264ac04969afc2e Mon Sep 17 00:00:00 2001 From: Elfish Date: Fri, 31 Mar 2023 15:12:13 +0200 Subject: [PATCH 2/7] Split code between ulanzi environment and awtrix_upgrade Added BME280 sensor support for awtrix_upgrade. Removed battery readings for awtrix_upgrade Added DFMiniMp3 lib for replacing the Ulanzi buzzer in the future --- .../.gitattributes | 17 + .../.github/FUNDING.yml | 2 + lib/DFMiniMp3-1.0.7-noChecksums/.gitignore | 79 +++ lib/DFMiniMp3-1.0.7-noChecksums/COPYING | 165 ++++++ lib/DFMiniMp3-1.0.7-noChecksums/README.md | 25 + .../PlayAdvertisements/PlayAdvertisements.ino | 105 ++++ .../examples/PlayMp3/PlayMp3.ino | 121 ++++ .../examples/PlayRandom/PlayRandom.ino | 100 ++++ lib/DFMiniMp3-1.0.7-noChecksums/keywords.txt | 79 +++ .../library.properties | 9 + .../src/DFMiniMp3.h | 559 ++++++++++++++++++ platformio.ini | 2 +- src/Apps.h | 2 + src/Dictionary.h | 2 + src/DisplayManager.cpp | 4 + src/DisplayManager.h | 2 + src/Globals.cpp | 8 + src/Globals.h | 4 + src/MQTTManager.cpp | 13 +- src/MenuManager.cpp | 9 + src/PeripheryManager.cpp | 23 +- src/PeripheryManager.h | 6 + 22 files changed, 1331 insertions(+), 5 deletions(-) create mode 100644 lib/DFMiniMp3-1.0.7-noChecksums/.gitattributes create mode 100644 lib/DFMiniMp3-1.0.7-noChecksums/.github/FUNDING.yml create mode 100644 lib/DFMiniMp3-1.0.7-noChecksums/.gitignore create mode 100644 lib/DFMiniMp3-1.0.7-noChecksums/COPYING create mode 100644 lib/DFMiniMp3-1.0.7-noChecksums/README.md create mode 100644 lib/DFMiniMp3-1.0.7-noChecksums/examples/PlayAdvertisements/PlayAdvertisements.ino create mode 100644 lib/DFMiniMp3-1.0.7-noChecksums/examples/PlayMp3/PlayMp3.ino create mode 100644 lib/DFMiniMp3-1.0.7-noChecksums/examples/PlayRandom/PlayRandom.ino create mode 100644 lib/DFMiniMp3-1.0.7-noChecksums/keywords.txt create mode 100644 lib/DFMiniMp3-1.0.7-noChecksums/library.properties create mode 100644 lib/DFMiniMp3-1.0.7-noChecksums/src/DFMiniMp3.h diff --git a/lib/DFMiniMp3-1.0.7-noChecksums/.gitattributes b/lib/DFMiniMp3-1.0.7-noChecksums/.gitattributes new file mode 100644 index 0000000..bdb0cab --- /dev/null +++ b/lib/DFMiniMp3-1.0.7-noChecksums/.gitattributes @@ -0,0 +1,17 @@ +# Auto detect text files and perform LF normalization +* text=auto + +# Custom for Visual Studio +*.cs diff=csharp + +# Standard to msysgit +*.doc diff=astextplain +*.DOC diff=astextplain +*.docx diff=astextplain +*.DOCX diff=astextplain +*.dot diff=astextplain +*.DOT diff=astextplain +*.pdf diff=astextplain +*.PDF diff=astextplain +*.rtf diff=astextplain +*.RTF diff=astextplain diff --git a/lib/DFMiniMp3-1.0.7-noChecksums/.github/FUNDING.yml b/lib/DFMiniMp3-1.0.7-noChecksums/.github/FUNDING.yml new file mode 100644 index 0000000..9bcf96a --- /dev/null +++ b/lib/DFMiniMp3-1.0.7-noChecksums/.github/FUNDING.yml @@ -0,0 +1,2 @@ +github: [makuna] +custom: ["https://paypal.me/MakunaGithub"] diff --git a/lib/DFMiniMp3-1.0.7-noChecksums/.gitignore b/lib/DFMiniMp3-1.0.7-noChecksums/.gitignore new file mode 100644 index 0000000..f8afdc7 --- /dev/null +++ b/lib/DFMiniMp3-1.0.7-noChecksums/.gitignore @@ -0,0 +1,79 @@ +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app + +# ========================= +# Operating System Files +# ========================= + +# OSX +# ========================= + +.DS_Store +.AppleDouble +.LSOverride + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +# Windows +# ========================= + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msm +*.msp + +# Windows shortcuts +*.lnk diff --git a/lib/DFMiniMp3-1.0.7-noChecksums/COPYING b/lib/DFMiniMp3-1.0.7-noChecksums/COPYING new file mode 100644 index 0000000..02bbb60 --- /dev/null +++ b/lib/DFMiniMp3-1.0.7-noChecksums/COPYING @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. \ No newline at end of file diff --git a/lib/DFMiniMp3-1.0.7-noChecksums/README.md b/lib/DFMiniMp3-1.0.7-noChecksums/README.md new file mode 100644 index 0000000..fcdfba6 --- /dev/null +++ b/lib/DFMiniMp3-1.0.7-noChecksums/README.md @@ -0,0 +1,25 @@ +# DFPlayer Mini mp3 + +[![Join the chat at https://gitter.im/DFMiniMp3/Lobby](https://badges.gitter.im/DFMiniMp3/Lobby.svg)](https://gitter.im/DFMiniMp3/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + +[![Donate](https://img.shields.io/badge/paypal-donate-yellow.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=6AA97KE54UJR4) + +Library for the DFPlayer Mini Mp3 module + +This library allows your Arduino project to control the DFPlayer Mini MP3 module. It supports both hardware serial and software serial. It was designed to fit in the smallest Arduino hardware by consuming less code and memory space than other libraries. + +Please read the product link before connecting your module, it will save you alot of time and effort. +[DFRobot's DFPlayer Mini Mp3](http://www.dfrobot.com/wiki/index.php/DFPlayer_Mini_SKU:DFR0299) + +## Documentation +[See Wiki](https://github.com/Makuna/DFMiniMp3/wiki) + +## Installing This Library (prefered, you just want to use it) +Open the Library Manager and search for "DFPlayer Mini Mp3 by Makuna" and install. + +## Installing This Library From GitHub (advanced, you want to contribute) +Create a directory in your Arduino\Library folder named "DfMiniMp3" +Clone (Git) this project into that folder. +It should now show up in the import list when you restart Arduino IDE. + + diff --git a/lib/DFMiniMp3-1.0.7-noChecksums/examples/PlayAdvertisements/PlayAdvertisements.ino b/lib/DFMiniMp3-1.0.7-noChecksums/examples/PlayAdvertisements/PlayAdvertisements.ino new file mode 100644 index 0000000..fa34f12 --- /dev/null +++ b/lib/DFMiniMp3-1.0.7-noChecksums/examples/PlayAdvertisements/PlayAdvertisements.ino @@ -0,0 +1,105 @@ +// this example will play a track and then every 60 seconds +// it will play an advertisement +// +// it expects the sd card to contain the following mp3 files +// but doesn't care whats in them +// +// sd:/01/001.mp3 - the song to play, the longer the better +// sd:/advert/0001.mp3 - the advertisement to interrupt the song, keep it short + +#include +#include + +// implement a notification class, +// its member methods will get called +// +class Mp3Notify +{ +public: + static void PrintlnSourceAction(DfMp3_PlaySources source, const char* action) + { + if (source & DfMp3_PlaySources_Sd) + { + Serial.print("SD Card, "); + } + if (source & DfMp3_PlaySources_Usb) + { + Serial.print("USB Disk, "); + } + if (source & DfMp3_PlaySources_Flash) + { + Serial.print("Flash, "); + } + Serial.println(action); + } + static void OnError(uint16_t errorCode) + { + // see DfMp3_Error for code meaning + Serial.println(); + Serial.print("Com Error "); + Serial.println(errorCode); + } + static void OnPlayFinished(DfMp3_PlaySources source, uint16_t track) + { + Serial.print("Play finished for #"); + Serial.println(track); + } + static void OnPlaySourceOnline(DfMp3_PlaySources source) + { + PrintlnSourceAction(source, "online"); + } + static void OnPlaySourceInserted(DfMp3_PlaySources source) + { + PrintlnSourceAction(source, "inserted"); + } + static void OnPlaySourceRemoved(DfMp3_PlaySources source) + { + PrintlnSourceAction(source, "removed"); + } +}; + +// instance a DFMiniMp3 object, +// defined with the above notification class and the hardware serial class +// +DFMiniMp3 mp3(Serial1); + +// Some arduino boards only have one hardware serial port, so a software serial port is needed instead. +// comment out the above definition and uncomment these lines +//SoftwareSerial secondarySerial(10, 11); // RX, TX +//DFMiniMp3 mp3(secondarySerial); + +uint32_t lastAdvert; // track time for last advertisement + +void setup() +{ + Serial.begin(115200); + + Serial.println("initializing..."); + + mp3.begin(); + uint16_t volume = mp3.getVolume(); + Serial.print("volume was "); + Serial.println(volume); + mp3.setVolume(24); + volume = mp3.getVolume(); + Serial.print(" and changed to "); + Serial.println(volume); + + Serial.println("track 1 from folder 1"); + mp3.playFolderTrack(1, 1); // sd:/01/001.mp3 + + lastAdvert = millis(); +} + +void loop() +{ + uint32_t now = millis(); + if ((now - lastAdvert) > 60000) + { + // interrupt the song and play the advertisement, it will + // return to the song when its done playing automatically + mp3.playAdvertisement(1); // sd:/advert/0001.mp3 + lastAdvert = now; + } + mp3.loop(); +} diff --git a/lib/DFMiniMp3-1.0.7-noChecksums/examples/PlayMp3/PlayMp3.ino b/lib/DFMiniMp3-1.0.7-noChecksums/examples/PlayMp3/PlayMp3.ino new file mode 100644 index 0000000..c5e9b0a --- /dev/null +++ b/lib/DFMiniMp3-1.0.7-noChecksums/examples/PlayMp3/PlayMp3.ino @@ -0,0 +1,121 @@ +// this example will play a track and then +// every five seconds play another track +// +// it expects the sd card to contain these three mp3 files +// but doesn't care whats in them +// +// sd:/mp3/0001.mp3 +// sd:/mp3/0002.mp3 +// sd:/mp3/0003.mp3 + +#include +#include + +// implement a notification class, +// its member methods will get called +// +class Mp3Notify +{ +public: + static void PrintlnSourceAction(DfMp3_PlaySources source, const char* action) + { + if (source & DfMp3_PlaySources_Sd) + { + Serial.print("SD Card, "); + } + if (source & DfMp3_PlaySources_Usb) + { + Serial.print("USB Disk, "); + } + if (source & DfMp3_PlaySources_Flash) + { + Serial.print("Flash, "); + } + Serial.println(action); + } + static void OnError(uint16_t errorCode) + { + // see DfMp3_Error for code meaning + Serial.println(); + Serial.print("Com Error "); + Serial.println(errorCode); + } + static void OnPlayFinished(DfMp3_PlaySources source, uint16_t track) + { + Serial.print("Play finished for #"); + Serial.println(track); + } + static void OnPlaySourceOnline(DfMp3_PlaySources source) + { + PrintlnSourceAction(source, "online"); + } + static void OnPlaySourceInserted(DfMp3_PlaySources source) + { + PrintlnSourceAction(source, "inserted"); + } + static void OnPlaySourceRemoved(DfMp3_PlaySources source) + { + PrintlnSourceAction(source, "removed"); + } +}; + +// instance a DFMiniMp3 object, +// defined with the above notification class and the hardware serial class +// +DFMiniMp3 mp3(Serial1); + +// Some arduino boards only have one hardware serial port, so a software serial port is needed instead. +// comment out the above definition and uncomment these lines +//SoftwareSerial secondarySerial(10, 11); // RX, TX +//DFMiniMp3 mp3(secondarySerial); + +void setup() +{ + Serial.begin(115200); + + Serial.println("initializing..."); + + mp3.begin(); + + uint16_t volume = mp3.getVolume(); + Serial.print("volume "); + Serial.println(volume); + mp3.setVolume(24); + + uint16_t count = mp3.getTotalTrackCount(DfMp3_PlaySource_Sd); + Serial.print("files "); + Serial.println(count); + + Serial.println("starting..."); +} + +void waitMilliseconds(uint16_t msWait) +{ + uint32_t start = millis(); + + while ((millis() - start) < msWait) + { + // calling mp3.loop() periodically allows for notifications + // to be handled without interrupts + mp3.loop(); + delay(1); + } +} + +void loop() +{ + Serial.println("track 1"); + mp3.playMp3FolderTrack(1); // sd:/mp3/0001.mp3 + + waitMilliseconds(5000); + + Serial.println("track 2"); + mp3.playMp3FolderTrack(2); // sd:/mp3/0002.mp3 + + waitMilliseconds(5000); + + Serial.println("track 3"); + mp3.playMp3FolderTrack(3); // sd:/mp3/0002.mp3 + + waitMilliseconds(5000); +} diff --git a/lib/DFMiniMp3-1.0.7-noChecksums/examples/PlayRandom/PlayRandom.ino b/lib/DFMiniMp3-1.0.7-noChecksums/examples/PlayRandom/PlayRandom.ino new file mode 100644 index 0000000..9714099 --- /dev/null +++ b/lib/DFMiniMp3-1.0.7-noChecksums/examples/PlayRandom/PlayRandom.ino @@ -0,0 +1,100 @@ +// this example will play a random track from all on the sd +// +// it expects the sd card to contain some mp3 files + +#include +#include + +// implement a notification class, +// its member methods will get called +// +class Mp3Notify +{ +public: + static void PrintlnSourceAction(DfMp3_PlaySources source, const char* action) + { + if (source & DfMp3_PlaySources_Sd) + { + Serial.print("SD Card, "); + } + if (source & DfMp3_PlaySources_Usb) + { + Serial.print("USB Disk, "); + } + if (source & DfMp3_PlaySources_Flash) + { + Serial.print("Flash, "); + } + Serial.println(action); + } + static void OnError(uint16_t errorCode) + { + // see DfMp3_Error for code meaning + Serial.println(); + Serial.print("Com Error "); + Serial.println(errorCode); + } + static void OnPlayFinished(DfMp3_PlaySources source, uint16_t track) + { + Serial.print("Play finished for #"); + Serial.println(track); + } + static void OnPlaySourceOnline(DfMp3_PlaySources source) + { + PrintlnSourceAction(source, "online"); + } + static void OnPlaySourceInserted(DfMp3_PlaySources source) + { + PrintlnSourceAction(source, "inserted"); + } + static void OnPlaySourceRemoved(DfMp3_PlaySources source) + { + PrintlnSourceAction(source, "removed"); + } +}; + +// instance a DFMiniMp3 object, +// defined with the above notification class and the hardware serial class +// +DFMiniMp3 mp3(Serial1); + +// Some arduino boards only have one hardware serial port, so a software serial port is needed instead. +// comment out the above definition and uncomment these lines +//SoftwareSerial secondarySerial(10, 11); // RX, TX +//DFMiniMp3 mp3(secondarySerial); + +void setup() +{ + + Serial.begin(115200); + + Serial.println("initializing..."); + + mp3.begin(); + mp3.reset(); + + // show some properties and set the volume + uint16_t volume = mp3.getVolume(); + Serial.print("volume "); + Serial.println(volume); + mp3.setVolume(24); + + uint16_t count = mp3.getTotalTrackCount(DfMp3_PlaySource_Sd); + Serial.print("files "); + Serial.println(count); + + uint16_t mode = mp3.getPlaybackMode(); + Serial.print("playback mode "); + Serial.println(mode); + + Serial.println("starting..."); + + mp3.playRandomTrackFromAll(); // random of all folders on sd +} + +void loop() +{ + // calling mp3.loop() periodically allows for notifications + // to be handled without interrupts + mp3.loop(); +} diff --git a/lib/DFMiniMp3-1.0.7-noChecksums/keywords.txt b/lib/DFMiniMp3-1.0.7-noChecksums/keywords.txt new file mode 100644 index 0000000..76b29ec --- /dev/null +++ b/lib/DFMiniMp3-1.0.7-noChecksums/keywords.txt @@ -0,0 +1,79 @@ +####################################### +# Syntax Coloring Map for DFMiniMp3 +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +DFMiniMp3 KEYWORD1 +DfMp3_PlaybackMode KEYWORD1 +DfMp3_Eq KEYWORD1 +DfMp3_PlaySource KEYWORD1 +DfMp3_PlaySources KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +begin KEYWORD2 +loop KEYWORD2 +getPlaySources KEYWORD2 +playGlobalTrack KEYWORD2 +playMp3FolderTrack KEYWORD2 +playFolderTrack KEYWORD2 +playFolderTrack16 KEYWORD2 +playRandomTrackFromAll KEYWORD2 +nextTrack KEYWORD2 +prevTrack KEYWORD2 +getCurrentTrack KEYWORD2 +setVolume KEYWORD2 +getVolume KEYWORD2 +increaseVolume KEYWORD2 +decreaseVolume KEYWORD2 +loopGlobalTrack KEYWORD2 +loopFolder KEYWORD2 +getPlaybackMode KEYWORD2 +setRepeatPlayAllInRoot KEYWORD2 +setRepeatPlayCurrentTrack KEYWORD2 +setEq KEYWORD2 +getEq KEYWORD2 +setPlaybackSource KEYWORD2 +sleep KEYWORD2 +reset KEYWORD2 +start KEYWORD2 +pause KEYWORD2 +stop KEYWORD2 +getStatus KEYWORD2 +getFolderTrackCount KEYWORD2 +getTotalTrackCount KEYWORD2 +getTotalFolderCount KEYWORD2 +playAdvertisement KEYWORD2 +stopAdvertisement KEYWORD2 +enableDac KEYWORD2 +disableDac KEYWORD2 +isOnline KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### + +DfMp3_PlaybackMode_Repeat LITERAL1 +DfMp3_PlaybackMode_FolderRepeat LITERAL1 +DfMp3_PlaybackMode_SingleRepeat LITERAL1 +DfMp3_PlaybackMode_Random LITERAL1 +DfMp3_Eq_Normal LITERAL1 +DfMp3_Eq_Pop LITERAL1 +DfMp3_Eq_Rock LITERAL1 +DfMp3_Eq_Jazz LITERAL1 +DfMp3_Eq_Classic LITERAL1 +DfMp3_Eq_Bass LITERAL1 +DfMp3_PlaySource_Usb LITERAL1 +DfMp3_PlaySource_Sd LITERAL1 +DfMp3_PlaySource_Aux LITERAL1 +DfMp3_PlaySource_Sleep LITERAL1 +DfMp3_PlaySource_Flash LITERAL1 +DfMp3_PlaySources_Usb LITERAL1 +DfMp3_PlaySources_Sd LITERAL1 +DfMp3_PlaySources_Pc LITERAL1 +DfMp3_PlaySources_Flash LITERAL1 diff --git a/lib/DFMiniMp3-1.0.7-noChecksums/library.properties b/lib/DFMiniMp3-1.0.7-noChecksums/library.properties new file mode 100644 index 0000000..2528491 --- /dev/null +++ b/lib/DFMiniMp3-1.0.7-noChecksums/library.properties @@ -0,0 +1,9 @@ +name=DFPlayer Mini Mp3 by Makuna +version=1.0.7 +author=Michael C. Miller (makuna@live.com) +maintainer=Michael C. Miller (makuna@live.com) +sentence=Library for the DFPlayer Mini Mp3 module +paragraph=This library allows your Arduino project to control the DFPlayer Mini MP3 module. It supports both hardware serial and software serial. It was designed to fit in the smallest Arduino hardware by consuming less code and memory space than other libraries. +category=Device Control +url=https://github.com/Makuna/DFMiniMp3/wiki +architectures=* \ No newline at end of file diff --git a/lib/DFMiniMp3-1.0.7-noChecksums/src/DFMiniMp3.h b/lib/DFMiniMp3-1.0.7-noChecksums/src/DFMiniMp3.h new file mode 100644 index 0000000..e1c9994 --- /dev/null +++ b/lib/DFMiniMp3-1.0.7-noChecksums/src/DFMiniMp3.h @@ -0,0 +1,559 @@ +/*------------------------------------------------------------------------- +DFMiniMp3 library + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/DFMiniMp3) + +------------------------------------------------------------------------- +This file is part of the Makuna/DFMiniMp3 library. + +DFMiniMp3 is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +DFMiniMp3 is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with DFMiniMp3. If not, see +. +-------------------------------------------------------------------------*/ +#pragma once + +enum DfMp3_Error +{ + // from device + DfMp3_Error_Busy = 1, + DfMp3_Error_Sleeping, + DfMp3_Error_SerialWrongStack, + DfMp3_Error_CheckSumNotMatch, + DfMp3_Error_FileIndexOut, + DfMp3_Error_FileMismatch, + DfMp3_Error_Advertise, + // from library + DfMp3_Error_RxTimeout = 0x81, + DfMp3_Error_PacketSize, + DfMp3_Error_PacketHeader, + DfMp3_Error_PacketChecksum, + DfMp3_Error_General = 0xff +}; + +enum DfMp3_PlaybackMode +{ + DfMp3_PlaybackMode_Repeat, + DfMp3_PlaybackMode_FolderRepeat, + DfMp3_PlaybackMode_SingleRepeat, + DfMp3_PlaybackMode_Random +}; + +enum DfMp3_Eq +{ + DfMp3_Eq_Normal, + DfMp3_Eq_Pop, + DfMp3_Eq_Rock, + DfMp3_Eq_Jazz, + DfMp3_Eq_Classic, + DfMp3_Eq_Bass +}; + +enum DfMp3_PlaySource // value - only one can be set +{ + DfMp3_PlaySource_Usb = 1, + DfMp3_PlaySource_Sd, + DfMp3_PlaySource_Aux, + DfMp3_PlaySource_Sleep, + DfMp3_PlaySource_Flash +}; + +enum DfMp3_PlaySources // bitfield - more than one can be set +{ + DfMp3_PlaySources_Usb = 0x01, + DfMp3_PlaySources_Sd = 0x02, + DfMp3_PlaySources_Pc = 0x04, + DfMp3_PlaySources_Flash = 0x08, +}; + +template +class DFMiniMp3 +{ +public: + DFMiniMp3(T_SERIAL_METHOD &serial) : _serial(serial), + _lastSendSpace(c_msSendSpace), + _isOnline(false) + { + } + + void begin(unsigned long baud = 9600) + { + _serial.begin(baud); + _serial.setTimeout(10000); + _lastSend = millis(); + } + + void loop() + { + while (_serial.available() >= DfMp3_Packet_SIZE) + { + listenForReply(0x00); + } + } + + // Does not work with all models. + // YX5200-24SS - sends reply + // MH2024K-24SS - sends NO reply --> results in error notification + DfMp3_PlaySources getPlaySources() + { + drainResponses(); + sendPacket(0x3f); + return static_cast(listenForReply(0x3f)); + } + + // the track as enumerated across all folders + void playGlobalTrack(uint16_t track = 0) + { + sendPacket(0x03, track); + } + + // sd:/mp3/####track name + void playMp3FolderTrack(uint16_t track) + { + sendPacket(0x12, track); + } + + // older devices: sd:/###/###track name + // newer devices: sd:/##/###track name + // folder and track numbers are zero padded + void playFolderTrack(uint8_t folder, uint8_t track) + { + uint16_t arg = (folder << 8) | track; + sendPacket(0x0f, arg); + } + + // sd:/##/####track name + // track number must be four digits, zero padded + void playFolderTrack16(uint8_t folder, uint16_t track) + { + uint16_t arg = (((uint16_t)folder) << 12) | track; + sendPacket(0x14, arg); + } + + void playRandomTrackFromAll() + { + sendPacket(0x18); + } + + void nextTrack() + { + sendPacket(0x01); + } + + void prevTrack() + { + sendPacket(0x02); + } + + uint16_t getCurrentTrack(DfMp3_PlaySource source = DfMp3_PlaySource_Sd) + { + drainResponses(); + + uint8_t command; + + switch (source) + { + case DfMp3_PlaySource_Usb: + command = 0x4b; + break; + case DfMp3_PlaySource_Sd: + command = 0x4c; + break; + case DfMp3_PlaySource_Flash: + command = 0x4d; + break; + default: + command = 0x4c; + break; + } + + sendPacket(command); + return listenForReply(command); + } + + // 0- 30 + void setVolume(uint8_t volume) + { + sendPacket(0x06, volume); + } + + uint8_t getVolume() + { + drainResponses(); + sendPacket(0x43); + return static_cast(listenForReply(0x43)); + } + + void increaseVolume() + { + sendPacket(0x04); + } + + void decreaseVolume() + { + sendPacket(0x05); + } + + // useless, removed + // 0-31 + /* + void setVolume(bool mute, uint8_t volume) + { + uint16_t arg = (!mute << 8) | volume; + sendPacket(0x10, arg); + } + */ + + void loopGlobalTrack(uint16_t globalTrack) + { + sendPacket(0x08, globalTrack); + } + + // sd:/##/* + // 0-99 + void loopFolder(uint8_t folder) + { + sendPacket(0x17, folder); + } + + DfMp3_PlaybackMode getPlaybackMode() + { + drainResponses(); + sendPacket(0x45); + return static_cast(listenForReply(0x45)); + } + + void setRepeatPlayAllInRoot(bool repeat) + { + sendPacket(0x11, !!repeat); + } + + void setRepeatPlayCurrentTrack(bool repeat) + { + sendPacket(0x19, !repeat); + } + + void setEq(DfMp3_Eq eq) + { + sendPacket(0x07, eq); + } + + DfMp3_Eq getEq() + { + drainResponses(); + sendPacket(0x44); + return static_cast(listenForReply(0x44)); + } + + void setPlaybackSource(DfMp3_PlaySource source) + { + sendPacket(0x09, source, 200); + } + + void sleep() + { + sendPacket(0x0a); + } + + void reset() + { + sendPacket(0x0c, 0, 600); + _isOnline = false; + } + + void start() + { + sendPacket(0x0d); + } + + void pause() + { + sendPacket(0x0e); + } + + void stop() + { + sendPacket(0x16); + } + + uint16_t getStatus() + { + drainResponses(); + sendPacket(0x42); + return listenForReply(0x42); + } + + uint16_t getFolderTrackCount(uint16_t folder) + { + drainResponses(); + sendPacket(0x4e, folder); + return listenForReply(0x4e); + } + + uint16_t getTotalTrackCount(DfMp3_PlaySource source) + { + drainResponses(); + + uint8_t command; + + switch (source) + { + case DfMp3_PlaySource_Usb: + command = 0x47; + break; + case DfMp3_PlaySource_Sd: + command = 0x48; + break; + case DfMp3_PlaySource_Flash: + command = 0x49; + break; + default: + command = 0x48; + break; + } + + sendPacket(command); + return listenForReply(command); + } + + uint16_t getTotalFolderCount() + { + drainResponses(); + sendPacket(0x4F); + return listenForReply(0x4F); + } + + // sd:/advert/####track name + void playAdvertisement(uint16_t track) + { + sendPacket(0x13, track); + } + + void stopAdvertisement() + { + sendPacket(0x15); + } + + void enableDac() + { + sendPacket(0x1A, 0x00); + } + + void disableDac() + { + sendPacket(0x1A, 0x01); + } + + bool isOnline() const + { + return _isOnline; + } + +private: + static const uint16_t c_msSendSpace = 50; + + // 7E FF 06 0F 00 01 01 xx xx EF + // 0 -> 7E is start code + // 1 -> FF is version + // 2 -> 06 is length + // 3 -> 0F is command + // 4 -> 00 is no receive + // 5~6 -> 01 01 is argument + // 7~8 -> checksum = 0 - ( FF+06+0F+00+01+01 ) + // 9 -> EF is end code + enum DfMp3_Packet + { + DfMp3_Packet_StartCode, + DfMp3_Packet_Version, + DfMp3_Packet_Length, + DfMp3_Packet_Command, + DfMp3_Packet_RequestAck, + DfMp3_Packet_HiByteArgument, + DfMp3_Packet_LowByteArgument, + DfMp3_Packet_HiByteCheckSum, + DfMp3_Packet_LowByteCheckSum, + DfMp3_Packet_EndCode, + DfMp3_Packet_SIZE + }; + enum DfMp3_Packet_short + { + DfMp3_Packet_short_StartCode, + DfMp3_Packet_short_Version, + DfMp3_Packet_short_Length, + DfMp3_Packet_short_Command, + DfMp3_Packet_short_RequestAck, + DfMp3_Packet_short_HiByteArgument, + DfMp3_Packet_short_LowByteArgument, + // DfMp3_Packet_short_HiByteCheckSum, + // DfMp3_Packet_short_LowByteCheckSum, + DfMp3_Packet_short_EndCode, + DfMp3_Packet_short_SIZE + }; + + T_SERIAL_METHOD &_serial; + uint32_t _lastSend; + uint16_t _lastSendSpace; + bool _isOnline; + + void drainResponses() + { + while (_serial.available() > 0) + { + listenForReply(0x00); + } + } + + void sendPacket(uint8_t command, uint16_t arg = 0, uint16_t sendSpaceNeeded = c_msSendSpace) + { + uint8_t out[DfMp3_Packet_short_SIZE] = {0x7E, + 0xFF, + 06, + command, + 00, + static_cast(arg >> 8), + static_cast(arg & 0x00ff), + // 00, + // 00, + 0xEF}; + + // setChecksum(out); + + // wait for spacing since last send + while (((millis() - _lastSend) < _lastSendSpace)) + { + // check for event messages from the device while + // we wait + loop(); + delay(1); + } + + _lastSendSpace = sendSpaceNeeded; + _serial.write(out, DfMp3_Packet_short_SIZE); + + _lastSend = millis(); + } + + bool readPacket(uint8_t *command, uint16_t *argument) + { + uint8_t in[DfMp3_Packet_SIZE] = {0}; + uint8_t read; + + // init our out args always + *command = 0; + *argument = 0; + + // try to sync our reads to the packet start + do + { + // we use readBytes as it gives us the standard timeout + read = _serial.readBytes(&(in[DfMp3_Packet_StartCode]), 1); + + if (read != 1) + { + // nothing read + *argument = DfMp3_Error_RxTimeout; + + return false; + } + } while (in[DfMp3_Packet_StartCode] != 0x7e); + + read += _serial.readBytes(in + 1, DfMp3_Packet_SIZE - 1); + if (read < DfMp3_Packet_SIZE) + { + // not enough bytes, corrupted packet + *argument = DfMp3_Error_PacketSize; + return false; + } + + if (in[DfMp3_Packet_Version] != 0xFF || + in[DfMp3_Packet_Length] != 0x06 || + in[DfMp3_Packet_EndCode] != 0xef) + { + // invalid version or corrupted packet + *argument = DfMp3_Error_PacketHeader; + return false; + } + + // if (!validateChecksum(in)) + // { + // // checksum failed, corrupted packet + // *argument = DfMp3_Error_PacketChecksum; + // return false; + // } + + *command = in[DfMp3_Packet_Command]; + *argument = ((in[DfMp3_Packet_HiByteArgument] << 8) | in[DfMp3_Packet_LowByteArgument]); + + return true; + } + + uint16_t listenForReply(uint8_t command) + { + uint8_t replyCommand = 0; + uint16_t replyArg = 0; + + do + { + if (readPacket(&replyCommand, &replyArg)) + { + if (command != 0 && command == replyCommand) + { + return replyArg; + } + else + { + + } + } + else + { + if (replyArg != 0) + { + + if (_serial.available() == 0) + { + return 0; + } + } + } + } while (command != 0); + + return 0; + } + + // uint16_t calcChecksum(uint8_t *packet) + // { + // uint16_t sum = 0xFFFF; + // for (int i = DfMp3_Packet_Version; i < DfMp3_Packet_HiByteCheckSum; i++) + // { + // sum -= packet[i]; + // } + // return sum + 1; + // } + + // void setChecksum(uint8_t *out) + // { + // uint16_t sum = calcChecksum(out); + + // out[DfMp3_Packet_HiByteCheckSum] = ((sum >> 8) & 0xFF); + // out[DfMp3_Packet_LowByteCheckSum] = (sum & 0xff); + // } + + // bool validateChecksum(uint8_t *in) + // { + // uint16_t sum = calcChecksum(in); + // return (sum == static_cast((in[DfMp3_Packet_HiByteCheckSum] << 8) | in[DfMp3_Packet_LowByteCheckSum])); + // } +}; diff --git a/platformio.ini b/platformio.ini index 4d7eac4..bd2766f 100644 --- a/platformio.ini +++ b/platformio.ini @@ -31,7 +31,7 @@ upload_speed = 921600 framework = arduino build_flags = -DAWTRIX_UPGRADE -D MQTT_MAX_PACKET_SIZE=1024 lib_deps = - adafruit/Adafruit SHT31 Library@^2.2.0 + adafruit/Adafruit BME280 Library@^2.2.2 bblanchon/ArduinoJson@^6.20.0 evert-arias/EasyButton@^2.0.1 fastled/FastLED@^3.5.0 diff --git a/src/Apps.h b/src/Apps.h index 24fa508..3b17046 100644 --- a/src/Apps.h +++ b/src/Apps.h @@ -214,6 +214,7 @@ void HumApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, i matrix->print("%"); } +#ifdef ULANZI void BatApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp) { if (notify.flag) @@ -225,6 +226,7 @@ void BatApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, i matrix->print(BATTERY_PERCENT); // Ausgabe des Ladezustands matrix->print("%"); } +#endif void MenuApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state) { diff --git a/src/Dictionary.h b/src/Dictionary.h index 467f053..79132fc 100644 --- a/src/Dictionary.h +++ b/src/Dictionary.h @@ -50,11 +50,13 @@ extern const char HAhumName[]; extern const char HAhumClass[]; extern const char HAhumUnit[]; +#ifdef ULANZI extern const char HAbatID[]; extern const char HAbatIcon[]; extern const char HAbatName[]; extern const char HAbatClass[]; extern const char HAbatUnit[]; +#endif extern const char HAluxID[]; extern const char HAluxIcon[]; diff --git a/src/DisplayManager.cpp b/src/DisplayManager.cpp index 5acf730..a82265b 100644 --- a/src/DisplayManager.cpp +++ b/src/DisplayManager.cpp @@ -503,8 +503,10 @@ void DisplayManager_::loadNativeApps() // Update the "hum" app at position 3 updateApp("hum", HumApp, SHOW_HUM, 3); +#ifdef ULANZI // Update the "bat" app at position 4 updateApp("bat", BatApp, SHOW_BAT, 4); +#endif ui.setApps(Apps); @@ -813,11 +815,13 @@ void DisplayManager_::updateAppVector(const char *json) callback = HumApp; SHOW_HUM = show; } +#ifdef ULANZI else if (name == "bat") { callback = BatApp; SHOW_BAT = show; } +#endif else { // If the app is not one of the built-in apps, check if it's already in the vector diff --git a/src/DisplayManager.h b/src/DisplayManager.h index f83ffdf..942a290 100644 --- a/src/DisplayManager.h +++ b/src/DisplayManager.h @@ -11,8 +11,10 @@ private: DisplayManager_() = default; +#ifdef ULANZI const int BatReadings = 10; uint16_t TotalBatReadings[10]; +#endif int readIndex = 0; uint16_t total = 0; uint16_t average = 0; diff --git a/src/Globals.cpp b/src/Globals.cpp index e667399..377eb4c 100644 --- a/src/Globals.cpp +++ b/src/Globals.cpp @@ -31,7 +31,9 @@ void loadSettings() SHOW_DATE = Settings.getBool("DAT", true); SHOW_TEMP = Settings.getBool("TEMP", true); SHOW_HUM = Settings.getBool("HUM", true); +#ifdef ULANZI SHOW_BAT = Settings.getBool("BAT", true); +#endif Settings.end(); uniqueID = getID(); MQTT_PREFIX = String(uniqueID); @@ -55,7 +57,9 @@ void saveSettings() Settings.putBool("DAT", SHOW_DATE); Settings.putBool("TEMP", SHOW_TEMP); Settings.putBool("HUM", SHOW_HUM); +#ifdef ULANZI Settings.putBool("BAT", SHOW_BAT); +#endif Settings.end(); } @@ -77,7 +81,9 @@ bool NET_STATIC = false; bool SHOW_TIME = true; bool SHOW_DATE = true; bool SHOW_WEATHER = true; +#ifdef ULANZI bool SHOW_BAT = true; +#endif bool SHOW_TEMP = true; bool SHOW_HUM = true; bool SHOW_SECONDS = true; @@ -102,8 +108,10 @@ float CURRENT_HUM; float CURRENT_LUX; uint8_t BRIGHTNESS = 120; uint8_t BRIGHTNESS_PERCENT; +#ifdef ULANZI uint8_t BATTERY_PERCENT; uint16_t BATTERY_RAW; +#endif uint16_t LDR_RAW; String TIME_FORMAT = "%H:%M:%S"; String DATE_FORMAT = "%d.%m.%y"; diff --git a/src/Globals.h b/src/Globals.h index 66f59f5..e242d4b 100644 --- a/src/Globals.h +++ b/src/Globals.h @@ -20,7 +20,9 @@ extern bool NET_STATIC; extern bool SHOW_TIME; extern bool SHOW_DATE; extern bool SHOW_WEATHER; +#ifdef ULANZI extern bool SHOW_BAT; +#endif extern bool SHOW_TEMP; extern bool SHOW_HUM; extern bool SHOW_SECONDS; @@ -42,8 +44,10 @@ extern float CURRENT_HUM; extern float CURRENT_LUX; extern uint16_t LDR_RAW; extern String CURRENT_APP; +#ifdef ULANZI extern uint8_t BATTERY_PERCENT; extern uint16_t BATTERY_RAW; +#endif extern uint8_t BRIGHTNESS; extern uint8_t BRIGHTNESS_PERCENT; extern String TEXTCOLOR; diff --git a/src/MQTTManager.cpp b/src/MQTTManager.cpp index 55d003a..1999018 100644 --- a/src/MQTTManager.cpp +++ b/src/MQTTManager.cpp @@ -24,7 +24,9 @@ HAButton *nextApp = nullptr; HAButton *prevApp = nullptr; HASwitch *transition = nullptr; HASensor *curApp = nullptr; +#ifdef ULANZI HASensor *battery = nullptr; +#endif HASensor *temperature = nullptr; HASensor *humidity = nullptr; HASensor *illuminance = nullptr; @@ -238,7 +240,10 @@ void connect() } char matID[40], briID[40]; -char btnAID[40], btnBID[40], btnCID[40], appID[40], tempID[40], humID[40], luxID[40], verID[40], batID[40], ramID[40], upID[40], sigID[40], btnLID[40], btnMID[40], btnRID[40], transID[40]; +char btnAID[40], btnBID[40], btnCID[40], appID[40], tempID[40], humID[40], luxID[40], verID[40], ramID[40], upID[40], sigID[40], btnLID[40], btnMID[40], btnRID[40], transID[40]; +#ifdef ULANZI +char batID[40]; +#endif void MQTTManager_::setup() { @@ -330,12 +335,14 @@ void MQTTManager_::setup() humidity->setDeviceClass(HAhumClass); humidity->setUnitOfMeasurement(HAhumUnit); +#ifdef ULANZI sprintf(batID, HAbatID, macStr); battery = new HASensor(batID); battery->setIcon(HAbatIcon); battery->setName(HAbatName); battery->setDeviceClass(HAbatClass); battery->setUnitOfMeasurement(HAbatUnit); +#endif sprintf(luxID, HAluxID, macStr); illuminance = new HASensor(luxID); @@ -432,8 +439,10 @@ void MQTTManager_::sendStats() if (HA_DISCOVERY) { char buffer[5]; +#ifdef ULANZI snprintf(buffer, 5, "%d", BATTERY_PERCENT); battery->setValue(buffer); +#endif snprintf(buffer, 5, "%.0f", CURRENT_TEMP); temperature->setValue(buffer); @@ -467,8 +476,10 @@ void MQTTManager_::sendStats() StaticJsonDocument<200> doc; char buffer[5]; +#ifdef ULANZI doc[BatKey] = BATTERY_PERCENT; doc[BatRawKey] = BATTERY_RAW; +#endif snprintf(buffer, 5, "%.0f", CURRENT_LUX); doc[LuxKey] = buffer; doc[LDRRawKey] = LDR_RAW; diff --git a/src/MenuManager.cpp b/src/MenuManager.cpp index 798f98e..6c9e4d2 100644 --- a/src/MenuManager.cpp +++ b/src/MenuManager.cpp @@ -75,8 +75,13 @@ const char *appsItems[][2] PROGMEM = { {"13", "time"}, {"1158", "date"}, {"234", "temp"}, +#ifdef ULANZI {"2075", "hum"}, {"1486", "bat"}}; +#else + {"2075", "hum"}}; +#endif + int8_t appsIndex; uint8_t appsCount = 5; @@ -173,9 +178,11 @@ String MenuManager_::menutext() case 3: DisplayManager.drawBMP(0, 0, get_icon(2075), 8, 8); return SHOW_HUM ? "ON" : "OFF"; +#ifdef ULANZI case 4: DisplayManager.drawBMP(0, 0, get_icon(1486), 8, 8); return SHOW_BAT ? "ON" : "OFF"; +#endif default: break; } @@ -374,9 +381,11 @@ void MenuManager_::selectButton() case 3: SHOW_HUM = !SHOW_HUM; break; +#ifdef ULANZI case 4: SHOW_BAT = !SHOW_BAT; break; +#endif default: break; } diff --git a/src/PeripheryManager.cpp b/src/PeripheryManager.cpp index 2781d78..e7dac58 100644 --- a/src/PeripheryManager.cpp +++ b/src/PeripheryManager.cpp @@ -21,7 +21,6 @@ #define BUTTON_SELECT_PIN 27 #else // Pinouts für das WEMOS_D1_MINI32-Environment -#define BATTERY_PIN -1 #define BUZZER_PIN -1 #define LDR_PIN A0 #define BUTTON_UP_PIN D0 @@ -29,7 +28,11 @@ #define BUTTON_SELECT_PIN D8 #endif +#ifdef ULANZI Adafruit_SHT31 sht31; +#else +Adafruit_BME280 bme280; +#endif EasyButton button_left(BUTTON_UP_PIN); EasyButton button_right(BUTTON_DOWN_PIN); EasyButton button_select(BUTTON_SELECT_PIN); @@ -134,11 +137,16 @@ bool PeripheryManager_::isPlaying() void fistStart() { - +#ifdef ULANZI uint16_t ADCVALUE = analogRead(BATTERY_PIN); - BATTERY_PERCENT = min((int)map(ADCVALUE, 490, 690, 0, 100), 100); + BATTERY_RAW = ADCVALUE; sht31.readBoth(&CURRENT_TEMP, &CURRENT_HUM); + CURRENT_TEMP -= 9.0; +#else + CURRENT_TEMP = bme280.readTemperature(); + CURRENT_HUM = 0; +#endif uint16_t LDRVALUE = analogRead(LDR_PIN); brightnessPercent = LDRVALUE / 4095.0 * 100.0; @@ -160,7 +168,11 @@ void PeripheryManager_::setup() button_select.onPressedFor(1000, select_button_pressed_long); button_select.onSequence(2, 300, select_button_tripple); Wire.begin(21, 22); +#ifdef ULANZI sht31.begin(0x44); +#else + bme280.begin(); +#endif photocell.setPhotocellPositionOnGround(false); fistStart(); } @@ -176,11 +188,16 @@ void PeripheryManager_::tick() if (currentMillis_BatTempHum - previousMillis_BatTempHum >= interval_BatTempHum) { previousMillis_BatTempHum = currentMillis_BatTempHum; +#ifdef ULANZI uint16_t ADCVALUE = analogRead(BATTERY_PIN); BATTERY_PERCENT = min((int)map(ADCVALUE, 475, 665, 0, 100), 100); BATTERY_RAW = ADCVALUE; sht31.readBoth(&CURRENT_TEMP, &CURRENT_HUM); CURRENT_TEMP -= 9.0; +#else + CURRENT_TEMP = bme280.readTemperature(); + CURRENT_HUM = bme280.readHumidity(); +#endif checkAlarms(); MQTTManager.sendStats(); } diff --git a/src/PeripheryManager.h b/src/PeripheryManager.h index 5f180ee..73fcf6f 100644 --- a/src/PeripheryManager.h +++ b/src/PeripheryManager.h @@ -3,15 +3,21 @@ #include #include +#ifdef ULANZI #include "Adafruit_SHT31.h" +#else +#include "Adafruit_BME280.h" +#endif class PeripheryManager_ { private: PeripheryManager_() = default; void checkAlarms(); +#ifdef ULANZI const int BatReadings = 10; uint16_t TotalBatReadings[10]; +#endif int readIndex = 0; uint16_t total = 0; uint16_t average = 0; From 01cf81397f2ea8527443104e767b378205279184 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20M=C3=BChl?= Date: Fri, 31 Mar 2023 15:39:15 +0200 Subject: [PATCH 3/7] fix merge errors --- src/Globals.cpp | 1 - src/MQTTManager.cpp | 8 ++++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Globals.cpp b/src/Globals.cpp index acf8651..aa530d0 100644 --- a/src/Globals.cpp +++ b/src/Globals.cpp @@ -104,7 +104,6 @@ void saveSettings() #ifdef ULANZI Settings.putBool("BAT", SHOW_BAT); #endif -======= Settings.putBool("SOUND", SOUND_ACTIVE); Settings.end(); } diff --git a/src/MQTTManager.cpp b/src/MQTTManager.cpp index b56aab5..301dce3 100644 --- a/src/MQTTManager.cpp +++ b/src/MQTTManager.cpp @@ -213,15 +213,16 @@ void onMqttConnected() "/previousapp", "/nextapp", "/nextapp", - "/apps" - }; - + "/apps"}; for (const char *topic : topics) + { String fullTopic = prefix + topic; mqtt.subscribe(fullTopic.c_str()); } Serial.println(F("MQTT Connected")); } + + void connect() { mqtt.onMessage(onMqttMessage); @@ -264,7 +265,6 @@ void MQTTManager_::setup() device.setAvailability(true); device.enableSharedAvailability(); device.enableLastWill(); - String uniqueIDWithSuffix; From 058e9d1ba8f293298236a68b2d48eb905e510390 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20M=C3=BChl?= <31169771+Blueforcer@users.noreply.github.com> Date: Sat, 1 Apr 2023 18:32:20 +0200 Subject: [PATCH 4/7] add duration to custompage --- .../.github/FUNDING.yml | 2 - .../PlayAdvertisements/PlayAdvertisements.ino | 105 --------------- .../examples/PlayMp3/PlayMp3.ino | 121 ------------------ .../examples/PlayRandom/PlayRandom.ino | 100 --------------- lib/MatrixUI/MatrixDisplayUi.h | 2 - lib/webserver/src/esp-fs-webserver.cpp | 19 ++- lib/webserver/src/esp-fs-webserver.h | 9 +- platformio.ini | 4 +- src/Apps.h | 112 ++++++++-------- src/DisplayManager.cpp | 21 +-- src/DisplayManager.h | 5 +- src/Globals.cpp | 7 +- src/Globals.h | 3 + src/MenuManager.cpp | 30 ++++- src/PeripheryManager.cpp | 75 ++++++++++- src/PeripheryManager.h | 7 +- src/ServerManager.cpp | 29 ++++- src/main.cpp | 8 +- 18 files changed, 234 insertions(+), 425 deletions(-) delete mode 100644 lib/DFMiniMp3-1.0.7-noChecksums/.github/FUNDING.yml delete mode 100644 lib/DFMiniMp3-1.0.7-noChecksums/examples/PlayAdvertisements/PlayAdvertisements.ino delete mode 100644 lib/DFMiniMp3-1.0.7-noChecksums/examples/PlayMp3/PlayMp3.ino delete mode 100644 lib/DFMiniMp3-1.0.7-noChecksums/examples/PlayRandom/PlayRandom.ino diff --git a/lib/DFMiniMp3-1.0.7-noChecksums/.github/FUNDING.yml b/lib/DFMiniMp3-1.0.7-noChecksums/.github/FUNDING.yml deleted file mode 100644 index 9bcf96a..0000000 --- a/lib/DFMiniMp3-1.0.7-noChecksums/.github/FUNDING.yml +++ /dev/null @@ -1,2 +0,0 @@ -github: [makuna] -custom: ["https://paypal.me/MakunaGithub"] diff --git a/lib/DFMiniMp3-1.0.7-noChecksums/examples/PlayAdvertisements/PlayAdvertisements.ino b/lib/DFMiniMp3-1.0.7-noChecksums/examples/PlayAdvertisements/PlayAdvertisements.ino deleted file mode 100644 index fa34f12..0000000 --- a/lib/DFMiniMp3-1.0.7-noChecksums/examples/PlayAdvertisements/PlayAdvertisements.ino +++ /dev/null @@ -1,105 +0,0 @@ -// this example will play a track and then every 60 seconds -// it will play an advertisement -// -// it expects the sd card to contain the following mp3 files -// but doesn't care whats in them -// -// sd:/01/001.mp3 - the song to play, the longer the better -// sd:/advert/0001.mp3 - the advertisement to interrupt the song, keep it short - -#include -#include - -// implement a notification class, -// its member methods will get called -// -class Mp3Notify -{ -public: - static void PrintlnSourceAction(DfMp3_PlaySources source, const char* action) - { - if (source & DfMp3_PlaySources_Sd) - { - Serial.print("SD Card, "); - } - if (source & DfMp3_PlaySources_Usb) - { - Serial.print("USB Disk, "); - } - if (source & DfMp3_PlaySources_Flash) - { - Serial.print("Flash, "); - } - Serial.println(action); - } - static void OnError(uint16_t errorCode) - { - // see DfMp3_Error for code meaning - Serial.println(); - Serial.print("Com Error "); - Serial.println(errorCode); - } - static void OnPlayFinished(DfMp3_PlaySources source, uint16_t track) - { - Serial.print("Play finished for #"); - Serial.println(track); - } - static void OnPlaySourceOnline(DfMp3_PlaySources source) - { - PrintlnSourceAction(source, "online"); - } - static void OnPlaySourceInserted(DfMp3_PlaySources source) - { - PrintlnSourceAction(source, "inserted"); - } - static void OnPlaySourceRemoved(DfMp3_PlaySources source) - { - PrintlnSourceAction(source, "removed"); - } -}; - -// instance a DFMiniMp3 object, -// defined with the above notification class and the hardware serial class -// -DFMiniMp3 mp3(Serial1); - -// Some arduino boards only have one hardware serial port, so a software serial port is needed instead. -// comment out the above definition and uncomment these lines -//SoftwareSerial secondarySerial(10, 11); // RX, TX -//DFMiniMp3 mp3(secondarySerial); - -uint32_t lastAdvert; // track time for last advertisement - -void setup() -{ - Serial.begin(115200); - - Serial.println("initializing..."); - - mp3.begin(); - uint16_t volume = mp3.getVolume(); - Serial.print("volume was "); - Serial.println(volume); - mp3.setVolume(24); - volume = mp3.getVolume(); - Serial.print(" and changed to "); - Serial.println(volume); - - Serial.println("track 1 from folder 1"); - mp3.playFolderTrack(1, 1); // sd:/01/001.mp3 - - lastAdvert = millis(); -} - -void loop() -{ - uint32_t now = millis(); - if ((now - lastAdvert) > 60000) - { - // interrupt the song and play the advertisement, it will - // return to the song when its done playing automatically - mp3.playAdvertisement(1); // sd:/advert/0001.mp3 - lastAdvert = now; - } - mp3.loop(); -} diff --git a/lib/DFMiniMp3-1.0.7-noChecksums/examples/PlayMp3/PlayMp3.ino b/lib/DFMiniMp3-1.0.7-noChecksums/examples/PlayMp3/PlayMp3.ino deleted file mode 100644 index c5e9b0a..0000000 --- a/lib/DFMiniMp3-1.0.7-noChecksums/examples/PlayMp3/PlayMp3.ino +++ /dev/null @@ -1,121 +0,0 @@ -// this example will play a track and then -// every five seconds play another track -// -// it expects the sd card to contain these three mp3 files -// but doesn't care whats in them -// -// sd:/mp3/0001.mp3 -// sd:/mp3/0002.mp3 -// sd:/mp3/0003.mp3 - -#include -#include - -// implement a notification class, -// its member methods will get called -// -class Mp3Notify -{ -public: - static void PrintlnSourceAction(DfMp3_PlaySources source, const char* action) - { - if (source & DfMp3_PlaySources_Sd) - { - Serial.print("SD Card, "); - } - if (source & DfMp3_PlaySources_Usb) - { - Serial.print("USB Disk, "); - } - if (source & DfMp3_PlaySources_Flash) - { - Serial.print("Flash, "); - } - Serial.println(action); - } - static void OnError(uint16_t errorCode) - { - // see DfMp3_Error for code meaning - Serial.println(); - Serial.print("Com Error "); - Serial.println(errorCode); - } - static void OnPlayFinished(DfMp3_PlaySources source, uint16_t track) - { - Serial.print("Play finished for #"); - Serial.println(track); - } - static void OnPlaySourceOnline(DfMp3_PlaySources source) - { - PrintlnSourceAction(source, "online"); - } - static void OnPlaySourceInserted(DfMp3_PlaySources source) - { - PrintlnSourceAction(source, "inserted"); - } - static void OnPlaySourceRemoved(DfMp3_PlaySources source) - { - PrintlnSourceAction(source, "removed"); - } -}; - -// instance a DFMiniMp3 object, -// defined with the above notification class and the hardware serial class -// -DFMiniMp3 mp3(Serial1); - -// Some arduino boards only have one hardware serial port, so a software serial port is needed instead. -// comment out the above definition and uncomment these lines -//SoftwareSerial secondarySerial(10, 11); // RX, TX -//DFMiniMp3 mp3(secondarySerial); - -void setup() -{ - Serial.begin(115200); - - Serial.println("initializing..."); - - mp3.begin(); - - uint16_t volume = mp3.getVolume(); - Serial.print("volume "); - Serial.println(volume); - mp3.setVolume(24); - - uint16_t count = mp3.getTotalTrackCount(DfMp3_PlaySource_Sd); - Serial.print("files "); - Serial.println(count); - - Serial.println("starting..."); -} - -void waitMilliseconds(uint16_t msWait) -{ - uint32_t start = millis(); - - while ((millis() - start) < msWait) - { - // calling mp3.loop() periodically allows for notifications - // to be handled without interrupts - mp3.loop(); - delay(1); - } -} - -void loop() -{ - Serial.println("track 1"); - mp3.playMp3FolderTrack(1); // sd:/mp3/0001.mp3 - - waitMilliseconds(5000); - - Serial.println("track 2"); - mp3.playMp3FolderTrack(2); // sd:/mp3/0002.mp3 - - waitMilliseconds(5000); - - Serial.println("track 3"); - mp3.playMp3FolderTrack(3); // sd:/mp3/0002.mp3 - - waitMilliseconds(5000); -} diff --git a/lib/DFMiniMp3-1.0.7-noChecksums/examples/PlayRandom/PlayRandom.ino b/lib/DFMiniMp3-1.0.7-noChecksums/examples/PlayRandom/PlayRandom.ino deleted file mode 100644 index 9714099..0000000 --- a/lib/DFMiniMp3-1.0.7-noChecksums/examples/PlayRandom/PlayRandom.ino +++ /dev/null @@ -1,100 +0,0 @@ -// this example will play a random track from all on the sd -// -// it expects the sd card to contain some mp3 files - -#include -#include - -// implement a notification class, -// its member methods will get called -// -class Mp3Notify -{ -public: - static void PrintlnSourceAction(DfMp3_PlaySources source, const char* action) - { - if (source & DfMp3_PlaySources_Sd) - { - Serial.print("SD Card, "); - } - if (source & DfMp3_PlaySources_Usb) - { - Serial.print("USB Disk, "); - } - if (source & DfMp3_PlaySources_Flash) - { - Serial.print("Flash, "); - } - Serial.println(action); - } - static void OnError(uint16_t errorCode) - { - // see DfMp3_Error for code meaning - Serial.println(); - Serial.print("Com Error "); - Serial.println(errorCode); - } - static void OnPlayFinished(DfMp3_PlaySources source, uint16_t track) - { - Serial.print("Play finished for #"); - Serial.println(track); - } - static void OnPlaySourceOnline(DfMp3_PlaySources source) - { - PrintlnSourceAction(source, "online"); - } - static void OnPlaySourceInserted(DfMp3_PlaySources source) - { - PrintlnSourceAction(source, "inserted"); - } - static void OnPlaySourceRemoved(DfMp3_PlaySources source) - { - PrintlnSourceAction(source, "removed"); - } -}; - -// instance a DFMiniMp3 object, -// defined with the above notification class and the hardware serial class -// -DFMiniMp3 mp3(Serial1); - -// Some arduino boards only have one hardware serial port, so a software serial port is needed instead. -// comment out the above definition and uncomment these lines -//SoftwareSerial secondarySerial(10, 11); // RX, TX -//DFMiniMp3 mp3(secondarySerial); - -void setup() -{ - - Serial.begin(115200); - - Serial.println("initializing..."); - - mp3.begin(); - mp3.reset(); - - // show some properties and set the volume - uint16_t volume = mp3.getVolume(); - Serial.print("volume "); - Serial.println(volume); - mp3.setVolume(24); - - uint16_t count = mp3.getTotalTrackCount(DfMp3_PlaySource_Sd); - Serial.print("files "); - Serial.println(count); - - uint16_t mode = mp3.getPlaybackMode(); - Serial.print("playback mode "); - Serial.println(mode); - - Serial.println("starting..."); - - mp3.playRandomTrackFromAll(); // random of all folders on sd -} - -void loop() -{ - // calling mp3.loop() periodically allows for notifications - // to be handled without interrupts - mp3.loop(); -} diff --git a/lib/MatrixUI/MatrixDisplayUi.h b/lib/MatrixUI/MatrixDisplayUi.h index 485060f..4f817fc 100644 --- a/lib/MatrixUI/MatrixDisplayUi.h +++ b/lib/MatrixUI/MatrixDisplayUi.h @@ -102,7 +102,6 @@ private: uint8_t updateInterval = 33; uint8_t getnextAppNumber(); - void drawIndicator(); void drawApp(); void drawOverlays(); void tick(); @@ -110,7 +109,6 @@ private: public: MatrixDisplayUi(FastLED_NeoMatrix *matrix); - uint8_t AppCount = 0; /** * Initialise the display diff --git a/lib/webserver/src/esp-fs-webserver.cpp b/lib/webserver/src/esp-fs-webserver.cpp index 00cd534..79031a6 100644 --- a/lib/webserver/src/esp-fs-webserver.cpp +++ b/lib/webserver/src/esp-fs-webserver.cpp @@ -24,16 +24,17 @@ void FSWebServer::addHandler(const Uri &uri, HTTPMethod method, WebServerClass:: webserver->on(uri, method, fn); } + +void FSWebServer::onNotFound(WebServerClass::THandlerFunction fn) +{ + webserver->onNotFound(fn); +} + void FSWebServer::addHandler(const Uri &uri, WebServerClass::THandlerFunction handler) { webserver->on(uri, HTTP_ANY, handler); } -void FSWebServer::onNotFound(WebServerClass::THandlerFunction handler) -{ - webserver->onNotFound(handler); -} - // List all files saved in the selected filesystem bool FSWebServer::checkDir(char *dirname, uint8_t levels) { @@ -85,7 +86,7 @@ bool FSWebServer::begin(const char *path) webserver->on("/edit", HTTP_PUT, std::bind(&FSWebServer::handleFileCreate, this)); webserver->on("/edit", HTTP_DELETE, std::bind(&FSWebServer::handleFileDelete, this)); #endif - //webserver->onNotFound(std::bind(&FSWebServer::handleRequest, this)); + webserver->onNotFound(std::bind(&FSWebServer::handleRequest, this)); webserver->on("/favicon.ico", HTTP_GET, std::bind(&FSWebServer::replyOK, this)); webserver->on("/", HTTP_GET, std::bind(&FSWebServer::handleIndex, this)); #ifdef INCLUDE_SETUP_HTM @@ -158,6 +159,7 @@ IPAddress FSWebServer::startWiFi(uint32_t timeout, const char *apSSID, const cha #elif defined(ESP32) wifi_config_t conf; esp_wifi_get_config(WIFI_IF_STA, &conf); + _ssid = reinterpret_cast(conf.sta.ssid); _pass = reinterpret_cast(conf.sta.password); #endif @@ -167,6 +169,7 @@ IPAddress FSWebServer::startWiFi(uint32_t timeout, const char *apSSID, const cha WiFi.begin(_ssid, _pass); Serial.print(F("Connecting to ")); Serial.println(_ssid); + uint32_t startTime = millis(); while (WiFi.status() != WL_CONNECTED) { @@ -174,6 +177,8 @@ IPAddress FSWebServer::startWiFi(uint32_t timeout, const char *apSSID, const cha Serial.print("."); if (WiFi.status() == WL_CONNECTED) { + WiFi.setAutoReconnect(true); + WiFi.persistent(true); ip = WiFi.localIP(); return ip; } @@ -921,4 +926,4 @@ void FSWebServer::handleStatus() webserver->send(200, "application/json", json); } -#endif // INCLUDE_EDIT_HTM +#endif // INCLUDE_EDIT_HTM \ No newline at end of file diff --git a/lib/webserver/src/esp-fs-webserver.h b/lib/webserver/src/esp-fs-webserver.h index 88aab4f..9701dbe 100644 --- a/lib/webserver/src/esp-fs-webserver.h +++ b/lib/webserver/src/esp-fs-webserver.h @@ -5,7 +5,7 @@ #include #include #include -//#include +// #include #include #define INCLUDE_EDIT_HTM @@ -82,11 +82,11 @@ public: bool begin(const char *path = nullptr); void run(); - + void onNotFound(WebServerClass::THandlerFunction fn); + void addHandler(const Uri &uri, HTTPMethod method, WebServerClass::THandlerFunction fn); void addHandler(const Uri &uri, WebServerClass::THandlerFunction handler); - void onNotFound(WebServerClass::THandlerFunction handler); void setCaptiveWebage(const char *url); @@ -256,13 +256,12 @@ public: return true; } - template bool saveOptionValue(const char *label, T val) { // Öffne die Datei im Lesemodus, um den Inhalt des Dokuments beizubehalten File file = m_filesystem->open("/config.json", "r"); - DynamicJsonDocument doc(file.size()* 1.33); + DynamicJsonDocument doc(file.size() * 1.33); if (file) { diff --git a/platformio.ini b/platformio.ini index bd2766f..a73cba3 100644 --- a/platformio.ini +++ b/platformio.ini @@ -22,6 +22,7 @@ lib_deps = fastled/FastLED@^3.5.0 marcmerlin/FastLED NeoMatrix@^1.2 knolleary/PubSubClient@^2.8 + plerup/EspSoftwareSerial@^8.0.1 [env:awtrix_upgrade] platform = https://github.com/platformio/platform-espressif32.git @@ -36,4 +37,5 @@ lib_deps = evert-arias/EasyButton@^2.0.1 fastled/FastLED@^3.5.0 marcmerlin/FastLED NeoMatrix@^1.2 - knolleary/PubSubClient@^2.8 \ No newline at end of file + knolleary/PubSubClient@^2.8 + plerup/EspSoftwareSerial@^8.0.1 diff --git a/src/Apps.h b/src/Apps.h index aef6c56..ca747eb 100644 --- a/src/Apps.h +++ b/src/Apps.h @@ -36,6 +36,7 @@ struct CustomApp bool isGif; bool rainbow; bool soundPlayed; + uint16_t duration = 0; String sound; int16_t repeat = 0; int16_t currentRepeat = 0; @@ -61,7 +62,7 @@ struct Notification bool isGif; bool flag = false; unsigned long startime = 0; - unsigned long duration = 0; + uint16_t duration = 0; int16_t repeat = -1; bool hold = false; byte pushIcon = 0; @@ -104,7 +105,7 @@ int findAppIndexByName(const String &name) return -1; } -void TimeApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp) +void TimeApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame) { if (notify.flag) return; @@ -152,7 +153,7 @@ void TimeApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, } } -void DateApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp) +void DateApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame) { if (notify.flag) return; @@ -180,7 +181,7 @@ void DateApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, } } -void TempApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp) +void TempApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame) { if (notify.flag) return; @@ -201,7 +202,7 @@ void TempApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, } } -void HumApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp) +void HumApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame) { if (notify.flag) return; @@ -215,7 +216,7 @@ void HumApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, i } #ifdef ULANZI -void BatApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp) +void BatApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame) { if (notify.flag) return; @@ -275,7 +276,7 @@ void TimerApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state) } } -void ShowCustomApp(String name, FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp) +void ShowCustomApp(String name, FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame) { // Abort if notify.flag is set if (notify.flag) @@ -292,8 +293,8 @@ void ShowCustomApp(String name, FastLED_NeoMatrix *matrix, MatrixDisplayUiState return; } - // reset custom App properties if last App - if (lastApp) + // reset custom App properties if last frame + if (lastFrame) { ca->iconWasPushed = false; ca->scrollposition = 9; @@ -301,6 +302,14 @@ void ShowCustomApp(String name, FastLED_NeoMatrix *matrix, MatrixDisplayUiState ca->scrollDelay = 0; } + if (!DisplayManager.appIsSwitching) + { + if (ca->duration > 0) + { + DisplayManager.setAppTime(ca->duration); + } + } + CURRENT_APP = ca->name; currentCustomApp = name; @@ -622,127 +631,126 @@ void NotifyApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state) DisplayManager.getInstance().resetTextColor(); } +// Unattractive to have a function for every customapp wich does the same, but currently still no other option found TODO -//Unattractive to have a function for every customapp wich does the same, but currently still no other option found TODO - -void CApp1(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp) +void CApp1(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame) { String name = getAppNameByFunction(CApp1); - ShowCustomApp(name, matrix, state, x, y, firstApp, lastApp); + ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame); } -void CApp2(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp) +void CApp2(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame) { String name = getAppNameByFunction(CApp2); - ShowCustomApp(name, matrix, state, x, y, firstApp, lastApp); + ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame); } -void CApp3(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp) +void CApp3(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame) { String name = getAppNameByFunction(CApp3); - ShowCustomApp(name, matrix, state, x, y, firstApp, lastApp); + ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame); } -void CApp4(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp) +void CApp4(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame) { String name = getAppNameByFunction(CApp4); - ShowCustomApp(name, matrix, state, x, y, firstApp, lastApp); + ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame); } -void CApp5(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp) +void CApp5(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame) { String name = getAppNameByFunction(CApp5); - ShowCustomApp(name, matrix, state, x, y, firstApp, lastApp); + ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame); } -void CApp6(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp) +void CApp6(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame) { String name = getAppNameByFunction(CApp6); - ShowCustomApp(name, matrix, state, x, y, firstApp, lastApp); + ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame); } -void CApp7(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp) +void CApp7(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame) { String name = getAppNameByFunction(CApp7); - ShowCustomApp(name, matrix, state, x, y, firstApp, lastApp); + ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame); } -void CApp8(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp) +void CApp8(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame) { String name = getAppNameByFunction(CApp8); - ShowCustomApp(name, matrix, state, x, y, firstApp, lastApp); + ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame); } -void CApp9(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp) +void CApp9(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame) { String name = getAppNameByFunction(CApp9); - ShowCustomApp(name, matrix, state, x, y, firstApp, lastApp); + ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame); } -void CApp10(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp) +void CApp10(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame) { String name = getAppNameByFunction(CApp10); - ShowCustomApp(name, matrix, state, x, y, firstApp, lastApp); + ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame); } -void CApp11(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp) +void CApp11(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame) { String name = getAppNameByFunction(CApp11); - ShowCustomApp(name, matrix, state, x, y, firstApp, lastApp); + ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame); } -void CApp12(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp) +void CApp12(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame) { String name = getAppNameByFunction(CApp12); - ShowCustomApp(name, matrix, state, x, y, firstApp, lastApp); + ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame); } -void CApp13(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp) +void CApp13(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame) { String name = getAppNameByFunction(CApp13); - ShowCustomApp(name, matrix, state, x, y, firstApp, lastApp); + ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame); } -void CApp14(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp) +void CApp14(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame) { String name = getAppNameByFunction(CApp14); - ShowCustomApp(name, matrix, state, x, y, firstApp, lastApp); + ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame); } -void CApp15(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp) +void CApp15(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame) { String name = getAppNameByFunction(CApp15); - ShowCustomApp(name, matrix, state, x, y, firstApp, lastApp); + ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame); } -void CApp16(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp) +void CApp16(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame) { String name = getAppNameByFunction(CApp16); - ShowCustomApp(name, matrix, state, x, y, firstApp, lastApp); + ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame); } -void CApp17(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp) +void CApp17(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame) { String name = getAppNameByFunction(CApp17); - ShowCustomApp(name, matrix, state, x, y, firstApp, lastApp); + ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame); } -void CApp18(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp) +void CApp18(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame) { String name = getAppNameByFunction(CApp18); - ShowCustomApp(name, matrix, state, x, y, firstApp, lastApp); + ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame); } -void CApp19(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp) +void CApp19(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame) { String name = getAppNameByFunction(CApp19); - ShowCustomApp(name, matrix, state, x, y, firstApp, lastApp); + ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame); } -void CApp20(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp) +void CApp20(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame) { String name = getAppNameByFunction(CApp20); - ShowCustomApp(name, matrix, state, x, y, firstApp, lastApp); + ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame); } const uint16_t *getWeatherIcon(int code) @@ -759,7 +767,7 @@ const uint16_t *getWeatherIcon(int code) } } -void WeatherApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp) +void WeatherApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame) { if (notify.flag) return; diff --git a/src/DisplayManager.cpp b/src/DisplayManager.cpp index 7091d99..958d9a7 100644 --- a/src/DisplayManager.cpp +++ b/src/DisplayManager.cpp @@ -27,8 +27,6 @@ Ticker TimerTicker; #define MATRIX_WIDTH 32 #define MATRIX_HEIGHT 8 -bool appIsSwitching; - GifPlayer gif; CRGB leds[MATRIX_WIDTH * MATRIX_HEIGHT]; @@ -240,17 +238,15 @@ void removeCustomApp(const String &name) auto it = std::find_if(Apps.begin(), Apps.end(), [&name](const std::pair &appPair) { return appPair.first == name; }); - if (it != Apps.end()) - { - Apps.erase(it); - ui.setApps(Apps); - } + Apps.erase(it); + ui.setApps(Apps); } void DisplayManager_::generateCustomPage(String name, const char *json) { - if (json == "" && customApps.count(name)) + if (strcmp(json, "") == 0 && customApps.count(name)) { + Serial.println("delete"); customApps.erase(customApps.find(name)); removeCustomApp(name); return; @@ -297,6 +293,7 @@ void DisplayManager_::generateCustomPage(String name, const char *json) customApp.barSize = 0; } + customApp.duration = doc.containsKey("duration") ? doc["duration"].as() * 1000 : -1; int pos = doc.containsKey("pos") ? doc["pos"].as() : -1; customApp.rainbow = doc.containsKey("rainbow") ? doc["rainbow"] : false; customApp.pushIcon = doc.containsKey("pushIcon") ? doc["pushIcon"] : 0; @@ -534,17 +531,17 @@ void DisplayManager_::tick() } else { - ui.update(); if (ui.getUiState()->appState == IN_TRANSITION && !appIsSwitching) { appIsSwitching = true; - MQTTManager.setCurrentApp(CURRENT_APP); } else if (ui.getUiState()->appState == FIXED && appIsSwitching) { appIsSwitching = false; MQTTManager.setCurrentApp(CURRENT_APP); + setAppTime(TIME_PER_APP); } + ui.update(); } } @@ -910,3 +907,7 @@ String DisplayManager_::getStat() return jsonString; } +void DisplayManager_::setAppTime(uint16_t duration) +{ + ui.setTimePerApp(duration); +} \ No newline at end of file diff --git a/src/DisplayManager.h b/src/DisplayManager.h index b6b79a4..c81253f 100644 --- a/src/DisplayManager.h +++ b/src/DisplayManager.h @@ -26,6 +26,7 @@ private: public: static DisplayManager_ &getInstance(); + bool appIsSwitching; void setup(); void tick(); void clear(); @@ -48,7 +49,7 @@ public: void setFPS(uint8_t); void MatrixState(bool); void generateNotification(const char *json); - void generateCustomPage(String, const char *json); + void generateCustomPage(String name, const char *json); void printText(int16_t x, int16_t y, const char *text, bool centered, bool ignoreUppercase); bool setAutoTransition(bool active); void switchToApp(const char *json); @@ -60,6 +61,8 @@ public: void drawBMP(int16_t x, int16_t y, const uint16_t bitmap[], int16_t w, int16_t h); void drawBarChart(int16_t x, int16_t y, const int data[], byte dataSize, bool withIcon, uint16_t color); void updateAppVector(const char *json); + void setMatrixLayout(int layout); + void setAppTime(uint16_t duration); String getStat(); }; diff --git a/src/Globals.cpp b/src/Globals.cpp index aa530d0..549de3d 100644 --- a/src/Globals.cpp +++ b/src/Globals.cpp @@ -73,6 +73,7 @@ void loadSettings() SHOW_DATE = Settings.getBool("DAT", true); SHOW_TEMP = Settings.getBool("TEMP", true); SHOW_HUM = Settings.getBool("HUM", true); + MATRIX_LAYOUT = Settings.getUInt("MAT", 0); #ifdef ULANZI SHOW_BAT = Settings.getBool("BAT", true); #endif @@ -101,6 +102,7 @@ void saveSettings() Settings.putBool("DAT", SHOW_DATE); Settings.putBool("TEMP", SHOW_TEMP); Settings.putBool("HUM", SHOW_HUM); + Settings.putUInt("MAT", MATRIX_LAYOUT); #ifdef ULANZI Settings.putBool("BAT", SHOW_BAT); #endif @@ -177,4 +179,7 @@ bool TIMER_ACTIVE; bool ALARM_ACTIVE; uint16_t TEXTCOLOR_565 = 0xFFFF; bool SOUND_ACTIVE; -String BOOT_SOUND = ""; \ No newline at end of file +String BOOT_SOUND = ""; +uint8_t VOLUME; +uint8_t VOLUME_PERCENT; +int MATRIX_LAYOUT; \ No newline at end of file diff --git a/src/Globals.h b/src/Globals.h index a5242e6..6cb3e06 100644 --- a/src/Globals.h +++ b/src/Globals.h @@ -68,6 +68,9 @@ extern bool START_ON_MONDAY; extern bool IS_CELSIUS; extern bool SOUND_ACTIVE; extern String BOOT_SOUND; +extern uint8_t VOLUME; +extern uint8_t VOLUME_PERCENT; +extern int MATRIX_LAYOUT; void loadSettings(); void saveSettings(); #endif // Globals_H \ No newline at end of file diff --git a/src/MenuManager.cpp b/src/MenuManager.cpp index f4f0127..55f8b4e 100644 --- a/src/MenuManager.cpp +++ b/src/MenuManager.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -26,7 +27,8 @@ enum MenuState WeekdayMenu, TempMenu, Appmenu, - SoundMenu + SoundMenu, + VolumeMenu }; const char *menuItems[] PROGMEM = { @@ -42,10 +44,11 @@ const char *menuItems[] PROGMEM = { "TEMP", "APPS", "SOUND", + "VOLUME", "UPDATE"}; int8_t menuIndex = 0; -uint8_t menuItemCount = 13; +uint8_t menuItemCount = 14; const char *timeFormat[] PROGMEM = { "%H:%M:%S", @@ -77,10 +80,10 @@ const char *appsItems[][2] PROGMEM = { {"13", "time"}, {"1158", "date"}, {"234", "temp"}, -#ifdef ULANZI +#ifdef ULANZI {"2075", "hum"}, {"1486", "bat"}}; -#else +#else {"2075", "hum"}}; #endif @@ -247,6 +250,10 @@ void MenuManager_::rightButton() case TempMenu: IS_CELSIUS = !IS_CELSIUS; break; + case VolumeMenu: + VOLUME_PERCENT = (VOLUME_PERCENT % 100) + 1; + VOLUME = map(VOLUME_PERCENT, 0, 100, 0, 30); + PeripheryManager.setVolume(VOLUME); default: break; } @@ -307,6 +314,10 @@ void MenuManager_::leftButton() case SoundMenu: SOUND_ACTIVE = !SOUND_ACTIVE; break; + case VolumeMenu: + VOLUME_PERCENT = (VOLUME_PERCENT % 100) + 1; + VOLUME = map(VOLUME_PERCENT, 0, 100, 0, 30); + PeripheryManager.setVolume(VOLUME); default: break; } @@ -361,6 +372,11 @@ void MenuManager_::selectButton() currentState = SoundMenu; break; case 12: +#ifdef AWTRIX_UPGRADE + currentState = VolumeMenu; +#endif + break; + case 13: if (FirmwareVersionCheck()) { updateFirmware(); @@ -437,6 +453,12 @@ void MenuManager_::selectButtonLong() DisplayManager.applyAllSettings(); saveSettings(); break; + case VolumeMenu: +#ifdef AWTRIX_UPGRADE + VOLUME = map(VOLUME_PERCENT, 0, 100, 0, 30); + saveSettings(); +#endif + break; case TimeFormatMenu: TIME_FORMAT = timeFormat[timeFormatIndex]; saveSettings(); diff --git a/src/PeripheryManager.cpp b/src/PeripheryManager.cpp index ba5ea0c..2232ea5 100644 --- a/src/PeripheryManager.cpp +++ b/src/PeripheryManager.cpp @@ -29,8 +29,16 @@ #ifdef ULANZI Adafruit_SHT31 sht31; #else + +class Mp3Notify +{ +}; Adafruit_BME280 bme280; +SoftwareSerial mySoftwareSerial(D7, D5); // RX, TX +typedef DFMiniMp3 DfMp3; +DfMp3 dfmp3(mySoftwareSerial); #endif + EasyButton button_left(BUTTON_UP_PIN); EasyButton button_right(BUTTON_DOWN_PIN); EasyButton button_select(BUTTON_SELECT_PIN); @@ -59,6 +67,11 @@ float sampleSum = 0.0; float sampleAverage = 0.0; float brightnessPercent = 0.0; +#ifdef awrtrix_upgrade +class Mp3Notify; +SoftwareSerial mySoftwareSerial(D7, D5); // RX, TX +#endif + // The getter for the instantiated singleton instance PeripheryManager_ &PeripheryManager_::getInstance() { @@ -71,14 +84,36 @@ PeripheryManager_ &PeripheryManager = PeripheryManager.getInstance(); void left_button_pressed() { - DisplayManager.leftButton(); - MenuManager.leftButton(); + if (AP_MODE) + { + --MATRIX_LAYOUT; + if (MATRIX_LAYOUT < 0) + MATRIX_LAYOUT = 2; + saveSettings(); + ESP.restart(); + } + else + { + DisplayManager.leftButton(); + MenuManager.leftButton(); + } } void right_button_pressed() { - DisplayManager.rightButton(); - MenuManager.rightButton(); + if (AP_MODE) + { + ++MATRIX_LAYOUT; + if (MATRIX_LAYOUT > 2) + MATRIX_LAYOUT = 0; + saveSettings(); + ESP.restart(); + } + else + { + DisplayManager.rightButton(); + MenuManager.rightButton(); + } } void select_button_pressed() @@ -111,35 +146,61 @@ void PeripheryManager_::playBootSound() return; if (BOOT_SOUND == "") { +#ifdef ULANZI const int nNotes = 6; String notes[nNotes] = {"E5", "C5", "G4", "E4", "G4", "C5"}; const int timeUnit = 150; Melody melody = MelodyFactory.load("Bootsound", timeUnit, notes, nNotes); player.playAsync(melody); +#else +// no standardsound +#endif } else - { +#ifdef ULANZI playFromFile("/MELODIES/" + BOOT_SOUND + ".txt"); +#else + dfmp3.playMp3FolderTrack(BOOT_SOUND.toInt()); +#endif } } void PeripheryManager_::stopSound() { +#ifdef ULANZI player.stop(); +#else + dfmp3.stop(); +#endif +} + +void PeripheryManager_::setVolume(uint8_t vol) +{ +#ifdef AWTRIX_UPGRADE + dfmp3.setVolume(vol); +#endif } void PeripheryManager_::playFromFile(String file) { if (!SOUND_ACTIVE) return; +#ifdef ULANZI Melody melody = MelodyFactory.loadRtttlFile(file); player.playAsync(melody); +#else + dfmp3.playMp3FolderTrack(file.toInt()); +#endif } bool PeripheryManager_::isPlaying() { +#ifdef ULANZI return player.isPlaying(); +#else + return false; +#endif } void fistStart() @@ -152,7 +213,7 @@ void fistStart() CURRENT_TEMP -= 9.0; #else CURRENT_TEMP = bme280.readTemperature(); - CURRENT_HUM = 0; + CURRENT_HUM = bme280.readHumidity(); #endif uint16_t LDRVALUE = analogRead(LDR_PIN); @@ -180,6 +241,7 @@ void PeripheryManager_::setup() sht31.begin(0x44); #else bme280.begin(); + dfmp3.begin(); #endif photocell.setPhotocellPositionOnGround(false); fistStart(); @@ -300,7 +362,6 @@ void PeripheryManager_::checkAlarms() } } - const char *PeripheryManager_::readUptime() { static char uptime[25]; // Make the array static to keep it from being destroyed when the function returns diff --git a/src/PeripheryManager.h b/src/PeripheryManager.h index 838a3ac..c2111bd 100644 --- a/src/PeripheryManager.h +++ b/src/PeripheryManager.h @@ -4,9 +4,11 @@ #include #include #ifdef ULANZI -#include "Adafruit_SHT31.h" + #include "Adafruit_SHT31.h" #else -#include "Adafruit_BME280.h" + #include "Adafruit_BME280.h" + #include "SoftwareSerial.h" + #include #endif class PeripheryManager_ @@ -35,6 +37,7 @@ public: void playFromFile(String file); bool isPlaying(); void stopSound(); + void setVolume(uint8_t); const char *readUptime(); }; diff --git a/src/ServerManager.cpp b/src/ServerManager.cpp index 3f24a54..3fde180 100644 --- a/src/ServerManager.cpp +++ b/src/ServerManager.cpp @@ -37,7 +37,7 @@ void saveHandler() webRequest->send(200); } -void handlePostRequest() +void handleAPIRequest() { WebServerClass *webRequest = mws.getRequest(); String url = webRequest->uri(); @@ -129,7 +129,7 @@ void ServerManager_::setup() if (isConnected) { - mws.onNotFound(handlePostRequest); + mws.addOptionBox("Network"); mws.addOption("Static IP", NET_STATIC); mws.addOption("Local IP", NET_IP); @@ -154,9 +154,30 @@ void ServerManager_::setup() mws.addJavascript(custom_script); mws.addOptionBox("General"); mws.addOption("Uppercase letters", UPPERCASE_LETTERS); - mws.addHandler("/save", HTTP_GET, saveHandler); + mws.addHandler("/save", HTTP_POST, saveHandler); + mws.addHandler("/api/notify", HTTP_POST, []() + {DisplayManager.generateNotification(mws.webserver->arg("plain").c_str()); mws.webserver->send(200,"OK"); }); + mws.addHandler("/api/nextapp", HTTP_POST, []() + {DisplayManager.nextApp(); mws.webserver->send(200,"OK"); }); + mws.addHandler("/api/previousapp", HTTP_POST, []() + {DisplayManager.previousApp(); mws.webserver->send(200,"OK"); }); + mws.addHandler("/api/timer", HTTP_POST, []() + { DisplayManager.gererateTimer(mws.webserver->arg("plain").c_str()); mws.webserver->send(200,"OK"); }); + mws.addHandler("/api/notify/dismiss", HTTP_POST, []() + { DisplayManager.dismissNotify(); mws.webserver->send(200,"OK"); }); + mws.addHandler("/api/apps", HTTP_POST, []() + { DisplayManager.updateAppVector(mws.webserver->arg("plain").c_str()); mws.webserver->send(200,"OK"); }); + mws.addHandler("/api/switch", HTTP_POST, []() + { DisplayManager.switchToApp(mws.webserver->arg("plain").c_str()); mws.webserver->send(200,"OK"); }); + mws.addHandler("/api/settings", HTTP_POST, []() + { DisplayManager.setNewSettings(mws.webserver->arg("plain").c_str()); mws.webserver->send(200,"OK"); }); + mws.addHandler("/api/custom", HTTP_POST, []() + { DisplayManager.generateCustomPage(mws.webserver->arg("name"),mws.webserver->arg("plain").c_str()); mws.webserver->send(200,"OK"); }); + mws.addHandler("/api/stats", HTTP_GET, []() + { mws.webserver->sendContent(DisplayManager.getStat()); }); + Serial.println("Webserver loaded"); } - + mws.addHandler("/version", HTTP_GET, versionHandler); mws.begin(); if (!MDNS.begin(uniqueID)) diff --git a/src/main.cpp b/src/main.cpp index 3e78a3a..18a0b5f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -61,10 +61,15 @@ void setup() delay(500); Serial.begin(9600); loadSettings(); + Serial.println("1"); ServerManager.loadSettings(); + Serial.println("2"); DisplayManager.setup(); + Serial.println("3"); DisplayManager.HSVtext(9, 6, VERSION, true); + Serial.println("4"); delay(500); + Serial.println("5"); PeripheryManager.playBootSound(); xTaskCreatePinnedToCore(BootAnimation, "Task", 10000, NULL, 1, &taskHandle, 1); ServerManager.setup(); @@ -88,9 +93,10 @@ void loop() { ServerManager.tick(); DisplayManager.tick(); + PeripheryManager.tick(); if (ServerManager.isConnected) { - PeripheryManager.tick(); + MQTTManager.tick(); } } From 4cbce3f860577c8fb484e395d6d1431809ea773d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20M=C3=BChl?= <31169771+Blueforcer@users.noreply.github.com> Date: Sat, 1 Apr 2023 18:45:24 +0200 Subject: [PATCH 5/7] update docs --- docs/quickstart.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/quickstart.md b/docs/quickstart.md index 75be93f..103d1b9 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -2,7 +2,7 @@ # Quick start 1. :computer: Connect your device to your PC or Mac and [use the online flahser](flasher.md) 2. :signal_strength: After flashing, Awtrix will open an access point with the name "AWTRIX LIGHT". Connect with PW "12345678". -3. :mag: Open a browser and navigate to 192.168.4.1. Enter your WiFi information and reboot the clock. -4. :clock1: Your clock is accessible via http://awtrixlight.local/. +3. :mag: Open a browser and navigate to 192.168.4.1. Enter your WiFi information and connect to your WiFi. +4. :clock1: Your clock is accessible via the IP adress you see at connect. 5. :gear: Set up your MQTT and other options in the web interface. 6. :heavy_check_mark: You're ready to go. \ No newline at end of file From 641572671fc32e58811958465c6f09a6ea2f6c01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20M=C3=BChl?= <31169771+Blueforcer@users.noreply.github.com> Date: Sat, 1 Apr 2023 21:31:05 +0200 Subject: [PATCH 6/7] update docs --- docs/_sidebar.md | 5 ++-- docs/{mqtt.md => api.md} | 54 +++++++++++++++++++++++++++------------- docs/custom.md | 15 ++++++----- src/DisplayManager.cpp | 1 + src/Globals.cpp | 2 +- src/MenuManager.cpp | 6 ++--- src/ServerManager.cpp | 5 ++-- src/ServerManager.h | 1 + src/main.cpp | 14 ++++++----- 9 files changed, 66 insertions(+), 37 deletions(-) rename docs/{mqtt.md => api.md} (70%) diff --git a/docs/_sidebar.md b/docs/_sidebar.md index bf68571..1f29159 100644 --- a/docs/_sidebar.md +++ b/docs/_sidebar.md @@ -15,6 +15,7 @@ - [Icons](icons.md) - [Sounds](sounds.md) -- MQTT +- API + - [MQTT/HTTP](api.md) - [Custom Pages & Notifications](custom.md) - - [Commands](mqtt.md) + diff --git a/docs/mqtt.md b/docs/api.md similarity index 70% rename from docs/mqtt.md rename to docs/api.md index a9224cd..641db5f 100644 --- a/docs/mqtt.md +++ b/docs/api.md @@ -1,26 +1,40 @@ -# MQTT Commands +# MQTT / HTTP API + + +## Status +In MQTT awtrix send its stats every 10s to `[PREFIX]/stats` +With HTTP, make GET request to `http://[IP]/api/stats` + + +## Add custom app + create custom apps or notifications to display your own text and icons. + Have a look at [this section](custom?id=custom-apps-and-notifications) + +| Topic | URL | Payload/Body | HTTP Header | HTTP method | +| --- | --- | --- |--- |--- | +| `[PREFIX]/custom/[appname]` |`http://[IP]/api/custom` | JSON | name = [appname] | POST | ## Dismiss Notification Dismiss a notification which was set to "hold"=true. -| Topic | Payload | -| --- | --- | -| `[PREFIX]/notify/dismiss` | empty payload | +| Topic | URL | Payload/Body | HTTP method | +| --- | --- | --- | --- | +| `[PREFIX]/custom/[appname]` |`http://[IP]/api/notify/dismiss` | empty payload/body | POST | ## Switch Apps Switch to next or previous app. -| Topic | Payload | -| --- | --- | -| `[PREFIX]/nextapp` | empty payload | -| `[PREFIX]/previousapp` | empty payload | +| Topic | URL | Payload/Body | HTTP method | +| --- | --- | --- | --- | +| `[PREFIX]/nextapp` | `http://[IP]/api/nextapp` | empty payload/body | POST | +| `[PREFIX]/previousapp` | `http://[IP]/api/previousapp` | payload/body | POST | ## Switch to Specific App Switch to a specific app by name. -| Topic | Payload | -| --- | --- | -| `[PREFIX]/switch` | `{"name":"time"}` | +| Topic | URL | Payload/Body | HTTP method | +| --- | --- | --- | --- | +| `[PREFIX]/switch` | `http://[IP]/api/switch` | `{"name":"time"}` | POST | Built-in app names are: - `time` @@ -34,9 +48,9 @@ For custom apps, use the name you set in the topic. For example, if `[PREFIX]/cu ## Add/remove and rearange apps -| Topic | -| --- | -| `[PREFIX]/apps` | +| Topic | URL | Payload/Body | HTTP method | +| --- | --- | --- | --- | +| `[PREFIX]/apps`|`http://[IP]/api/apps`| json | POST | !> This function provides users with the ability to manage the apps on their device by adding, removing, and rearranging them. However, as it is an experimental feature, caution should be exercised, particularly when attempting to rearrange multiple apps at once, as this can lead to unintended consequences due to the resulting shifts in position of other apps. @@ -98,15 +112,21 @@ In this example, - The "bat" app is inactive and will be removed, - and the "github" app is active and should be displayed in position 4. +## Add timer + create custom apps or notifications to display your own text and icons. + have a look at [this section](custom) +| Topic | URL | Payload/Body |HTTP method | +| --- | --- | --- |--- | +| `[PREFIX]/custom/[appname]` |`http://[IP]/api/notify/dismiss` | empty payload/body | POST | ## Change Settings Change various settings related to the app display. -| Topic | Payload | -| --- | --- | -| `[PREFIX]/settings` | JSON properties | +| Topic | URL | Payload/Body |HTTP method | +| --- | --- | --- |--- | +| `[PREFIX]/settings` |`http://[IP]/api/settings`| JSON | POST | Each property is optional; you do not need to send all. diff --git a/docs/custom.md b/docs/custom.md index c7a320e..64eecf7 100644 --- a/docs/custom.md +++ b/docs/custom.md @@ -1,7 +1,9 @@ -# Custom Apps & Notifications +# Custom Apps and Notifications -With AWTRIX Light, you can create custom apps or notifications to display your own text and icons. -Simply send a JSON object to the topic "awtrixlight/custom/[page]" where [page] is a the name of your page (without spaces). +With AWTRIX Light, you can create custom apps or notifications to display your own text and icons. + +With MQTT simply send a JSON object to the topic `[PREFIX]/custom/[page]` where [page] is a the name of your page (without spaces). +With the [HTTP API](api?id=add-custom-app) you have to set the appname in the request header (`name = Appname`) ## JSON Properties @@ -9,7 +11,7 @@ The JSON object has the following properties: | Key | Type | Description | Default | | --- | ---- | ----------- | ------- | -| `pos` | number | defines the position of your custompage in the loop, starting at 0 for the first position. This will only apply with your first push. You cant change the position afterwards with [this function](mqtt?id=addremove-and-rearange-apps) | +| `pos` | number | defines the position of your custompage in the loop, starting at 0 for the first position. This will only apply with your first push. You cant change the position afterwards with [this function](api?id=addremove-and-rearange-apps) | | `text` | string | The text to display on the page. | | | `icon` | string | The icon ID or filename (without extension) to display on the page. | | | `repeat` | number | Sets how many times the text should be scrolled through the matrix before the display ends. | 1 | @@ -41,5 +43,6 @@ Here's an example JSON object to display the text "Hello, AWTRIX Light!" with th } ``` -## Delete a custom page -To delelte a custom page simply send a empty payload to the same topic +## Delete a custom app +To delete a custom app simply send a empty payload/body to the same topic/url. +You can also use [this API](api?id=addremove-and-rearange-apps) diff --git a/src/DisplayManager.cpp b/src/DisplayManager.cpp index 958d9a7..d0aa5b9 100644 --- a/src/DisplayManager.cpp +++ b/src/DisplayManager.cpp @@ -514,6 +514,7 @@ void DisplayManager_::loadNativeApps() void DisplayManager_::setup() { + TJpgDec.setCallback(jpg_output); FastLED.addLeds(leds, MATRIX_WIDTH * MATRIX_HEIGHT); gif.setMatrix(&matrix); diff --git a/src/Globals.cpp b/src/Globals.cpp index 549de3d..46fc48d 100644 --- a/src/Globals.cpp +++ b/src/Globals.cpp @@ -116,7 +116,7 @@ IPAddress gateway; IPAddress subnet; IPAddress primaryDNS; IPAddress secondaryDNS; -const char *VERSION = "0.45"; +const char *VERSION = "0.46"; String MQTT_HOST = ""; uint16_t MQTT_PORT = 1883; String MQTT_USER; diff --git a/src/MenuManager.cpp b/src/MenuManager.cpp index 55f8b4e..1abb672 100644 --- a/src/MenuManager.cpp +++ b/src/MenuManager.cpp @@ -44,11 +44,10 @@ const char *menuItems[] PROGMEM = { "TEMP", "APPS", "SOUND", - "VOLUME", "UPDATE"}; int8_t menuIndex = 0; -uint8_t menuItemCount = 14; +uint8_t menuItemCount = 13; const char *timeFormat[] PROGMEM = { "%H:%M:%S", @@ -374,8 +373,9 @@ void MenuManager_::selectButton() case 12: #ifdef AWTRIX_UPGRADE currentState = VolumeMenu; + break; #endif - break; + case 13: if (FirmwareVersionCheck()) { diff --git a/src/ServerManager.cpp b/src/ServerManager.cpp index 3fde180..bd322d4 100644 --- a/src/ServerManager.cpp +++ b/src/ServerManager.cpp @@ -123,13 +123,14 @@ void ServerManager_::setup() { WiFi.config(local_IP, gateway, subnet, primaryDNS, secondaryDNS); } - IPAddress myIP = mws.startWiFi(10000, uniqueID, "12345678"); + myIP = mws.startWiFi(10000, uniqueID, "12345678"); + isConnected = !(myIP == IPAddress(192, 168, 4, 1)); Serial.println(myIP.toString()); if (isConnected) { - + mws.addOptionBox("Network"); mws.addOption("Static IP", NET_STATIC); mws.addOption("Local IP", NET_IP); diff --git a/src/ServerManager.h b/src/ServerManager.h index 5c898fe..d86ef03 100644 --- a/src/ServerManager.h +++ b/src/ServerManager.h @@ -14,6 +14,7 @@ public: void tick(); void loadSettings(); bool isConnected; + IPAddress myIP; }; extern ServerManager_ &ServerManager; diff --git a/src/main.cpp b/src/main.cpp index 18a0b5f..18b845a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -61,15 +61,10 @@ void setup() delay(500); Serial.begin(9600); loadSettings(); - Serial.println("1"); ServerManager.loadSettings(); - Serial.println("2"); DisplayManager.setup(); - Serial.println("3"); DisplayManager.HSVtext(9, 6, VERSION, true); - Serial.println("4"); delay(500); - Serial.println("5"); PeripheryManager.playBootSound(); xTaskCreatePinnedToCore(BootAnimation, "Task", 10000, NULL, 1, &taskHandle, 1); ServerManager.setup(); @@ -78,13 +73,20 @@ void setup() { MQTTManager.setup(); DisplayManager.loadNativeApps(); + StopTask = true; + float x = 4; + while (x >= -85) + { + DisplayManager.HSVtext(x, 6, ("AWTRIX " + ServerManager.myIP.toString()).c_str(), true); + x -= 0.18; + } } else { AP_MODE = true; + StopTask = true; } - StopTask = true; delay(200); DisplayManager.clearMatrix(); } From a4f14a58c1ca2fb19d15f7b1c2582eb056f2fcab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20M=C3=BChl?= <31169771+Blueforcer@users.noreply.github.com> Date: Sat, 1 Apr 2023 21:42:08 +0200 Subject: [PATCH 7/7] update docs --- docs/_sidebar.md | 1 + docs/custom.md | 2 +- docs/dev.md | 15 ++++++++ docs/onscreen.md | 1 + src/Globals.cpp | 5 +++ src/ServerManager.cpp | 80 ------------------------------------------- 6 files changed, 23 insertions(+), 81 deletions(-) create mode 100644 docs/dev.md diff --git a/docs/_sidebar.md b/docs/_sidebar.md index 1f29159..bd6b350 100644 --- a/docs/_sidebar.md +++ b/docs/_sidebar.md @@ -14,6 +14,7 @@ - [Timer](timer.md) - [Icons](icons.md) - [Sounds](sounds.md) + - [Hidden features](dev.md) - API - [MQTT/HTTP](api.md) diff --git a/docs/custom.md b/docs/custom.md index 64eecf7..d2d5345 100644 --- a/docs/custom.md +++ b/docs/custom.md @@ -45,4 +45,4 @@ Here's an example JSON object to display the text "Hello, AWTRIX Light!" with th ## Delete a custom app To delete a custom app simply send a empty payload/body to the same topic/url. -You can also use [this API](api?id=addremove-and-rearange-apps) +You can also use [this API](api?id=addremove-and-rearange-apps) \ No newline at end of file diff --git a/docs/dev.md b/docs/dev.md new file mode 100644 index 0000000..84e92f2 --- /dev/null +++ b/docs/dev.md @@ -0,0 +1,15 @@ +# Hidden Features + +Ok, now they are no longer hidden :). +This section contains small setting options that the majority of users do not change or change very rarely and therefore saved the effort of creating an elaborate settings interface. + +Create a `dev.json` in your filemanager. + +## JSON Properties + +The JSON object has the following properties: + +| Key | Type | Description | Default | +| --- | ---- | ----------- | ------- | +| `bootsound` | string | Uses a custom melodie from the MELODIES folder | standart | +| `uppercase` | boolean | Print every character in uppercase | true | diff --git a/docs/onscreen.md b/docs/onscreen.md index caa5f0f..57549bd 100644 --- a/docs/onscreen.md +++ b/docs/onscreen.md @@ -18,5 +18,6 @@ Hold down the middle button for 2s to exit the current menu and to save your set | `WEEKDAY` | Allows selection of start of week. | | `TEMP` | Allows selection of temperature system (°C or °F). | | `APPS` | Allows to enable or disable internal apps | +| `SOUND` | Allows to enable or disable sound output | | `UPDATE` | Check and download new firmware if available. | diff --git a/src/Globals.cpp b/src/Globals.cpp index 46fc48d..985bb2b 100644 --- a/src/Globals.cpp +++ b/src/Globals.cpp @@ -51,6 +51,11 @@ void loadDevSettings() BOOT_SOUND = doc["bootsound"].as(); } + if (doc.containsKey("bootsound")) + { + UPPERCASE_LETTERS = doc["uppercase"].as(); + } + file.close(); } diff --git a/src/ServerManager.cpp b/src/ServerManager.cpp index bd322d4..f34edab 100644 --- a/src/ServerManager.cpp +++ b/src/ServerManager.cpp @@ -37,83 +37,6 @@ void saveHandler() webRequest->send(200); } -void handleAPIRequest() -{ - WebServerClass *webRequest = mws.getRequest(); - String url = webRequest->uri(); - url.replace("/api", ""); - if (webRequest->method() == HTTP_POST) - { - String body = webRequest->arg("plain"); - const char *bodyPtr = body.c_str(); - webRequest->send(200); - if (url == "/notify") - { - if (body[0] != '{' || body[strlen(bodyPtr) - 1] != '}') - { - webRequest->send(400, "text/plain", "Invalid payload format"); - return; - } - DisplayManager.generateNotification(bodyPtr); - } - - else if (url == "/timer") - { - DisplayManager.gererateTimer(bodyPtr); - } - - else if (url == "/notify/dismiss") - { - DisplayManager.dismissNotify(); - } - - else if (url == "/apps") - { - DisplayManager.updateAppVector(bodyPtr); - } - - else if (url == "/switch") - { - DisplayManager.switchToApp(bodyPtr); - } - - else if (url == "/settings") - { - DisplayManager.setNewSettings(bodyPtr); - } - - else if (url == "/nextapp") - { - DisplayManager.nextApp(); - } - - else if (url == "/previousapp") - { - DisplayManager.previousApp(); - } - - else if (url.startsWith("/custom")) - { - String topic_str = url.substring(MQTT_PREFIX.length() + 7); - DisplayManager.generateCustomPage(topic_str, bodyPtr); - } - else - { - webRequest->send(400); - } - } - else if (webRequest->method() == HTTP_GET) - { - if (url == "/stats") - { - webRequest->sendContent(DisplayManager.getStat()); - } - else - { - webRequest->send(400); - } - } -} void ServerManager_::setup() { @@ -153,8 +76,6 @@ void ServerManager_::setup() mws.addHTML(custom_html, "icon_html"); mws.addCSS(custom_css); mws.addJavascript(custom_script); - mws.addOptionBox("General"); - mws.addOption("Uppercase letters", UPPERCASE_LETTERS); mws.addHandler("/save", HTTP_POST, saveHandler); mws.addHandler("/api/notify", HTTP_POST, []() {DisplayManager.generateNotification(mws.webserver->arg("plain").c_str()); mws.webserver->send(200,"OK"); }); @@ -266,7 +187,6 @@ void ServerManager_::loadSettings() NET_SN = doc["Subnet"].as(); NET_PDNS = doc["Primary DNS"].as(); NET_SDNS = doc["Secondary DNS"].as(); - UPPERCASE_LETTERS = doc["Uppercase letters"]; file.close(); DisplayManager.applyAllSettings(); Serial.println(F("Configuration loaded"));