commit 37431bffecdd2db87ae82ead00436d8faf3f26fb Author: bendtherules Date: Mon Nov 27 23:13:56 2023 +0530 Init project diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..46699c3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +.pio/* +!.pio/build +.pio/build/* +!.pio/build/esp12e +.pio/build/esp12e/* +!.pio/build/esp12e/firmware.bin + +.vscode/.browse.c_cpp.db* +.vscode/c_cpp_properties.json +.vscode/launch.json +.vscode/ipch + +.DS_Store \ No newline at end of file diff --git a/.pio/build/esp12e/firmware.bin b/.pio/build/esp12e/firmware.bin new file mode 100644 index 0000000..af81808 Binary files /dev/null and b/.pio/build/esp12e/firmware.bin differ diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..080e70d --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,10 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 + // for the documentation about the extensions.json format + "recommendations": [ + "platformio.platformio-ide" + ], + "unwantedRecommendations": [ + "ms-vscode.cpptools-extension-pack" + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..5e09a03 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "files.associations": { + "chrono": "cpp" + } +} \ No newline at end of file diff --git a/include/README b/include/README new file mode 100644 index 0000000..194dcd4 --- /dev/null +++ b/include/README @@ -0,0 +1,39 @@ + +This directory is intended for project header files. + +A header file is a file containing C declarations and macro definitions +to be shared between several project source files. You request the use of a +header file in your project source file (C, C++, etc) located in `src` folder +by including it, with the C preprocessing directive `#include'. + +```src/main.c + +#include "header.h" + +int main (void) +{ + ... +} +``` + +Including a header file produces the same results as copying the header file +into each source file that needs it. Such copying would be time-consuming +and error-prone. With a header file, the related declarations appear +in only one place. If they need to be changed, they can be changed in one +place, and programs that include the header file will automatically use the +new version when next recompiled. The header file eliminates the labor of +finding and changing all the copies as well as the risk that a failure to +find one copy will result in inconsistencies within a program. + +In C, the usual convention is to give header files names that end with `.h'. +It is most portable to use only letters, digits, dashes, and underscores in +header file names, and at most one dot. + +Read more about using header files in official GCC documentation: + +* Include Syntax +* Include Operation +* Once-Only Headers +* Computed Includes + +https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html diff --git a/include/buzzer.h b/include/buzzer.h new file mode 100644 index 0000000..b416398 --- /dev/null +++ b/include/buzzer.h @@ -0,0 +1,11 @@ +#include + +enum TONE_TYPE { + TONE_BEEP, + TONE_BEEP_TWICE, + TONE_BEEP_ONE_EIGHT, + TONE_BEEP_LONG, + TONE_SARE_JAHA_SE_ACCHA, +}; + +void playBuzzer(uint8_t pin, TONE_TYPE toneType); diff --git a/include/myDisplay.h b/include/myDisplay.h new file mode 100644 index 0000000..5bee5f7 --- /dev/null +++ b/include/myDisplay.h @@ -0,0 +1,9 @@ +#include + +enum DISPLAY_POSITION { + POSITION_LEFT, + POSITION_RIGHT, +}; + +void setupDisplay(); +void showNumber(uint8_t number); \ No newline at end of file diff --git a/include/myOTA.h b/include/myOTA.h new file mode 100644 index 0000000..594adf7 --- /dev/null +++ b/include/myOTA.h @@ -0,0 +1,4 @@ +#include + +void setupOTA(); +void handleOTA(); \ No newline at end of file diff --git a/include/networkCredentials.h b/include/networkCredentials.h new file mode 100644 index 0000000..c27e9a1 --- /dev/null +++ b/include/networkCredentials.h @@ -0,0 +1,2 @@ +#define WIFI_SSID "Wifi name" +#define WIFI_PASSWORD "Pass" diff --git a/lib/README b/lib/README new file mode 100644 index 0000000..6debab1 --- /dev/null +++ b/lib/README @@ -0,0 +1,46 @@ + +This directory is intended for project specific (private) libraries. +PlatformIO will compile them to static libraries and link into executable file. + +The source code of each library should be placed in a an own separate directory +("lib/your_library_name/[here are source files]"). + +For example, see a structure of the following two libraries `Foo` and `Bar`: + +|--lib +| | +| |--Bar +| | |--docs +| | |--examples +| | |--src +| | |- Bar.c +| | |- Bar.h +| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html +| | +| |--Foo +| | |- Foo.c +| | |- Foo.h +| | +| |- README --> THIS FILE +| +|- platformio.ini +|--src + |- main.c + +and a contents of `src/main.c`: +``` +#include +#include + +int main (void) +{ + ... +} + +``` + +PlatformIO Library Dependency Finder will find automatically dependent +libraries scanning project source files. + +More information about PlatformIO Library Dependency Finder +- https://docs.platformio.org/page/librarymanager/ldf.html diff --git a/platformio.ini b/platformio.ini new file mode 100644 index 0000000..c702f31 --- /dev/null +++ b/platformio.ini @@ -0,0 +1,21 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + +[env:esp12e] +platform = espressif8266 +board = esp12e +framework = arduino +lib_deps = + fastled/FastLED@^3.5.0 + crankyoldgit/IRremoteESP8266@^2.8.5 + enjoyneering/LiquidCrystal_I2C@^1.4.0 +monitor_speed = 115200 +upload_protocol = espota +upload_port = 192.168.29.35 diff --git a/src/buzzer.cpp b/src/buzzer.cpp new file mode 100644 index 0000000..fbf4fe4 --- /dev/null +++ b/src/buzzer.cpp @@ -0,0 +1,159 @@ +#include + +const float songSpeed = 1.0; +#define NOTE_D3 147 +#define NOTE_C4 262 +#define NOTE_D4 294 +#define NOTE_E4 330 +#define NOTE_F4 349 +#define NOTE_G4 392 +#define NOTE_G_black_4 415 +#define NOTE_A4 440 +#define NOTE_A_black_4 466 +#define NOTE_B4 494 +#define NOTE_C5 523 +#define NOTE_C_black_5 554 +#define NOTE_D5 587 +#define NOTE_D_black_5 622 +#define NOTE_E5 659 +#define NOTE_F5 698 +#define NOTE_F_black_5 740 +#define NOTE_G5 784 +#define NOTE_G_black_5 830 +#define NOTE_A5 880 +#define NOTE_A_black_5 932 +#define NOTE_B5 988 +#define NOTE_D6 1175 + +#define rest 10 + +enum TONE_TYPE { + TONE_BEEP, + TONE_BEEP_TWICE, + TONE_BEEP_ONE_EIGHT, + TONE_BEEP_LONG, + TONE_SARE_JAHA_SE_ACCHA, +}; + +void playBuzzer(uint8_t pin, TONE_TYPE toneType) { + // Music notes of the song, 0 is a rest/pulse + int notes[] = { + // NOTE_E5,0,NOTE_E5,0, + // NOTE_D_black_5,0,NOTE_C_black_5,0,NOTE_D_black_5, + // 0,NOTE_C_black_5,0,NOTE_C_black_5,0, + + // NOTE_G_black_4,0,NOTE_A_black_4,0,NOTE_C_black_5,0,NOTE_D_black_5, + // 0,NOTE_F5,0,NOTE_F_black_5,0,NOTE_F5,0,NOTE_F5,0, + + // NOTE_F5,0,NOTE_F_black_5,0,NOTE_G_black_5,0,NOTE_F_black_5,0, + // NOTE_F5,0,NOTE_F_black_5,0,NOTE_A_black_5,0,NOTE_G_black_5,0, + + // NOTE_F5,0,NOTE_F_black_5,0,NOTE_G_black_5,0, + // NOTE_F_black_5,0,NOTE_E5,0,NOTE_D_black_5,0, + // NOTE_C_black_5,0,NOTE_C_black_5,0,NOTE_C5,0, + // NOTE_A_black_4,0,NOTE_G_black_4,0, + + + // NOTE_E5,0,NOTE_E5,0, + // NOTE_D_black_5,0,NOTE_C_black_5,0,NOTE_D_black_5, + // 0,NOTE_C_black_5,0,NOTE_C_black_5,0, + + // NOTE_G_black_4,0,NOTE_A_black_4,0,NOTE_C_black_5,0,NOTE_D_black_5, + // 0,NOTE_F5,0,NOTE_F_black_5,0,NOTE_F5,0,NOTE_F5,0, + + // NOTE_F5,0,NOTE_F_black_5,0,NOTE_G_black_5,0,NOTE_F_black_5,0, + // NOTE_F5,0,NOTE_F_black_5,0,NOTE_A_black_5,0,NOTE_G_black_5,0, + + NOTE_F5,0,NOTE_F_black_5,0,NOTE_G_black_5,0, + NOTE_F_black_5,0,NOTE_E5,0,NOTE_D_black_5,0, + NOTE_C_black_5,0,NOTE_C_black_5,0,NOTE_C5,0, + NOTE_A_black_4,0,NOTE_G_black_4,0, + }; + // Durations (in ms) of each music note of the song + // Quarter Note is 250 ms when songSpeed = 1.0 + int durations[] = { + // 300,200,200,300, + // 200,100,200,300,100, + // 100,250,200,250,400, + + // 200,100,200,100,200,300,100, + // 10,300,200,300,300,250,300,200,400, + + // 200,100,200,100,250,300,250,200, + // 200,100,200,100,250,100,300,200, + + // 200,100,200,100,250,300, + // 200,100,300,300,200,100, + // 300,300,300,300,200,100, + // 200,100,300,400, + + // 300,200,200,300, + // 200,100,200,300,100, + // 100,250,200,250,400, + + // 200,100,200,100,200,300,100, + // 10,300,200,300,300,250,300,200,400, + + // 200,100,200,100,250,300,250,200, + // 200,100,200,100,250,100,300,200, + + 200,100,200,100,250,300, + 200,100,300,300,200,100, + 300,300,300,300,200,100, + 200,100,300,400, + + }; + + pinMode(pin, OUTPUT); + if (toneType == TONE_SARE_JAHA_SE_ACCHA) { + const int totalNotes = sizeof(notes) / sizeof(int); + // Loop through each note + for (int i = 0; i < totalNotes; i++) + { + const int currentNote = notes[i]; + float wait = durations[i] / songSpeed; + // Play tone if currentNote is not 0 frequency, otherwise pause (noTone) + if (currentNote != 0) + { + tone(pin, notes[i], wait); // tone(pin, frequency, duration) + } + else + { + noTone(pin); + } + // delay is used to wait for tone to finish playing before moving to next loop + delay(wait); + } + noTone(pin); + } else if (toneType == TONE_BEEP) { + digitalWrite(pin, HIGH); + delay(100); + digitalWrite(pin, LOW); + } else if (toneType == TONE_BEEP_TWICE) { + digitalWrite(pin, HIGH); + delay(80); + digitalWrite(pin, LOW); + delay(50); + digitalWrite(pin, HIGH); + delay(80); + digitalWrite(pin, LOW); + } else if (toneType == TONE_BEEP_ONE_EIGHT) { + { + digitalWrite(pin, HIGH); + delay(400); + digitalWrite(pin, LOW); + delay(200); + } + for (size_t tmpIndex = 0; tmpIndex < 8; tmpIndex++) + { + digitalWrite(pin, HIGH); + delay(80); + digitalWrite(pin, LOW); + delay(40); + } + } else if (toneType == TONE_BEEP_LONG) { + digitalWrite(pin, HIGH); + delay(500); + digitalWrite(pin, LOW); + } +} diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..2af2545 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,213 @@ +#include +#include "buzzer.h" +#include "myOTA.h" +#include "myDisplay.h" +#include +#include +#include +#include +#include +#include + +#define LED_BUILTIN D4 + +// BUZZER Setup +#define BUZZER_PIN D7 + +// IR Remote +const uint8_t kRecvPin = D6; +const uint16_t kCaptureBufferSize = 1024; +#if DECODE_AC +// Some A/C units have gaps in their protocols of ~40ms. e.g. Kelvinator +// A value this large may swallow repeats of some protocols +const uint8_t kTimeout = 50; +#else // DECODE_AC +// Suits most messages, while not swallowing many repeats. +const uint8_t kTimeout = 15; +#endif // DECODE_AC + +const uint16_t kMinUnknownSize = 12; +const uint8_t kTolerancePercentage = 40; +#define LEGACY_TIMING_INFO false + +IRrecv irrecv(kRecvPin, kCaptureBufferSize, kTimeout, true); + +decode_results results; + +unsigned long KEYPAD_NUMBER_MAX_DELAY = 2000; + +#define NUMBER_DEFAULT 1 +uint8_t currentNumber = NUMBER_DEFAULT; + +// Color remote codes +// const String KEY_1 = "0xF710EF"; +// const String KEY_2 = "0xF7906F"; +// const String KEY_3 = "0xF750AF"; +// const String KEY_4 = "0xF730CF"; +// const String KEY_5 = "0xF7B04F"; +// const String KEY_6 = "0xF7708F"; +// const String KEY_7 = "0xF708F7"; +// const String KEY_8 = "0xF78877"; +// const String KEY_9 = "0xF748B7"; +// const String KEY_0 = "0xF7A857"; +// const String KEY_A = "0xF7D02F"; +// const String KEY_B = "0xF7F00F"; +// const String KEY_C = "0xF7C837"; +// const String KEY_D = "0xF7E817"; +// const String KEY_ON = "0xF7C03F"; +// const String KEY_OFF = "0xF740BF"; + +// Numerical remote code +const String KEY_1 = "0x1FE50AF"; +const String KEY_2 = "0x1FED827"; +const String KEY_3 = "0x1FEF807"; +const String KEY_4 = "0x1FE30CF"; +const String KEY_5 = "0x1FEB04F"; +const String KEY_6 = "0x1FE708F"; +const String KEY_7 = "0x1FE00FF"; +const String KEY_8 = "0x1FEF00F"; +const String KEY_9 = "0x1FE9867"; +const String KEY_0 = "0x1FEE01F"; +const String KEY_A = "0x1FEC03F"; +const String KEY_B = "0x1FE40BF"; +const String KEY_C = "0x1FE807F"; +const String KEY_D = "0x1FE20DF"; +const String KEY_ON = "0x1FE48B7"; +const String KEY_OFF = "0x1FE48B7"; + + +char lastPressedKey = '\0'; +long lastMillis = millis(); +bool shouldIgnoreLast = false; +void handleKeyPress(char pressedKey) { + long currentMillis = millis(); + bool isSecondKeyPress = (currentMillis - lastMillis) < KEYPAD_NUMBER_MAX_DELAY; + if (pressedKey) { + Serial.printf("Pressed: %c\n", pressedKey); + if (pressedKey == 'A') { + currentNumber = (currentNumber < 99) ? (currentNumber + 1): 99; + Serial.printf("currentNumber: %d\n", currentNumber); + playBuzzer(BUZZER_PIN, TONE_BEEP); + showNumber(currentNumber); + } + if (pressedKey == 'B') { + currentNumber = (currentNumber > 0) ? (currentNumber - 1): 0; + Serial.printf("currentNumber: %d\n", currentNumber); + playBuzzer(BUZZER_PIN, TONE_BEEP); + showNumber(currentNumber); + } + if (pressedKey == 'C') { + playBuzzer(BUZZER_PIN, TONE_SARE_JAHA_SE_ACCHA); + } + if (pressedKey == 'D') { + currentNumber = NUMBER_DEFAULT; + Serial.printf("currentNumber: %d\n", currentNumber); + playBuzzer(BUZZER_PIN, TONE_BEEP); + showNumber(currentNumber); + } + if (pressedKey == 'R') { + Serial.println("Pressed restart. Rstarting.."); + Serial.flush(); + playBuzzer(BUZZER_PIN, TONE_BEEP_LONG); + ESP.restart(); + } + // If pressed number + uint8_t currentNumberEntered = pressedKey - '0'; + uint8_t lastNumberEntered = lastPressedKey - '0'; + if (currentNumberEntered <= 9) { + if (isSecondKeyPress && (lastNumberEntered <= 9) && !shouldIgnoreLast) { + currentNumberEntered = lastNumberEntered*10 + currentNumberEntered; + Serial.printf("Second number, total: %d, lastPressedKey:%c\n", currentNumberEntered, lastPressedKey); + playBuzzer(BUZZER_PIN, TONE_BEEP_TWICE); + // Stop 3rd number from adding to 2nd number + shouldIgnoreLast = true; + } else { + Serial.printf("First number, total: %d\n", currentNumberEntered); + playBuzzer(BUZZER_PIN, TONE_BEEP); + shouldIgnoreLast = false; + } + currentNumber = currentNumberEntered; + showNumber(currentNumber); + } + } +} + +void setup() { + Serial.begin(115200); + setupDisplay(); + + showNumber(currentNumber); + + // playBuzzer(BUZZER_PIN); + + assert(irutils::lowLevelSanityCheck() == 0); + Serial.printf("\n" D_STR_IRRECVDUMP_STARTUP "\n", kRecvPin); + #if DECODE_HASH + // Ignore messages with less than minimum on or off pulses. + irrecv.setUnknownThreshold(kMinUnknownSize); + #endif // DECODE_HASH + irrecv.setTolerance(kTolerancePercentage); // Override the default tolerance. + irrecv.enableIRIn(); // Start the receiver + + setupOTA(); +} + +void loop() { + // Check if the IR code has been received. + if (!shouldIgnoreLast && (millis() - lastMillis > KEYPAD_NUMBER_MAX_DELAY)) { + playBuzzer(BUZZER_PIN, TONE_BEEP_TWICE); + shouldIgnoreLast = true; + } + if (irrecv.decode(&results)) { + // Display the basic output of what we found. + Serial.print(resultToHumanReadableBasic(&results)); + Serial.println(); // Blank line between entries + + char pressedKey = '\0'; // default ignore + if (results.decode_type == NEC) { + String hexKey = resultToHexidecimal(&results); + Serial.printf("Received hex: %S\n", hexKey); + if (hexKey == KEY_1) { + pressedKey = '1'; + } else if (hexKey == KEY_2) { + pressedKey = '2'; + } else if (hexKey == KEY_3) { + pressedKey = '3'; + } else if (hexKey == KEY_4) { + pressedKey = '4'; + } else if (hexKey == KEY_5) { + pressedKey = '5'; + } else if (hexKey == KEY_6) { + pressedKey = '6'; + } else if (hexKey == KEY_7) { + pressedKey = '7'; + } else if (hexKey == KEY_8) { + pressedKey = '8'; + } else if (hexKey == KEY_9) { + pressedKey = '9'; + } else if (hexKey == KEY_0) { + pressedKey = '0'; + } else if (hexKey == KEY_A) { + pressedKey = 'A'; + } else if (hexKey == KEY_B) { + pressedKey = 'B'; + } else if (hexKey == KEY_C) { + pressedKey = 'C'; + } else if (hexKey == KEY_D) { + pressedKey = 'D'; + } else if (hexKey == KEY_ON) { + pressedKey = 'R'; + } else if (hexKey == KEY_OFF) { + pressedKey = 'R'; + } + if (pressedKey != '\0') { + handleKeyPress(pressedKey); + } + lastPressedKey = pressedKey; + lastMillis = millis(); + } + yield(); // Feed the WDT (again) + } + + handleOTA(); +} diff --git a/src/myDisplay.cpp b/src/myDisplay.cpp new file mode 100644 index 0000000..5487dd8 --- /dev/null +++ b/src/myDisplay.cpp @@ -0,0 +1,205 @@ +#include +#include +#include + +// How many leds in your strip? +#define NUM_LEDS 65 + +// Skip indicator led +#define SKIP_LEDS 1 + + +// For led chips like WS2812, which have a data line, ground, and power, you just +// need to define DATA_PIN. +#define DATA_PIN D8 + +// Effects +#define FONT_WIDTH 4 +#define FONT_HEIGHT 8 +#define LED_WIDTH 8 +#define LED_HEIGHT 8 + +CRGB myRed = CRGB(255, 10, 10); +CRGB myPink = CRGB(255, 30, 10); +CRGB myBlue = CRGB(10, 10, 250); + +// Define the array of leds +CRGB leds[NUM_LEDS]; + +// LCD setup +#define LCD_COLUMNS 16 +#define LCD_ROWS 2 +#define PAGE ((LCD_COLUMNS) * (LCD_ROWS)) +LiquidCrystal_I2C lcd(PCF8574_ADDR_A21_A11_A01, 4, 5, 6, 16, 11, 12, 13, 14, POSITIVE); + +bool FONT_NUMBERS[10][FONT_HEIGHT][FONT_WIDTH] = { + { // 0 + {1, 1, 1, 1}, + {1, 0, 0, 1}, + {1, 0, 0, 1}, + {1, 0, 0, 1}, + {1, 0, 0, 1}, + {1, 0, 0, 1}, + {1, 0, 0, 1}, + {1, 1, 1, 1}, + }, + { // 1 + {0, 0, 1, 0}, + {0, 1, 1, 0}, + {1, 0, 1, 0}, + {0, 0, 1, 0}, + {0, 0, 1, 0}, + {0, 0, 1, 0}, + {0, 0, 1, 0}, + {1, 1, 1, 1}, + }, + { // 2 + {1, 1, 1, 1}, + {1, 0, 0, 1}, + {0, 0, 0, 1}, + {0, 0, 0, 1}, + {1, 1, 1, 1}, + {1, 0, 0, 0}, + {1, 0, 0, 0}, + {1, 1, 1, 1}, + }, + { // 3 + {0, 1, 1, 1}, + {0, 0, 0, 1}, + {0, 0, 0, 1}, + {0, 1, 1, 1}, + {0, 1, 1, 1}, + {0, 0, 0, 1}, + {0, 0, 0, 1}, + {0, 1, 1, 1}, + }, + { // 4 + {1, 0, 0, 0}, + {1, 0, 0, 0}, + {1, 0, 1, 0}, + {1, 0, 1, 0}, + {1, 1, 1, 1}, + {0, 0, 1, 0}, + {0, 0, 1, 0}, + {0, 0, 1, 0}, + }, + { // 5 + {1, 1, 1, 1}, + {1, 0, 0, 0}, + {1, 0, 0, 0}, + {1, 1, 1, 1}, + {0, 0, 0, 1}, + {0, 0, 0, 1}, + {1, 0, 0, 1}, + {1, 1, 1, 1}, + }, + { // 6 + {0, 1, 1, 0}, + {1, 0, 0, 1}, + {1, 0, 0, 0}, + {1, 1, 1, 0}, + {1, 0, 0, 1}, + {1, 0, 0, 1}, + {1, 0, 0, 1}, + {0, 1, 1, 0}, + }, + { // 7 + {1, 1, 1, 1}, + {1, 0, 0, 1}, + {0, 0, 0, 1}, + {0, 0, 1, 0}, + {0, 1, 0, 0}, + {0, 1, 0, 0}, + {0, 1, 0, 0}, + {0, 1, 0, 0}, + }, + { // 8 + {0, 1, 1, 0}, + {1, 0, 0, 1}, + {1, 0, 0, 1}, + {0, 1, 1, 0}, + {0, 1, 1, 0}, + {1, 0, 0, 1}, + {1, 0, 0, 1}, + {0, 1, 1, 0}, + }, + { // 9 + {0, 1, 1, 0}, + {1, 0, 0, 1}, + {1, 0, 0, 1}, + {1, 0, 0, 1}, + {0, 1, 1, 1}, + {0, 0, 0, 1}, + {1, 0, 0, 1}, + {0, 1, 1, 0}, + }, +}; + +enum DISPLAY_POSITION { + POSITION_LEFT, + POSITION_RIGHT, +}; + +void showOutsideNumberSingle(uint8_t number, DISPLAY_POSITION pos, bool show = false) { + for (size_t tmp_y = 0; tmp_y < FONT_HEIGHT; tmp_y++) + { + for (size_t tmp_x = 0; tmp_x < FONT_WIDTH; tmp_x++) + { + uint8_t ledIndex = tmp_y * LED_WIDTH + tmp_x + (pos == POSITION_LEFT ? 0 : FONT_WIDTH); + leds[ledIndex + SKIP_LEDS] = FONT_NUMBERS[number][tmp_y][tmp_x] ? (pos == POSITION_LEFT ? myPink : myRed) : CRGB::Black; + } + } + if (show) { + FastLED.show(); + } +} + +void cleanDisplay() { + fill_solid(leds, NUM_LEDS, CRGB::Black); + fill_solid(leds, SKIP_LEDS, CRGB::Blue); +} + +void showOutsideNumber(uint8_t number) { + cleanDisplay(); + FastLED.show(); + + uint8_t numberRight = number % 10; + uint8_t numberLeft = min(number / 10, 9); + Serial.printf("Printing numberRight: %d, numberLeft: %d\n", numberRight, numberLeft); + showOutsideNumberSingle(numberRight, POSITION_RIGHT); + if (numberLeft > 0) { + showOutsideNumberSingle(numberLeft, POSITION_LEFT); + } + + FastLED.show(); +} + +void showInsideNumber(int number) { + lcd.clear(); + lcd.setCursor(0,0); + lcd.print(number); +} + +void showNumber(uint8_t number) { + showOutsideNumber(number); + showInsideNumber(number); +} + +void setupDisplay() { + // LED matrix setup + FastLED.addLeds(leds, NUM_LEDS); // GRB ordering is assumed + FastLED.setMaxPowerInVoltsAndMilliamps(5, 400); + FastLED.setBrightness(20); + showOutsideNumberSingle(3, POSITION_RIGHT, true); + delay(10); + cleanDisplay(); + FastLED.show(); + + // LCD setup + while (lcd.begin(LCD_COLUMNS, LCD_ROWS, LCD_5x8DOTS) != 1) //colums, rows, characters size + { + Serial.println(F("PCF8574 is not connected or lcd pins declaration is wrong. Only pins numbers: 4,5,6,16,11,12,13,14 are legal.")); + delay(5000); + } + lcd.clear(); +} diff --git a/src/myOTA.cpp b/src/myOTA.cpp new file mode 100644 index 0000000..4990238 --- /dev/null +++ b/src/myOTA.cpp @@ -0,0 +1,42 @@ +#include +#include +#include +#include +#include +#include + +void setupOTA() { + Serial.println("Booting"); + WiFi.mode(WIFI_STA); + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); + while (WiFi.waitForConnectResult() != WL_CONNECTED) { + Serial.println("Connection Failed! Rebooting..."); + delay(5000); + ESP.restart(); + } + ArduinoOTA.onStart([]() { + Serial.println("Start"); + }); + ArduinoOTA.onEnd([]() { + Serial.println("\nEnd"); + }); + ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { + Serial.printf("Progress: %u%%\r", (progress / (total / 100))); + }); + ArduinoOTA.onError([](ota_error_t error) { + Serial.printf("Error[%u]: ", error); + if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed"); + else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed"); + else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed"); + else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed"); + else if (error == OTA_END_ERROR) Serial.println("End Failed"); + }); + ArduinoOTA.begin(); + Serial.println("Ready"); + Serial.print("IP address: "); + Serial.println(WiFi.localIP()); +} + +void handleOTA() { + ArduinoOTA.handle(); +} diff --git a/test/README b/test/README new file mode 100644 index 0000000..9b1e87b --- /dev/null +++ b/test/README @@ -0,0 +1,11 @@ + +This directory is intended for PlatformIO Test Runner and project tests. + +Unit Testing is a software testing method by which individual units of +source code, sets of one or more MCU program modules together with associated +control data, usage procedures, and operating procedures, are tested to +determine whether they are fit for use. Unit testing finds problems early +in the development cycle. + +More information about PlatformIO Unit Testing: +- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html