diff --git a/README b/README index 28be06b..11d1c1d 100644 --- a/README +++ b/README @@ -2,11 +2,10 @@ OBP Keypad ========== - Stromversorgung über M12-Anschluß über NMEA2000 - Eingangsbereich 6~21V -- Ein- und Ausschalten durch langen Tastendruck auf DST/ ONOFF + - Eingangsbereich 6~21V +- Konfigurationsmodus durch langen Tastendruck auf DST + - Tiefschlaf und Reset aus Konfigmodus heraus auswählbar - Konfiguration über Web-Interface -- PWR leuchtet grün wen NMEA2000-Verbindung etabliert -- PWR leuchtet rot wenn nur Stromversorgung aktiv ist - Buzzer für Tastendruck-Feedback passiv, damit können die Töne mit PWM programmiert werden - I²C Temp/Hum-Sensor SHT31 @@ -25,14 +24,15 @@ Optionen für später bedeutet auch: viel komplizierteres Gehäuse Damit die LEDs nicht stören, kann umgeschaltet werden zwischen -permanentem Leuchten und nur kurzem Aufblinken bei Betätigung. +permanentem Leuchten und nur kurzem Aufblinken bei Betätigung: +Tag- und Nachtmodus Einschaltvorgang ---------------- -Es erfolgt ein "Lampentest": Alle LEDs werden einmal durchgeschaltet. - -Sind alle Tests erfolgreich ertönt ein Buzzer-Signal. + - Status leuchtet kurz rot auf + - Es erfolgt ein "Lampentest": Alle LEDs werden einmal durchgeschaltet. + - Sind alle Tests erfolgreich ertönt ein Buzzer-Signal. Beschreibung ------------ @@ -44,31 +44,29 @@ Die Destination-LEDs leuchten nur, wenn ein entsprechendes N2K-Zielgerät konfiguriert und erkannt wurde. - - +Gehäuse +------- Bohrung Taster: 12mm Taster Außenmaß: 17.5mm Verbindungskabel CPU-Platine - JST 2.54 XH 6 Pin Steckverbinder -> LED + JST 2.54 XH 7 Pin Steckverbinder -> LEDs + GND Anschlußmöglichkeiten +--------------------- für Stromversorgung +12V und NMEA2000 - 4pin Terminalblock steck-/schraubbar +12V, DNG, CAN-L, CAN-H + 2pin Terminalblock für I²C-Module 2x 4pin Buchsenleiste weibl. - 1x QWIIC-Buchse (JST_SH_BM04B-SRSS-TB_04x1.00mm) + 1x qwiic-Buchse (JST_SH_BM04B-SRSS-TB_04x1.00mm) + + für CAN-Transceiver-Modul: 4fach buchse liegend für mechanische Taster - 1x JST 2.54 XH 7 Pin Steckverbinder -> Tasten - Masseverbindung über einzelnes getrenntes Kabel - in eine 8-fach WAGO-Klemme - - für LEDs - TBD + 1x Terminalblock 8fach, 7 Tasten und GND Bemerkungen @@ -77,6 +75,10 @@ Bemerkungen Bei den aktuell verwendeten Tasten sind die Anschlußdrähte extrem filigran. Leichtes Brechen und schlechte Verarbeitung. +Es gibt verschiedene Varianten mit unterschiedlicher Federkraft. +Auswahl muß noch erfolgen + + Beschaltung MCU Nano -------------------- @@ -94,7 +96,7 @@ werden! Die Pins für SPI (D11, D12, D13) sind absichtlich nicht belegt um frei für Erweiterungen zu sein. An SPI kann -ggf. ein Epaper angeschlossen werden. +ggf. ein E-Paper angeschlossen werden. Key Color Pin Remarks @@ -124,27 +126,35 @@ ggf. ein Epaper angeschlossen werden. BUZZER TBD -Bauteilliste +Bauteilliste (WIP) ------------ 1x ESP32-S3 Nano (Waveshare) berrybase.de eckstein-shop.de - 5x Taster schwarz - 2x Taster gelb - 1x M12 Einbaubuchse - 1x RGB LED (gemeinsame Anode), diffus + 6x Taster schwarz (1-6) + 1x Taster farbig (DST) + 1x M12 Micro-C Einbaubuchse + 1x RGB LED (gemeinsame Kathode), diffus 3x LED grün, diffus 6x Widerstand 330 Ohm 1x SN65HVD230 CAN Transceiver - 1x Buzzer, passiv - 1x Kabelsatz - 1x Terminalblock 4pol. 2,54mm schraubbar - 1x Gehäuse 150x60x40 bestehend auf Front- und Rückseite - 4x Befestigungsschraube M4 - 4x Gehäuseschraube M2,5 + 1x Buzzer 12V, passiv + 1x MOSFET 2N7000 + 1x Widerstand 150 Ohm + 1x Kabelsatz für Tasten, 0,25 bis 0,5 mm² + 1x Terminalblock 2pol. 2,54mm schraubbar + 1x 3D-Gehäuse bestehend auf Front- und Rückseite + 1x Mutternwerkzeug 3D-Druck + 4x Befestigungsschraube M4 Senkkopf + 4x Gehäuseschraube M2,5, lang + 8x Platinenschraube M2,5, kurz 1x Silikondichtschnur 2mm - + 1x SHT31 I²C-Modul + Buchsenleiste 2,54 mm + Stiftleiste 2,54mm + 2x Jumper + 1x Polyfuse Konfiguration ------------- diff --git a/include/main.h b/include/main.h index c9cb90b..5c97c35 100644 --- a/include/main.h +++ b/include/main.h @@ -6,6 +6,7 @@ // NMEA2000 defaults #define N2K_DEFAULT_NODEID 124 +#define NMEA2000_HEARTBEAT_INTERVAL 5000 // milliseconds // Keys #define KEY_1 GPIO_NUM_5 // D2 @@ -54,3 +55,24 @@ #define SPI_MISO GPIO_NUM_47 // D12 #define SPI_SCK GPIO_NUM_48 // D13 #define SPI_CS GPIO_NUM_46 // B0 + +// Button indices +#define BUTTON_1 0 +#define BUTTON_2 1 +#define BUTTON_3 2 +#define BUTTON_4 3 +#define BUTTON_5 4 +#define BUTTON_6 5 +#define BUTTON_DST 6 + +enum class ButtonPressType : uint8_t +{ + SHORT, // < 1 second + MEDIUM, // >= 1 second and < 3 seconds + LONG // >= 3 seconds +}; +struct ButtonEvent +{ + uint8_t buttonId; + ButtonPressType pressType; +}; diff --git a/platformio.ini b/platformio.ini index c8a8f50..be1c1a7 100644 --- a/platformio.ini +++ b/platformio.ini @@ -41,10 +41,9 @@ build_unflags = [env:esp32-s3-nano] build_type = release # debug | release -# board = esp32-s3-devkitc-1 board = esp32_s3_nano #board = arduino_nano_esp32 # ATTENTION! Pin numbering scheme changes board_upload.flash_size = 16MB -board_build.partitions = default.csv +board_build.partitions = default_16MB.csv #ESP32-S3 N16, 16MB flash upload_port = /dev/ttyACM0 upload_protocol = esptool diff --git a/src/main.cpp b/src/main.cpp index 75c4a29..57d4741 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -13,9 +13,9 @@ #include "Nmea2kTwai.h" #include - #include "mbedtls/md.h" // for SHA256 #include // for cpu frequency +#include "driver/rtc_io.h" // for wakeup from deep sleep String get_sha256(String payload) { byte shaResult[32]; @@ -90,8 +90,10 @@ uint64_t chipid = ESP.getEfuseMac(); const char* wifi_ssid = "OBPKP61"; const char* wifi_pass = "keypad61"; +bool apEnabled = false; AsyncWebServer server(80); +unsigned long firstStart = 0; unsigned long lastSensor = 0; unsigned long lastPrint = 0; unsigned long counter = 0; @@ -100,12 +102,17 @@ bool rgb_r = false; bool rgb_g = false; bool rgb_b = false; -char destination = 'A'; // A | B | C +char mode = 'N'; // (N)ormal | (C)onfig +char ledmode = 'D'; // (D)ay | (N)ight +char audiomode = 'E'; // (E)nabled | (D)isabled +RTC_DATA_ATTR char destination = 'A'; // A | B | C im RTC-Speicher überlebt deep sleep uint8_t led_brightness = 16; // analog pin: 0 .. 255 uint8_t rgb_brightness = 64; uint buzzerpower = 50; // TBD make use of this +uint8_t keycode[6]; // configurable keycodes + SHT31 sht(SHT31_ADDRESS); bool sht_available = false; float temp = 0.0; @@ -143,7 +150,7 @@ String uptime_with_unit() { void ledtest() { // all led one after another to test functionality - Serial.print("LED test started"); + Serial.println("LED test started"); // Onbard RGB LED, inverted mode digitalWrite(LED_IR, LOW); @@ -173,9 +180,6 @@ void ledtest() { analogWrite(LED_C, led_brightness); delay(500); analogWrite(LED_C, 0); - // select dst A finally - analogWrite(LED_A, led_brightness); - delay(500); // enclosure rgb led (common cathode, so low is off) analogWrite(RGBLED_R, rgb_brightness); @@ -190,25 +194,126 @@ void ledtest() { delay(700); analogWrite(RGBLED_B, 0); - Serial.print("LED test finished"); + Serial.println("LED test finished"); } +TaskHandle_t ledTaskHandle = NULL; +TaskHandle_t sensorTaskHandle = NULL; +TaskHandle_t keyTaskHandle = NULL; + +QueueHandle_t ledQueue = NULL; +QueueHandle_t keyQueue = NULL; + +void ledTask(void *parameter) { + Serial.println("Starting LED task"); + for (;;) { + vTaskDelay(5000); + analogWrite(RGBLED_G, 10); // a short activity flash + vTaskDelay(20); + analogWrite(RGBLED_G, 0); + } +} + +void sensorTask(void *parameter) { + Serial.println("Starting sensor task"); + for (;;) { + vTaskDelay(10000); // nothing yet + } +} + +void keyTask(void *parameter) { + // short key press <= 1s + // medium key press >1s and < 3s + // long key press >= 3s + Serial.println("Starting keyboard task"); + + constexpr uint8_t NUM_BUTTONS = 7; + constexpr gpio_num_t buttonPins[NUM_BUTTONS] = { + KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_DST + }; + constexpr TickType_t DEBOUNCE_TIME = pdMS_TO_TICKS(30); + constexpr TickType_t POLL_INTERVAL = pdMS_TO_TICKS(10); // 100Hz update rate (10ms) + + bool lastRead[NUM_BUTTONS]; + bool lastStable[NUM_BUTTONS]; + TickType_t lastDebounce[NUM_BUTTONS]; + TickType_t pressStart[NUM_BUTTONS]; + // init + for (int i = 0; i < NUM_BUTTONS; i++) { + lastRead[i]= HIGH; + lastStable[i] = HIGH; + lastDebounce[i]= 0; + pressStart[i] = 0; + } + for (;;) { + TickType_t now = xTaskGetTickCount(); + for (int i = 0; i < NUM_BUTTONS; i++) { + bool reading = digitalRead(buttonPins[i]); + if (reading != lastRead[i]) { + lastDebounce[i] = now; + lastRead[i] = reading; + } + if ((now - lastDebounce[i]) > DEBOUNCE_TIME) { + if (reading != lastStable[i]) { + lastStable[i] = reading; + if (reading == LOW) { + // button pressed + pressStart[i] = now; + } else { + // button released: send to queue + TickType_t duration = now - pressStart[i]; + ButtonEvent event; + event.buttonId = i; + if (duration < 1000) { + event.pressType = ButtonPressType::SHORT; + } else if (duration < 3000) { + event.pressType = ButtonPressType::MEDIUM; + } else { + event.pressType = ButtonPressType::LONG; + } + xQueueSend(keyQueue, &event, 0); + } + } + } + vTaskDelay(POLL_INTERVAL); + } + } + vTaskDelete(NULL); +} + +void cpuFreqTimerCallback(TimerHandle_t xTimer) { + Serial.println("after 3 minutes: set CPU frequency to 160MHz"); + setCpuFrequencyMhz(160); +} + void setup() { Serial.begin(115200); - // while (!Serial) delay(10); + // while (!Serial) delay(10); verhindert Booten ohne USB-Verbindung delay(500); + preferences.begin("nvs", false); + keycode[0] = preferences.getInt("key1", 1); + keycode[1] = preferences.getInt("key2", 2); + keycode[2] = preferences.getInt("key3", 3); + keycode[3] = preferences.getInt("key4", 4); + keycode[4] = preferences.getInt("key5", 5); + keycode[5] = preferences.getInt("key6", 6); + preferences.end(); + // Configure I/O pins // internal user led (red) pinMode(LED_USER, OUTPUT); - // Init onbard RGB led + // Init onbard RGB led and switch off pinMode(LED_IR, OUTPUT); pinMode(LED_IG, OUTPUT); pinMode(LED_IB, OUTPUT); + digitalWrite(LED_IR, HIGH); + digitalWrite(LED_IG, HIGH); + digitalWrite(LED_IB, HIGH); // destination leds pinMode(LED_A, OUTPUT); @@ -244,6 +349,13 @@ void setup() { ESP_LOGI(TAG, "Starting ..."); + esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause(); + if (cause == ESP_SLEEP_WAKEUP_EXT0) { + ESP_LOGI(TAG, " Wake up by key"); + } else { + destination = 'A'; + } + // N2K basics nodeid = N2K_DEFAULT_NODEID; ESP_LOGI(TAG, "N2K default node is %d", nodeid); @@ -264,6 +376,7 @@ void setup() { IPAddress ap_subnet(255, 255, 255, 0); IPAddress ap_gateway(ap_addr); WiFi.softAPConfig(ap_addr, ap_gateway, ap_subnet); + apEnabled = true; // Route for root / web page server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) { @@ -292,11 +405,29 @@ void setup() { request->send(200, "application/json", out); }); server.on("/api/config", HTTP_GET, [](AsyncWebServerRequest *request){ - StaticJsonDocument<100> doc; + StaticJsonDocument<512> doc; doc["systemName"] = "Keypad1"; + doc["logLevel"] = 0; doc["version"] = "0.0"; doc["fwtype"] = "unknown"; doc["salt"] = "secret"; + doc["AdminPassword"] = "********"; + doc["useAdminPass"] = false; + doc["apIp"] = "192.168.15.1"; + doc["apMask"] = "255.255.255.0"; + doc["apPassword"] = "********"; + doc["stopApTime"] = 0; + doc["cpuSpeed"] = 160; + doc["tempFormat"] = "C"; + doc["ledBrightness"] = led_brightness; + doc["ledRgbBrightness"] = rgb_brightness; + doc["tempFormat"] = "C"; + doc["key1"] = keycode[BUTTON_1]; + doc["key2"] = keycode[BUTTON_2]; + doc["key3"] = keycode[BUTTON_3]; + doc["key4"] = keycode[BUTTON_4]; + doc["key5"] = keycode[BUTTON_5]; + doc["key6"] = keycode[BUTTON_6]; String out; serializeJson(doc, out); request->send(200, "application/json", out); @@ -334,6 +465,13 @@ void setup() { serializeJson(doc, out); request->send(200, "application/json", out); }); + server.on("/api/update", HTTP_POST, [](AsyncWebServerRequest *request){ + StaticJsonDocument<100> doc; + doc["status"] = "FAILED"; + String out; + serializeJson(doc, out); + request->send(200, "application/json", out); + }); // TODO POST vom Client entgegennehmen @@ -348,17 +486,37 @@ void setup() { NMEA2000.SetProductInformation("00000001", // Manufacturer's Model serial code 74, // Manufacturer's product code "OBPkeypad6/1", // Manufacturer's Model ID - "1.0.0 (2025-11-28)", // Manufacturer's Software version code - "0.1" // Manufacturer's Model version + "0.1.0 (2026-01-04)", // Manufacturer's Software version code + "0.1", // Manufacturer's Model version + 1 // LoadEquivalency (LEN) ); + uint32_t uid; // ISO 21bit identity number devived from chipid (MAC) + uid = ((chipid >> 32) ^ (chipid & 0xFFFFFFFF)) & 0x1FFFFF; // TODO Device unique id stored in preferences - NMEA2000.SetDeviceInformation(1, // Unique number. Use e.g. Serial number. - 130, // Device function=Atmospheric - 85, // Device class=External Environment - 2046 + NMEA2000.SetDeviceInformation(uid, // Unique number. Use e.g. Serial number. + 130, // Device function=Button Interface (or 190?) + 110, // Device class=Human Interface? (or 140?) + 2046, // Manufacturer code (custom OBP) + 4 // Industrygoup=Marine ); + NMEA2000.SetForwardType(tNMEA2000::fwdt_Text); + + // Debug + // NMEA2000.SetForwardStream(&Serial); + // NMEA2000.SetDebugMode(tNMEA2000::dm_2); + + NMEA2000.SetMode(tNMEA2000::N2km_ListenAndNode, nodeid); + NMEA2000.SetForwardOwnMessages(false); + NMEA2000.SetHeartbeatIntervalAndOffset(NMEA2000_HEARTBEAT_INTERVAL); + + const unsigned long TransmitPGNs[] = { + 127502UL, + 0 + }; + NMEA2000.ExtendTransmitMessages(TransmitPGNs); + NMEA2000.Open(); // internal user led (red) digitalWrite(LED_USER, HIGH); @@ -369,10 +527,11 @@ void setup() { ledcSetup(LEDC_CHANNEL, LEDC_BASE_FREQ, LEDC_TIMER_8_BIT); ledcAttachPin(BUZZER, LEDC_CHANNEL); // Test tone while booting + // Buzzer 12V, 2500Hz +/- 200Hz, 30mA, ca. 90dB if (ledcWriteTone(LEDC_CHANNEL, 2300) == 0) { Serial.println("Error setting buzzer tone"); } else { - delay(750); + delay(50); ledcWriteTone(LEDC_CHANNEL, 0); // Buzzer off } @@ -380,6 +539,19 @@ void setup() { analogWrite(RGBLED_R, 0); // boot status off delay(500); ledtest(); + + // select current destination + switch (destination) { + case 'A': + analogWrite(LED_A, led_brightness); + break; + case 'B': + analogWrite(LED_B, led_brightness); + break; + case 'C': + analogWrite(LED_C, led_brightness); + break; + } // I²C Serial.print("SHT31_LIB_VERSION: "); @@ -396,18 +568,47 @@ void setup() { // Additional tests String passhash = get_sha256("secretTEST"); + xTaskCreatePinnedToCore( + ledTask, // Task function + "LEDTask", // Task name + 10000, // Stack size (bytes) + NULL, // Parameters + 1, // Priority + &ledTaskHandle, // Task handle + 1 // Core 1 + ); + xTaskCreatePinnedToCore(sensorTask,"SensorTask", 10000, NULL, 1, &sensorTaskHandle, 1); + xTaskCreatePinnedToCore(keyTask,"KeyboardTask", 10000, NULL, 1, &keyTaskHandle, 1); + + // Create queues (5 items, each uint16_t) + keyQueue = xQueueCreate(5, sizeof(ButtonEvent)); + ledQueue = xQueueCreate(5, sizeof(uint8_t)); + + if (esp_sleep_is_valid_wakeup_gpio(KEY_DST)) { + Serial.println("DST-Taste ist als Wakeup-Pin konfiguriert"); + esp_sleep_enable_ext0_wakeup(KEY_DST, 0); + } else { + Serial.println("Keine Wakeup-Funktion vorhanden! Deep-sleep deaktiviert."); + } + + TimerHandle_t cpuFreqTimer = xTimerCreate( + "cpuFreqTimer", + pdMS_TO_TICKS(2 * 60 * 1000), + pdFALSE, // one shot only + nullptr, + cpuFreqTimerCallback + ); + xTimerStart(cpuFreqTimer, 0); + +} + +void shortBeep() { + ledcWriteTone(LEDC_CHANNEL, 2500); + delay(15); + ledcWriteTone(LEDC_CHANNEL, 0); } void atariKeyclick() { -/* - * Anderer 12V-fähiger Buzzer! - * - Buzzer + → 12V - Buzzer – → IRLZ44N Drain - IRLZ44N Source → GND - ESP32 GPIO43 → 1kΩ resistor → Gate - ESP32 GND must be connected to the same GND as the 12V supply. - * */ ledcWriteTone(LEDC_CHANNEL, 3200); delayMicroseconds(3000); ledcWriteTone(LEDC_CHANNEL, 0); @@ -417,118 +618,161 @@ void atariKeyclick() { ledcWriteTone(LEDC_CHANNEL, 0); } +void SendToN2K(uint8_t keycode) { + tN2kMsg N2kMsg; + tN2kBinaryStatus bankstatus; + N2kResetBinaryStatus(bankstatus); + N2kSetStatusBinaryOnStatus(bankstatus, N2kOnOff_On, keycode); + + // TODO + // Needs filled N2K device list to map NAME to current address + // N2kMsg.Destination = deviceAddress; + // + SetN2kPGN127502(N2kMsg, 0, bankstatus); + NMEA2000.SendMsg(N2kMsg); + + Serial.print("PGN127502 sent: Switch="); + Serial.print(keycode); + Serial.println(" Action=On"); +} + void loop() { - // Button pressed? (active low) - uint8_t button = 0; - if (digitalRead(KEY_1) == LOW) { - Serial.println("Button detected: 1"); - button = 1; - if (rgb_r) { - rgb_r = false; - analogWrite(RGBLED_R, 255); - } else { - rgb_r = true; - analogWrite(RGBLED_R, 255 - rgb_brightness); + ButtonEvent event; + if (xQueueReceive(keyQueue, &event, 0) == pdPASS) { + Serial.print("Button "); + Serial.print(event.buttonId); + Serial.print(" -> "); + switch (event.pressType) { + case ButtonPressType::SHORT: + Serial.println("SHORT"); + break; + case ButtonPressType::MEDIUM: + Serial.println("MEDIUM"); + break; + case ButtonPressType::LONG: + Serial.println("LONG"); + break; + default: + Serial.print("UNBEKANNT: "); + Serial.println(static_cast(event.pressType)); + break; } - } - if (digitalRead(KEY_2) == LOW) { - Serial.println("Button detected: 2"); - button += 2; - if (rgb_g) { - rgb_g = false; - analogWrite(RGBLED_G, 255); + if (event.buttonId == BUTTON_DST) { + if (event.pressType == ButtonPressType::SHORT) { + if (mode == 'N') { + // switch destination only in normal mode + if (destination == 'A') { + destination = 'B'; + analogWrite(LED_A, 0); + analogWrite(LED_B, led_brightness); + } else if (destination == 'B') { + destination = 'C'; + analogWrite(LED_B, 0); + analogWrite(LED_C, led_brightness); + } else { + destination = 'A'; + analogWrite(LED_C, 0); + analogWrite(LED_A, led_brightness); + } + Serial.print("New destination="); + Serial.println(destination); + } + } else if (event.pressType == ButtonPressType::LONG) { + shortBeep(); + // switch config mode + if (mode == 'N') { + mode = 'C'; + analogWrite(RGBLED_B, rgb_brightness); // blue status indicator + } else { + mode = 'N'; + analogWrite(RGBLED_B, 0); + } + } } else { - rgb_g = true; - analogWrite(RGBLED_G, 255 - rgb_brightness); - } - } - if (digitalRead(KEY_3) == LOW) { - Serial.println("Button detected: 3"); - button += 4; - if (rgb_b) { - rgb_b = false; - analogWrite(RGBLED_B, 255); - } else { - rgb_b = true; - analogWrite(RGBLED_B, 255 - rgb_brightness); + // normal button + if (mode == 'N') { + // TODO send key code to destination + atariKeyclick(); + SendToN2K(keycode[event.buttonId]); + } else { + // online config mode + switch (event.buttonId) { + case BUTTON_1: // switch day/night mode + if (ledmode == 'D') { + Serial.println("Night mode enabled"); + ledmode = 'N'; + } else { + Serial.println("Day mode enabled"); + ledmode = 'D'; + } + break; + case BUTTON_2: // switch audio on/off + if (audiomode == 'E') { + Serial.println("Disabled audio"); + audiomode = 'D'; + } else { + Serial.println("Enabled audio"); + audiomode = 'E'; + } + break; + case BUTTON_3: // switch accesspoint on/off + if (apEnabled) { + Serial.println("Disable Accesspoint"); + WiFi.softAPdisconnect(true); + apEnabled = false; + } else { + Serial.println("Enable Accesspoint"); + WiFi.softAP(wifi_ssid, wifi_pass); + apEnabled = true; + } + break; + case BUTTON_4: // reserved + break; + case BUTTON_5: // reset + Serial.println("Device reset"); + analogWrite(RGBLED_B, 0); + delay(500); + analogWrite(RGBLED_G, 255); + delay(500); + analogWrite(RGBLED_G, 0); + delay(500); + analogWrite(RGBLED_G, 255); + delay(500); + analogWrite(RGBLED_G, 0); + delay(500); + analogWrite(RGBLED_G, 255); + delay(500); + ESP.restart(); + break; + case BUTTON_6: // deep sleep + Serial.println("Going into deep sleep"); + Serial.flush(); + analogWrite(RGBLED_B, 0); + delay(500); + analogWrite(RGBLED_B, 255); + delay(500); + analogWrite(RGBLED_B, 0); + delay(500); + analogWrite(RGBLED_B, 255); + delay(500); + analogWrite(RGBLED_B, 0); + delay(500); + analogWrite(RGBLED_B, 255); + delay(500); + + rtc_gpio_pullup_en(KEY_DST); + rtc_gpio_pulldown_dis(KEY_DST); + esp_deep_sleep_start(); + + break; + } + } } } - if (digitalRead(KEY_4) == LOW) { - Serial.println("Button detected: 4"); - button += 8; - - atariKeyclick(); - - digitalWrite(LED_USER, HIGH); // Turn LED on - delay(500); // Keep it on 0.5s - digitalWrite(LED_USER, LOW); // Turn LED off - } - if (digitalRead(KEY_5) == LOW) { - Serial.println("Button detected: 5"); - button += 16; - - ledcWriteTone(LEDC_CHANNEL, 3200); - delay(8); - ledcWriteTone(LEDC_CHANNEL, 0); - - digitalWrite(LED_USER, HIGH); // Turn LED on - delay(500); // Keep it on 0.5s - digitalWrite(LED_USER, LOW); // Turn LED off - } - if (digitalRead(KEY_6) == LOW) { - Serial.println("Button detected: 6"); - button += 32; - - ledcWriteTone(LEDC_CHANNEL, 3200); - delay(8); - ledcWriteTone(LEDC_CHANNEL, 0); - - digitalWrite(LED_USER, HIGH); // Turn LED on - delay(500); // Keep it on 0.5s - digitalWrite(LED_USER, LOW); // Turn LED off - } - - if (digitalRead(KEY_DST) == LOW) { - Serial.println("Button detected: DST"); - button += 64; - - if (destination == 'A') { - destination = 'B'; - analogWrite(LED_A, 0); - analogWrite(LED_B, led_brightness); - } else if (destination == 'B') { - destination = 'C'; - analogWrite(LED_B, 0); - analogWrite(LED_C, led_brightness); - } else { - destination = 'A'; - analogWrite(LED_C, 0); - analogWrite(LED_A, led_brightness); - } - Serial.print("Destination="); - Serial.println(destination); - - /* - digitalWrite(LED_USER, HIGH); // Turn LED on - delay(500); // Keep it on 0.5s - digitalWrite(LED_USER, LOW); // Turn LED off - */ - - } - - if (button > 0) { - Serial.print(temp, 1); - Serial.print("\t"); - Serial.println(hum, 1); - // Debounce delay to avoid multiple triggers - delay(200); - } - - - // NMEA2000.loop(); - // NMEA2000.ParseMessages(); + NMEA2000.loop(); + NMEA2000.ParseMessages(); if (millis() - lastSensor >= 5000) { lastSensor = millis(); @@ -544,4 +788,5 @@ void loop() { Serial.printf("Loop counter: %lu\n", counter); } + delay(1); // 1ms für freertos } diff --git a/web/config.json b/web/config.json index 234293b..50e7653 100644 --- a/web/config.json +++ b/web/config.json @@ -125,5 +125,65 @@ ], "description": "Temperature format: Kelvin, Celsius or Fahrenheit [K|C|F].", "category": "Units" +}, +{ + "name": "key1", + "label": "Key 1 code", + "type": "number", + "default": 1, + "min": 1, + "max": 28, + "description": "The keycode to send for key 1 (leftmost) [1 .. 28]", + "category": "Keys" +}, +{ + "name": "key2", + "label": "Key 2 code", + "type": "number", + "default": 2, + "min": 1, + "max": 28, + "description": "The keycode to send for key 2 (second from left) [1 .. 28]", + "category": "Keys" +}, +{ + "name": "key3", + "label": "Key 3 code", + "type": "number", + "default": 3, + "min": 1, + "max": 28, + "description": "The keycode to send for key 3 (third from left) [1 .. 28]", + "category": "Keys" +}, +{ + "name": "key4", + "label": "Key 4 code", + "type": "number", + "default": 4, + "min": 1, + "max": 28, + "description": "The keycode to send for key 4 (fourth from left) [1 .. 28]", + "category": "Keys" +}, +{ + "name": "key5", + "label": "Key 5 code", + "type": "number", + "default": 5, + "min": 1, + "max": 28, + "description": "The keycode to send for key 5 (fifth from left) [1 .. 28]", + "category": "Keys" +}, +{ + "name": "key6", + "label": "Key 6 code", + "type": "number", + "default": 6, + "min": 1, + "max": 28, + "description": "The keycode to send for key 6 (rightmost) [1 .. 28]", + "category": "Keys" } ]