#include <EncButton.h>
#include <GTimer.h>
#include <GyverOLED.h>
#include "GyverOLEDMenu.h"
//#include <BleKeyboard.h>
// https://wokwi.com/projects/423136754515434497
const static uint8_t icons_8x8[][8] PROGMEM = {
{ 0x3c, 0x42, 0xa1, 0x91, 0x89, 0x85, 0x42, 0x3c }, //84 block -> 0
{ 0x00, 0x42, 0x24, 0x18, 0xff, 0x99, 0x66, 0x00 }, //8 bluetooth -> 1
{ 0xff, 0xff, 0xff, 0x7e, 0x7e, 0x3c, 0x3c, 0x18 }, //27 play -> 2
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, //28 stop -> 3
{ 0x18, 0x7e, 0x7e, 0xe7, 0xe7, 0x7e, 0x7e, 0x18 }, //4 cog, settings -> 4
{ 0x3c, 0x42, 0x81, 0x9d, 0x91, 0x91, 0x42, 0x3c }, //5 clock -> 5
};
const uint8_t cam_24x24[] PROGMEM = {
0xc0, 0xe0, 0x30, 0xb8, 0xb8, 0x38, 0x38, 0x30, 0x30, 0x30, 0x1c, 0x8c, 0x8c, 0xcc, 0xcc, 0xcc, 0x8c, 0x8c, 0x1c, 0x30, 0x30, 0x30, 0xe0, 0xc0,
0xff, 0xff, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x7c, 0xfe, 0xc7, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0xc7, 0xfe, 0x38, 0x00, 0xff, 0xff,
0x0f, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x19, 0x1b, 0x13, 0x16, 0x16, 0x16, 0x13, 0x1b, 0x19, 0x18, 0x18, 0x18, 0x1f, 0x0f
};
// https://www.youtube.com/watch?v=gfzHsvtZ4U0
// BLE кнопки:
// https://community.alexgyver.ru/threads/esp32-bluetooth-media-keyboard.7656/
#define ENC_DT 19
#define ENC_CK 18
#define ENC_SW 5
#define USE_NIMBLE
GyverOLED<SSD1306_128x32, OLED_BUFFER> oled;
OledMenu<2, GyverOLED<SSD1306_128x32>> menu(&oled); // Где 2 - количество элементов в меню
EncButton enc(ENC_DT, ENC_CK, ENC_SW);
//BleKeyboard ble("SergeShutter", "stsergo", 100);
GTimer<millis> interval_timer;
GTimer<millis> onesecond_timer;
GTimer<millis> count_timer;
int duration_interval = 33; // in secs
int duration_count = -1; // if -1 - ifinite, else duration_interval*duration_count
char no_ble_text1[] = "Телефон";
char no_ble_text2[] = "не подключен!";
char wait_ble_text1[] = "Ожидаем";
char wait_text1[] = "ОЖИДАЕМ";
char wait_ble_text2[] = "подключение";
char click_text[] = "ЧПОНКЬ!";
char countdown_text[] = "";
char itrvl[]="";
char cnt[] = " ";
char hhmmss[] = "00:00/--:--";
unsigned int shutter_counter = 0;
unsigned int shutter_countdown = duration_interval;
boolean ble = true;
void setup() {
Serial.begin(115200);
Serial.println("Starting BLE work!");
//ble.begin();
interval_timer.setMode(GTMode::Interval);
interval_timer.setTime(1000 * duration_interval);
onesecond_timer.setMode(GTMode::Interval);
onesecond_timer.setTime(1000);
onesecond_timer.start();
oled.init();
//Wire.setClock(400000L); // макс. 800'000 // ускорим вывод, ВЫЗЫВАТЬ ПОСЛЕ oled.init()!!!
oled.clear();
oled.home();
showWaitBle();
// меню
menu.addItem(PSTR("Интервал"), GM_N_INT(1), &duration_interval, GM_N_INT(5), GM_N_INT(33));
menu.addItem(PSTR("Количество"), GM_N_INT(100), &duration_count, GM_N_INT(-1), GM_N_INT(2618));
menu.onChange(onItemChange, true);
enc.attach(cb);
}
void onItemChange(const int index, const void* val, const byte valType) {
if (valType == VAL_ACTION) {
if (index == 0) {
menu.showMenu(false);
}
}
}
void cb() {
switch (enc.action()) {
case EB_TURN:
if (enc.dir() == 1) {
menu.selectPrev(enc.fast());
} else {
menu.selectNext(enc.fast());
}
break;
case EB_CLICK:
menu.toggleChangeSelected();
break;
}
}
void loop() {
if (ble) {
//if(ble.isConnected()) {
enc.tick(); // Тикер энкодера
if (enc.click()) {
// запускаем или останавливаем таймер
if (interval_timer.running()) {
interval_timer.stop();
count_timer.stop();
shutter_counter = 0;
Serial.println("Останавливаем таймеры, т.к. нажата кнопочка");
} else {
Serial.println("Запускаем таймеры, т.к. нажата кнопочка");
interval_timer.start(3000);
if (!count_timer.running()) {
if (duration_count == -1) {
count_timer.start(2111111000); // infinite
} else {
count_timer.start(duration_count*duration_interval*1000);
}
}
}
}
// длинное нажатие - меню. цикл останавливается только при наличии изменений.
if (enc.releaseStep() || enc.releaseHold()) {
// показываем меню
if(menu.isMenuShowing) {
menu.showMenu(false);
oled.setScale(1);
oled.clear();
Serial.println("Прячем меню!");
}
else {
if (interval_timer.running()) {
interval_timer.stop();
count_timer.stop();
shutter_counter = 0;
}
oled.setScale(1);
oled.clear();
menu.showMenu(true);
Serial.println("Показываем меню!");
}
}
if (interval_timer) {
Serial.println("Жмем спуск");
//ble.write(KEY_MEDIA_VOLUME_UP);
interval_timer.start(1000 * duration_interval);
onesecond_timer.start(); // синхронизируем ежесекундный таймер
shutter_counter += 1;
} else if (interval_timer.running()) {
shutter_countdown = interval_timer.getLeft() / 1000;
showCountdown();
}
} else // нет подключения по BLE
{
// останавливаем таймеры, если запущены
if (interval_timer.running()) {
interval_timer.stop();
count_timer.stop();
}
// показываем на экране инфо, как подключиться
showNoBleText();
}
// отрисовываем экран по таймеру
if (onesecond_timer) {
showPlayStopIcon(); // первая, т.к. очищает весь экран
showInterval();
showBleIcon();
showTotalTime();
oled.update();
}
}
void drawIcon8x8(byte index) {
size_t s = sizeof icons_8x8[index]; //можна так, а можна просто 8
for (unsigned int i = 0; i < s; i++) {
oled.drawByte(pgm_read_byte(&(icons_8x8[index][i])));
}
}
void showNoBleText() {
if(menu.isMenuShowing) { return; }
oled.clear();
oled.home();
oled.setCursor(60, 1);
drawIcon8x8(1);
oled.setCursor(44, 2); // 44 is good
oled.autoPrintln(true);
oled.setScale(1);
oled.print(no_ble_text1);
oled.setCursor(30, 3);
oled.autoPrintln(true);
oled.setScale(1);
oled.print(no_ble_text2);
}
void showWaitBle() {
if(menu.isMenuShowing) { return; }
if (!ble){
//if(!ble.isConnected()) {
oled.clear();
oled.home();
oled.setCursor(60, 1);
drawIcon8x8(1);
oled.setCursor(44, 2); // 44 is good
oled.autoPrintln(true);
oled.setScale(1);
oled.print(wait_ble_text1);
oled.setCursor(30, 3);
oled.autoPrintln(true);
oled.setScale(1);
oled.print(wait_ble_text2);
oled.update();
}
}
void showWait() {
if(menu.isMenuShowing) { return; }
if (!interval_timer.running()){
oled.setCursorXY(44, 9); // 44 is good
oled.autoPrintln(true);
oled.setScale(1);
oled.print(wait_text1);
}
}
void showCountdown() {
if(menu.isMenuShowing) { return; }
sprintf(countdown_text, "%02d",shutter_countdown);
if (shutter_countdown == 0) {
oled.clear(0, 8, 127, 32);
oled.setCursor(8, 2);
drawIcon8x8(2);
oled.clear(0, 8, 127, 32);
oled.drawBitmap(52, 10, cam_24x24, 24, 24);
} else {
oled.clear(44,8,84,32); // clear camera
oled.setCursor(56, 2);
oled.autoPrintln(true);
oled.setScale(2);
oled.print(countdown_text);
}
}
void showPlayStopIcon() {
if(menu.isMenuShowing) { return; }
oled.clear(0, 0, 8, 8);
oled.home();
if (interval_timer.running()) {
drawIcon8x8(2); // play
}
else {
drawIcon8x8(3); // stop
oled.clear(32, 0, 98, 8); // clear total time
oled.clear(44,8,80,32); // clear countdown
oled.clear(96,24,128,32); // clear counter
showWait();
}
}
void showBleIcon() {
if(menu.isMenuShowing) { return; }
oled.clear(120,0,128,8);
oled.setCursor(120, 0);
if (ble) {
//if(ble.isConnected()) {
drawIcon8x8(1);
} else {
drawIcon8x8(0);
}
}
void showInterval() {
if(menu.isMenuShowing) { return; }
sprintf(itrvl, "%ds",duration_interval);
oled.setCursor(0, 3);
drawIcon8x8(5);
oled.setCursor(12, 3);
oled.autoPrintln(true);
oled.setScale(1);
oled.print(itrvl);
// счетчик спусков
sprintf(cnt, "%05d", shutter_counter);
oled.setCursor(96, 3);
oled.print(cnt);
}
void showTotalTime() {
if(menu.isMenuShowing) { return; }
if (count_timer.running()) {
unsigned long totalTime = count_timer.getTime();
unsigned long currentMillis = totalTime - count_timer.getLeft();
unsigned long ss = currentMillis / 1000;
unsigned long mm = ss / 60;
unsigned long hh = mm / 60;
unsigned long dd = hh / 24;
unsigned long tss = totalTime / 1000;
unsigned long tmm = tss / 60;
unsigned long thh = tmm / 60;
oled.clear(32, 0, 94, 8);
oled.setCursor(32, 0);
oled.setScale(1);
if (currentMillis > 86400 * 1000) {
sprintf(hhmmss, "%02dd %02d:%02d",dd, hh-dd*24, mm-hh*60);
oled.setCursor(40, 0);
} else if (totalTime == 2111111000) {
sprintf(hhmmss, "%02d:%02d",hh,mm);
//} else if (currentMillis == 0) {
// sprintf(hhmmss, "00:00/%02d:%02d",thh,tmm-thh*60);
} else{
sprintf(hhmmss, "%02d:%02d/%02d:%02d",hh,mm,thh,tmm-thh*60);
}
oled.print(hhmmss);
}
}