Change analogWrite to ledcWrite, configuration improvements

This commit is contained in:
2026-01-28 15:46:37 +01:00
parent 107339b3d3
commit 564ed20720
11 changed files with 340 additions and 304 deletions

View File

@@ -1,8 +1,12 @@
#include "config.h"
#include "esp_rom_uart.h" // for uart wait idle
// Logging
static const char* TAG = "CFG";
Preferences preferences; // persistent storage for configuration
Config config(preferences); // configuration object
Config::Config(Preferences& prefs)
: prefs(prefs) {
@@ -13,12 +17,19 @@ Config::Config(Preferences& prefs)
}
[[noreturn]] void Config::error_abort() const {
ESP_LOGD(TAG, "Rebooting in about 2 seconds");
esp_rom_uart_tx_wait_idle(0);
delay(2000); // to have a chance to read
abort();
}
void Config::load() {
ESP_LOGI(TAG, "Loading configuration");
ESP_LOGD(TAG, "Loading configuration");
prefs.begin(PREF_NAME, true);
for (const auto& def : configdefs) {
if (prefs.isKey(def.key)) {
ESP_LOGI(TAG, "Config option '%s' loaded from NVS", def.key);
ESP_LOGD(TAG, "Config option '%s' loaded from NVS", def.key);
switch (def.type) {
case ConfigType::BYTE:
values[def.key] = (uint8_t)prefs.getUChar(def.key, std::get<uint8_t>(def.defval));
@@ -43,7 +54,7 @@ void Config::load() {
break;
}
} else {
ESP_LOGI(TAG, "Using default for '%s'", def.key);
ESP_LOGD(TAG, "Using default for '%s'", def.key);
switch (def.type) {
case ConfigType::BYTE:
values[def.key] = std::get<uint8_t>(def.defval);
@@ -204,36 +215,36 @@ uint8_t Config::getByte(const char* key) const {
auto it = values.find(key);
if (it == values.end()) {
ESP_LOGE(TAG, "Missing config key: %s", key);
abort();
error_abort();
}
if (auto v = std::get_if<uint8_t>(&it->second))
return *v;
ESP_LOGE(TAG, "Type mismatch for key: %s", key);
abort();
error_abort();
}
int16_t Config::getShort(const char* key) const {
auto it = values.find(key);
if (it == values.end()) {
ESP_LOGE(TAG, "Missing config key: %s", key);
abort();
error_abort();
}
if (auto v = std::get_if<int16_t>(&it->second))
return *v;
ESP_LOGE(TAG, "Type mismatch for key: %s", key);
abort();
error_abort();
}
int32_t Config::getInt(const char* key) const {
auto it = values.find(key);
if (it == values.end()) {
ESP_LOGE(TAG, "Missing config key: %s", key);
abort();
error_abort();
}
if (auto v = std::get_if<int32_t>(&it->second))
return *v;
ESP_LOGE(TAG, "Type mismatch for key: %s", key);
abort();
error_abort();
}
bool Config::getBool(const char* key) const {
@@ -251,34 +262,38 @@ float Config::getFloat(const char* key) const {
auto it = values.find(key);
if (it == values.end()) {
ESP_LOGE(TAG, "Missing config key: %s", key);
abort();
error_abort();
}
if (auto v = std::get_if<float>(&it->second))
return *v;
ESP_LOGE(TAG, "Type mismatch for key: %s", key);
abort();
error_abort();
}
char Config::getChar(const char* key) const {
auto it = values.find(key);
if (it == values.end()) {
ESP_LOGE(TAG, "Missing config key: %s", key);
abort();
error_abort();
}
if (auto v = std::get_if<char>(&it->second))
return *v;
ESP_LOGE(TAG, "Type mismatch for key: %s", key);
abort();
error_abort();
}
const String& Config::getString(const char* key) const {
auto it = values.find(key);
if (it == values.end()) {
ESP_LOGE(TAG, "Missing config key: %s", key);
abort();
error_abort();
}
if (auto v = std::get_if<String>(&it->second))
return *v;
ESP_LOGE(TAG, "Type mismatch for key: %s", key);
abort();
error_abort();
}
const char* Config::getCString(const char* key) const {
return getString(key).c_str();
}

32
src/hash.cpp Normal file
View File

@@ -0,0 +1,32 @@
#include "hash.h"
#include "mbedtls/md.h" // for SHA256
String get_sha256(String payload) {
byte shaResult[32];
mbedtls_md_context_t ctx;
mbedtls_md_type_t md_type = MBEDTLS_MD_SHA256;
mbedtls_md_init(&ctx);
mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(md_type), 0);
mbedtls_md_starts(&ctx);
mbedtls_md_update(&ctx, (const unsigned char *) payload.c_str(), payload.length());
mbedtls_md_finish(&ctx, shaResult);
mbedtls_md_free(&ctx);
// convert to hex string
char buffer[sizeof(shaResult)*2 + 1];
const char hexmap[] = "0123456789abcdef";
for (int i = 0; i < sizeof(shaResult); i++) {
buffer[i*2] = hexmap[(shaResult[i] >> 4) & 0x0F];
buffer[i*2+1] = hexmap[shaResult[i] & 0x0F];
}
buffer[sizeof(buffer) - 1] = '\0';
String hash = String(buffer);
Serial.print("SHA256 payload: ");
Serial.print(payload);
Serial.println();
Serial.print("SHA256-Hash: ");
Serial.print(hash);
Serial.println();
return hash;
}

95
src/led.cpp Normal file
View File

@@ -0,0 +1,95 @@
#include "main.h"
#include "led.h"
// Logging
static const char* TAG = "LED";
int16_t led_brightness = 512; // analog pin with ledc: 0 .. 4095
int16_t rgb_brightness = 768;
void led_init() {
// internal user led (red)
digitalWrite(LED_USER, HIGH);
delay(1000);
digitalWrite(LED_USER, LOW);
// LEDC
ledcSetup(LEDC_BUZZER, LEDC_BASE_FREQ, LEDC_RES_BUZZER);
ledcSetup(LEDC_LED_A, LEDC_BASE_FREQ, LEDC_RES_LED);
ledcSetup(LEDC_LED_B, LEDC_BASE_FREQ, LEDC_RES_LED);
ledcSetup(LEDC_LED_C, LEDC_BASE_FREQ, LEDC_RES_LED);
ledcSetup(LEDC_RGBLED_R, LEDC_BASE_FREQ, LEDC_RES_LED);
ledcSetup(LEDC_RGBLED_G, LEDC_BASE_FREQ, LEDC_RES_LED);
ledcSetup(LEDC_RGBLED_B, LEDC_BASE_FREQ, LEDC_RES_LED);
ledcAttachPin(LED_A, LEDC_LED_A);
ledcAttachPin(LED_B, LEDC_LED_B);
ledcAttachPin(LED_C, LEDC_LED_C);
ledcAttachPin(RGBLED_R, LEDC_RGBLED_R);
ledcAttachPin(RGBLED_G, LEDC_RGBLED_G);
ledcAttachPin(RGBLED_B, LEDC_RGBLED_B);
}
void led_test() {
// all led one after another to test functionality
ESP_LOGI(TAG, "LED test started");
// Onbard RGB LED, inverted mode
digitalWrite(LED_IR, LOW);
digitalWrite(LED_IG, HIGH);
digitalWrite(LED_IB, HIGH);
delay(500);
digitalWrite(LED_IR, HIGH);
digitalWrite(LED_IG, LOW);
delay(500);
digitalWrite(LED_IG, HIGH);
digitalWrite(LED_IB, LOW);
delay(500);
digitalWrite(LED_IB, HIGH);
// destination leds
ledcWrite(LEDC_LED_A, 0);
delay(250);
// test every led
ledcWrite(LEDC_LED_A, led_brightness);
ledcWrite(LEDC_LED_B, 0);
ledcWrite(LEDC_LED_C, 0);
delay(500);
ledcWrite(LEDC_LED_A, 0);
ledcWrite(LEDC_LED_B, led_brightness);
delay(500);
ledcWrite(LEDC_LED_B, 0);
ledcWrite(LEDC_LED_C, led_brightness);
delay(500);
ledcWrite(LEDC_LED_C, 0);
// enclosure rgb led (common cathode, so low is off)
ledcWrite(LEDC_RGBLED_R, rgb_brightness);
ledcWrite(LEDC_RGBLED_G, 0);
ledcWrite(LEDC_RGBLED_B, 0);
delay(700);
ledcWrite(LEDC_RGBLED_R, 0);
ledcWrite(LEDC_RGBLED_G, rgb_brightness);
delay(700);
ledcWrite(LEDC_RGBLED_G, 0);
ledcWrite(LEDC_RGBLED_B, rgb_brightness);
delay(700);
ledcWrite(LEDC_RGBLED_B, 0);
ESP_LOGI(TAG, "LED test finished");
}
void led_blink(uint8_t channel, uint8_t count, int16_t brightness, uint32_t interval_ms) {
ledcWrite(channel, 0);
for (uint16_t i = 0; i < count; i++) {
delay(interval_ms);
ledcWrite(channel, brightness);
delay(interval_ms);
ledcWrite(channel, 0);
}
delay(interval_ms);
}

View File

@@ -1,6 +1,8 @@
#include "main.h"
#include "config.h"
#include "webserver.h"
#include "led.h"
#include "hash.h"
#include <ArduinoJson.h>
#include <WiFi.h>
#include <Wire.h>
@@ -8,14 +10,12 @@
#include <NMEA2000.h>
#include <N2kMsg.h>
#include <N2kMessages.h>
#include "Nmea2kTwai.h"
#include "N2kDeviceList.h"
#include <map>
#include "mbedtls/md.h" // for SHA256
#include <esp32/clk.h> // for cpu frequency
#include "driver/rtc_io.h" // for wakeup from deep sleep
#include "esp_app_format.h" // for custom fw descriptor
#include "esp_rom_uart.h" // for uart wait idle
// ESP-IDF firmware descriptor
__attribute__((section(".rodata_custom_desc"))) esp_app_desc_t custom_app_desc = {
@@ -31,53 +31,18 @@ __attribute__((section(".rodata_custom_desc"))) esp_app_desc_t custom_app_desc =
{}
};
String get_sha256(String payload) {
byte shaResult[32];
mbedtls_md_context_t ctx;
mbedtls_md_type_t md_type = MBEDTLS_MD_SHA256;
mbedtls_md_init(&ctx);
mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(md_type), 0);
mbedtls_md_starts(&ctx);
mbedtls_md_update(&ctx, (const unsigned char *) payload.c_str(), payload.length());
mbedtls_md_finish(&ctx, shaResult);
mbedtls_md_free(&ctx);
// convert to hex string
char buffer[sizeof(shaResult)*2 + 1];
const char hexmap[] = "0123456789abcdef";
for (int i = 0; i < sizeof(shaResult); i++) {
buffer[i*2] = hexmap[(shaResult[i] >> 4) & 0x0F];
buffer[i*2+1] = hexmap[shaResult[i] & 0x0F];
}
buffer[sizeof(buffer) - 1] = '\0';
String hash = String(buffer);
Serial.print("SHA256 payload: ");
Serial.print(payload);
Serial.println();
Serial.print("SHA256-Hash: ");
Serial.print(hash);
Serial.println();
return hash;
}
// Logging
static const char* TAG = "MAIN";
Preferences preferences; // persistent storage for configuration
Config config(preferences); // configuration object
uint64_t chipid = ESP.getEfuseMac();
const char* wifi_ssid = "OBPKP61";
const char* wifi_pass = "keypad61";
bool apEnabled = false;
// AsyncWebServer server(80);
bool ap_enabled = false;
unsigned long firstStart = 0;
unsigned long lastSensor = 0;
unsigned long lastPrint = 0;
unsigned long counter = 0;
bool rgb_r = false;
bool rgb_g = false;
@@ -85,13 +50,11 @@ bool rgb_b = false;
int cpuspeed = 240; // MHz
char globalmode = 'K'; // (K)eyboard | (A)utopilot | (L)ogbook
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 globalmode = 'K'; // (K)eyboard | (A)utopilot | (L)ogbook
char mode = 'N'; // (N)ormal | (C)onfig -> do not store for reset!
RTC_DATA_ATTR char ledmode = 'D'; // (D)ay | (N)ight
RTC_DATA_ATTR 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
@@ -103,7 +66,7 @@ bool sht_available = false;
float temp = 0.0;
float hum = 0.0;
int nodeid; // NMEA2000 id on bus
uint8_t nodeid; // NMEA2000 id on bus
Nmea2kTwai &NMEA2000=*(new Nmea2kTwai(CAN_TX, CAN_RX, CAN_RECOVERY_PERIOD));
tN2kDeviceList *pN2kDeviceList;
@@ -112,77 +75,6 @@ String processor(const String& var) {
return "";
}
String uptime_with_unit() {
int64_t uptime = esp_timer_get_time() / 1000000;
String uptime_unit;
if (uptime < 120) {
uptime_unit = " seconds";
} else {
if (uptime < 2 * 3600) {
uptime /= 60;
uptime_unit = " minutes";
} else if (uptime < 2 * 3600 * 24) {
uptime /= 3600;
uptime_unit = " hours";
} else {
uptime /= 86400;
uptime_unit = " days";
}
}
return String(uptime) + " " + uptime_unit;
}
void ledtest() {
// all led one after another to test functionality
Serial.println("LED test started");
// Onbard RGB LED, inverted mode
digitalWrite(LED_IR, LOW);
digitalWrite(LED_IG, HIGH);
digitalWrite(LED_IB, HIGH);
delay(500);
digitalWrite(LED_IR, HIGH);
digitalWrite(LED_IG, LOW);
delay(500);
digitalWrite(LED_IG, HIGH);
digitalWrite(LED_IB, LOW);
delay(500);
digitalWrite(LED_IB, HIGH);
// destination leds
analogWrite(LED_A, 0);
delay(250);
// test every led
analogWrite(LED_A, led_brightness);
analogWrite(LED_B, 0);
analogWrite(LED_C, 0);
delay(500);
analogWrite(LED_A, 0);
analogWrite(LED_B, led_brightness);
delay(500);
analogWrite(LED_B, 0);
analogWrite(LED_C, led_brightness);
delay(500);
analogWrite(LED_C, 0);
// enclosure rgb led (common cathode, so low is off)
analogWrite(RGBLED_R, rgb_brightness);
analogWrite(RGBLED_G, 0);
analogWrite(RGBLED_B, 0);
delay(700);
analogWrite(RGBLED_R, 0);
analogWrite(RGBLED_G, rgb_brightness);
delay(700);
analogWrite(RGBLED_G, 0);
analogWrite(RGBLED_B, rgb_brightness);
delay(700);
analogWrite(RGBLED_B, 0);
Serial.println("LED test finished");
}
TaskHandle_t ledTaskHandle = NULL;
TaskHandle_t sensorTaskHandle = NULL;
TaskHandle_t keyTaskHandle = NULL;
@@ -191,17 +83,17 @@ QueueHandle_t ledQueue = NULL;
QueueHandle_t keyQueue = NULL;
void ledTask(void *parameter) {
Serial.println("Starting LED task");
ESP_LOGI(TAG, "Starting LED task");
for (;;) {
vTaskDelay(5000);
analogWrite(RGBLED_G, 10); // a short activity flash
ledcWrite(LEDC_RGBLED_G, 160); // a short activity flash
vTaskDelay(20);
analogWrite(RGBLED_G, 0);
ledcWrite(LEDC_RGBLED_G, 0);
}
}
void sensorTask(void *parameter) {
Serial.println("Starting sensor task");
ESP_LOGI(TAG, "Starting sensor task");
for (;;) {
vTaskDelay(10000); // nothing yet
}
@@ -211,7 +103,7 @@ void keyTask(void *parameter) {
// short key press <= 1s
// medium key press >1s and < 3s
// long key press >= 3s
Serial.println("Starting keyboard task");
ESP_LOGI(TAG, "Starting keyboard task");
constexpr uint8_t NUM_BUTTONS = 7;
constexpr gpio_num_t buttonPins[NUM_BUTTONS] = {
@@ -268,12 +160,12 @@ void keyTask(void *parameter) {
}
void stopApTimerCallback(TimerHandle_t xTimer) {
Serial.println("reached AP switchoff time: accesspoint switched off ");
ESP_LOGI(TAG, "reached AP switchoff time: accesspoint switched off ");
WiFi.softAPdisconnect(true);
}
void cpuFreqTimerCallback(TimerHandle_t xTimer) {
Serial.println("after 3 minutes: set CPU frequency to 160MHz");
ESP_LOGI(TAG, "after 3 minutes: set CPU frequency to 160MHz");
setCpuFrequencyMhz(cpuspeed);
}
@@ -315,10 +207,10 @@ void setup() {
pinMode(KEY_6, INPUT_PULLUP);
pinMode(KEY_DST, INPUT_PULLUP);
// Early signal system activity
analogWrite(RGBLED_R, 255);
analogWrite(RGBLED_G, 0);
analogWrite(RGBLED_B, 0);
// Early signal system activity, red while booting
digitalWrite(RGBLED_R, HIGH);
digitalWrite(RGBLED_G, LOW);
digitalWrite(RGBLED_B, LOW);
// Arduino ESP32 logging
esp_log_level_set("*", ESP_LOG_INFO);
@@ -348,7 +240,7 @@ void setup() {
esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause();
if (cause == ESP_SLEEP_WAKEUP_EXT0) {
ESP_LOGI(TAG, " Wake up by key");
ESP_LOGI(TAG, "Wake up by key");
} else {
destination = 'A';
}
@@ -356,9 +248,10 @@ void setup() {
// N2K basics
nodeid = N2K_DEFAULT_NODEID;
ESP_LOGI(TAG, "N2K default node is %d", nodeid);
preferences.begin(PREF_NAME, false);
nodeid = preferences.getInt("LastNodeId", N2K_DEFAULT_NODEID);
preferences.end();
//preferences.begin(PREF_NAME, false);
//nodeid = preferences.getInt("LastNodeId", N2K_DEFAULT_NODEID);
//preferences.end();
nodeid = config.getByte("LastNodeId");
ESP_LOGI(TAG, "N2K node id set to %d from preferences", nodeid);
//cpuspeed = preferences.getInt("cpuSpeed", 160);
@@ -392,37 +285,10 @@ void setup() {
IPAddress ap_gateway(ap_addr);
WiFi.softAPConfig(ap_addr, ap_gateway, ap_subnet);
apEnabled = true;
ap_enabled = true;
// Initialize WebGUI
webserver_init();
server.on("/api/devicelist", HTTP_GET, [](AsyncWebServerRequest *request){
// NMEA2000 device list
AsyncResponseStream *response = request->beginResponseStream("application/json");
response->print("[");
bool first = true;
for (int i = 0; i <= 252; i++) {
const tNMEA2000::tDevice *d = pN2kDeviceList->FindDeviceBySource(i);
if (d == nullptr) {
continue;
}
uint64_t NAME = d->GetName();
char hex_name[17];
snprintf(hex_name, sizeof(hex_name), "%08X%08X", (uint32_t)(NAME >> 32), (uint32_t)(NAME & 0xFFFFFFFF));
if (!first) {
response->print(",");
} else {
first = false;
}
// TODO last seen?
response->printf("{\"source\":%d,\"name\":\"%s\",\"manuf\":\"%d\",\"model\":\"%s\"}",
i, hex_name, d->GetManufacturerCode(), d->GetModelID());
}
response->print("]");
request->send(response);
});
// Start HTTP Webserver
server.begin();
@@ -486,52 +352,50 @@ void setup() {
// Debug: NMEA2000.EnableForward(true);
NMEA2000.Open();
// internal user led (red)
digitalWrite(LED_USER, HIGH);
delay(1000);
digitalWrite(LED_USER, LOW);
led_init();
// Buzzer
ledcSetup(LEDC_CHANNEL, LEDC_BASE_FREQ, LEDC_TIMER_8_BIT);
ledcAttachPin(BUZZER, LEDC_CHANNEL);
ledcAttachPin(BUZZER, LEDC_BUZZER);
// Test tone while booting
// Buzzer 12V, 2500Hz +/- 200Hz, 30mA, ca. 90dB
if (ledcWriteTone(LEDC_CHANNEL, 2300) == 0) {
if (ledcWriteTone(LEDC_BUZZER, 2300) == 0) {
Serial.println("Error setting buzzer tone");
} else {
delay(50);
ledcWriteTone(LEDC_CHANNEL, 0); // Buzzer off
ledcWriteTone(LEDC_BUZZER, 0); // Buzzer off
}
// Startup sequence: test all led and short beep buzzer
analogWrite(RGBLED_R, 0); // boot status off
digitalWrite(RGBLED_R, LOW); // boot status off
delay(500);
ledtest();
led_test();
// select current destination
switch (destination) {
case 'A':
analogWrite(LED_A, led_brightness);
ledcWrite(LEDC_LED_A, led_brightness);
break;
case 'B':
analogWrite(LED_B, led_brightness);
ledcWrite(LEDC_LED_B, led_brightness);
break;
case 'C':
analogWrite(LED_C, led_brightness);
ledcWrite(LEDC_LED_C, led_brightness);
break;
}
// I²C
Serial.print("SHT31_LIB_VERSION: ");
Serial.println(SHT31_LIB_VERSION);
// Serial.print("SHT31_LIB_VERSION: ");
// Serial.println(SHT31_LIB_VERSION);
ESP_LOGI(TAG, "SHT31_LIB_VERSION: %s", SHT31_LIB_VERSION);
Wire.begin(I2C_SDA, I2C_SCL);
Wire.setClock(I2C_SPEED);
uint16_t stat = sht.readStatus();
// stat = ffff anscheinend Fehler
// = 8010 läuft anscheinend
sht_available = (stat == 0x8010);
Serial.print(stat, HEX);
Serial.println();
ESP_LOGI(TAG, "SHT31 state=0x%X", stat);
// Additional tests
String passhash = get_sha256("secretTEST");
@@ -553,10 +417,10 @@ void setup() {
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_LOGI(TAG, "DST-key configured as wakeup-pin");
esp_sleep_enable_ext0_wakeup(KEY_DST, 0);
} else {
Serial.println("Keine Wakeup-Funktion vorhanden! Deep-sleep deaktiviert.");
ESP_LOGI(TAG, "No wakeup feature available! Deep-sleep disabled.");
}
if (cpuspeed < 240) {
@@ -584,19 +448,19 @@ void setup() {
}
void shortBeep() {
ledcWriteTone(LEDC_CHANNEL, 2500);
ledcWriteTone(LEDC_BUZZER, 2500);
delay(15);
ledcWriteTone(LEDC_CHANNEL, 0);
ledcWriteTone(LEDC_BUZZER, 0);
}
void atariKeyclick() {
ledcWriteTone(LEDC_CHANNEL, 3200);
ledcWriteTone(LEDC_BUZZER, 3200);
delayMicroseconds(3000);
ledcWriteTone(LEDC_CHANNEL, 0);
ledcWriteTone(LEDC_BUZZER, 0);
delayMicroseconds(800);
ledcWriteTone(LEDC_CHANNEL, 3200);
ledcWriteTone(LEDC_BUZZER, 3200);
delayMicroseconds(2000);
ledcWriteTone(LEDC_CHANNEL, 0);
ledcWriteTone(LEDC_BUZZER, 0);
}
void print_n2k_devicelist() {
@@ -658,7 +522,7 @@ void send_sensor_temphum(float temp_k, float hum_perc) {
unsigned char instance = 0;
tN2kTempSource temp_src = N2kts_OutsideTemperature; // 1=outside, 2=inside
tN2kHumiditySource hum_src = N2khs_OutsideHumidity; // 0=inside, 1=outside
Serial.printf("Sending temp=%f K, hum=%f %%\n", temp_k, hum_perc);
ESP_LOGI(TAG, "Sending temp=%f K, hum=%f %%", temp_k, hum_perc);
SetN2kPGN130312(N2kMsg, SID, instance, temp_src, temp_k);
NMEA2000.SendMsg(N2kMsg);
SetN2kPGN130313(N2kMsg, SID, instance, hum_src, hum_perc);
@@ -670,55 +534,37 @@ void loop() {
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<uint8_t>(event.pressType));
break;
}
if (event.buttonId == BUTTON_DST) {
// destination / mode button
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);
ledcWrite(LEDC_LED_A, 0);
ledcWrite(LEDC_LED_B, led_brightness);
} else if (destination == 'B') {
destination = 'C';
analogWrite(LED_B, 0);
analogWrite(LED_C, led_brightness);
ledcWrite(LEDC_LED_B, 0);
ledcWrite(LEDC_LED_C, led_brightness);
} else {
destination = 'A';
analogWrite(LED_C, 0);
analogWrite(LED_A, led_brightness);
ledcWrite(LEDC_LED_C, 0);
ledcWrite(LEDC_LED_A, led_brightness);
}
Serial.print("New destination=");
Serial.println(destination);
ESP_LOGI(TAG, "New destination=%s", destination);
}
} else if (event.pressType == ButtonPressType::LONG) {
shortBeep();
// switch config mode
if (mode == 'N') {
mode = 'C';
analogWrite(RGBLED_B, rgb_brightness); // blue status indicator
Serial.println("Entering config mode");
ledcWrite(LEDC_RGBLED_B, rgb_brightness); // blue status indicator
ESP_LOGI(TAG, "Entering config mode");
} else {
mode = 'N';
analogWrite(RGBLED_B, 0);
Serial.println("Leaving config mode");
ledcWrite(LEDC_RGBLED_B, 0);
ESP_LOGI(TAG, "Leaving config mode");
}
}
} else {
@@ -742,71 +588,48 @@ void loop() {
switch (event.buttonId) {
case BUTTON_1: // switch day/night mode
if (ledmode == 'D') {
Serial.println("Night mode enabled");
ESP_LOGI(TAG, "Night mode enabled");
ledmode = 'N';
} else {
Serial.println("Day mode enabled");
ESP_LOGI(TAG, "Day mode enabled");
ledmode = 'D';
}
break;
case BUTTON_2: // switch audio on/off
if (audiomode == 'E') {
Serial.println("Disabled audio");
ESP_LOGI(TAG, "Disabled audio");
audiomode = 'D';
} else {
Serial.println("Enabled audio");
ESP_LOGI(TAG, "Enabled audio");
audiomode = 'E';
}
break;
case BUTTON_3: // switch accesspoint on/off
if (apEnabled) {
Serial.println("Disable Accesspoint");
if (ap_enabled) {
ESP_LOGI(TAG, "Disable Accesspoint");
WiFi.softAPdisconnect(true);
apEnabled = false;
ap_enabled = false;
} else {
Serial.println("Enable Accesspoint");
WiFi.softAP(wifi_ssid, wifi_pass);
apEnabled = true;
ap_enabled = 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_LOGI(TAG, "Device reset");
esp_rom_uart_tx_wait_idle(0);
led_blink(LEDC_RGBLED_G, 3, 4095, 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);
ESP_LOGI(TAG, "Going into deep sleep");
esp_rom_uart_tx_wait_idle(0);
led_blink(LEDC_RGBLED_B, 3, 4095, 500);
rtc_gpio_pullup_en(KEY_DST);
rtc_gpio_pulldown_dis(KEY_DST);
esp_deep_sleep_start();
break;
}
}
@@ -816,7 +639,7 @@ void loop() {
NMEA2000.loop();
NMEA2000.ParseMessages();
if (millis() - lastSensor >= 5000) {
if ((millis() - lastSensor >= 5000) and sht_available) {
lastSensor = millis();
sht.read();
temp = sht.getTemperature(); // °C
@@ -826,12 +649,5 @@ void loop() {
send_sensor_temphum(temp + 273.15, hum);
}
// development heartbeat
if (millis() - lastPrint >= 1000) {
lastPrint = millis();
counter++;
Serial.printf("Loop counter: %lu\n", counter);
}
delay(1); // 1ms für freertos
delay(1); // 1ms for FreeRTOS
}

View File

@@ -1,4 +1,5 @@
#include "main.h"
#include "config.h"
#include "webserver.h"
#include <map>
#include <AsyncTCP.h>
@@ -42,6 +43,26 @@ void send_embedded_file(String name, AsyncWebServerRequest *request)
}
}
String uptime_with_unit() {
int64_t uptime = esp_timer_get_time() / 1000000;
String uptime_unit;
if (uptime < 120) {
uptime_unit = " seconds";
} else {
if (uptime < 2 * 3600) {
uptime /= 60;
uptime_unit = " minutes";
} else if (uptime < 2 * 3600 * 24) {
uptime /= 3600;
uptime_unit = " hours";
} else {
uptime /= 86400;
uptime_unit = " days";
}
}
return String(uptime) + " " + uptime_unit;
}
void webserver_init() {
// Route for root / web page
@@ -76,24 +97,24 @@ void webserver_init() {
server.on("/api/config", HTTP_GET, [](AsyncWebServerRequest *request){
StaticJsonDocument<512> doc;
doc["systemName"] = "Keypad1";
doc["systemName"] = config.getString("systemName");
doc["systemMode"] = String(config.getChar("systemMode"));
doc["logLevel"] = 0;
doc["version"] = VERSION;
doc["fwtype"] = "unknown";
doc["fwtype"] = "unknown"; // TODO ?
doc["salt"] = "secret";
doc["AdminPassword"] = "********";
doc["useAdminPass"] = false;
doc["apEnable"] = true;
doc["apIp"] = "192.168.15.1";
doc["apMask"] = "255.255.255.0";
doc["useAdminPass"] = "false"; //config.getBool("useAdminPass") ? "true" : "false";
doc["apEnable"] = "true";
doc["apIp"] = config.getString("apIp");
doc["apMask"] = config.getString("apMask");
doc["apPassword"] = "********";
doc["stopApTime"] = 0;
doc["stopApTime"] = config.getShort("stopApTime");
doc["cpuSpeed"] = 160;
doc["tempFormat"] = "C";
doc["tempFormat"] = String(config.getChar("tempFormat"));
doc["ledBrightness"] = led_brightness;
doc["ledRgbBrightness"] = rgb_brightness;
doc["tempFormat"] = "C";
doc["switchBank"] = 0;
doc["switchBank"] = config.getByte("switchBank");
doc["key1"] = keycode[BUTTON_1];
doc["key2"] = keycode[BUTTON_2];
doc["key3"] = keycode[BUTTON_3];
@@ -106,7 +127,7 @@ void webserver_init() {
doc["key4long"] = longcode[BUTTON_4];
doc["key5long"] = longcode[BUTTON_5];
doc["key6long"] = longcode[BUTTON_6];
doc["envInterval"] = 5;
doc["envInterval"] = 5; // config.getShort("envInterval");
String out;
serializeJson(doc, out);
request->send(200, "application/json", out);
@@ -122,16 +143,12 @@ void webserver_init() {
server.on("/api/status", HTTP_GET, [](AsyncWebServerRequest *request){
StaticJsonDocument<200> doc;
doc["version"] = VERSION;
int cpu_freq = esp_clk_cpu_freq() / 1000000;
doc["cpuspeed"] = String(cpu_freq) + "MHz";
char ssid[13];
snprintf(ssid, 13, "%04X%08X", (uint16_t)(chipid >> 32), (uint32_t)chipid);
doc["chipid"] = String(ssid);
doc["uptime"] = uptime_with_unit();
doc["heap"]=(long)xPortGetFreeHeapSize();
doc["temp"] = String(temp, 1);
@@ -147,6 +164,9 @@ void webserver_init() {
doc["version"] = VERSION;
doc["build_date"] = BUILD_DATE;
doc["build_time"] = BUILD_TIME;
String out;
serializeJson(doc, out);
request->send(200, "application/json", out);
});
server.on("/api/setconfig", HTTP_POST, [](AsyncWebServerRequest *request){
@@ -187,4 +207,30 @@ void webserver_init() {
});
server.on("/api/devicelist", HTTP_GET, [](AsyncWebServerRequest *request){
// NMEA2000 device list
AsyncResponseStream *response = request->beginResponseStream("application/json");
response->print("[");
bool first = true;
for (int i = 0; i <= 252; i++) {
const tNMEA2000::tDevice *d = pN2kDeviceList->FindDeviceBySource(i);
if (d == nullptr) {
continue;
}
uint64_t NAME = d->GetName();
char hex_name[17];
snprintf(hex_name, sizeof(hex_name), "%08X%08X", (uint32_t)(NAME >> 32), (uint32_t)(NAME & 0xFFFFFFFF));
if (!first) {
response->print(",");
} else {
first = false;
}
// TODO last seen?
response->printf("{\"source\":%d,\"name\":\"%s\",\"manuf\":\"%d\",\"model\":\"%s\"}",
i, hex_name, d->GetManufacturerCode(), d->GetModelID());
}
response->print("]");
request->send(response);
});
}