diff --git a/src/officesense_scanner/platformio.ini b/src/officesense_scanner/platformio.ini index e2ceb56..aa7b0ca 100644 --- a/src/officesense_scanner/platformio.ini +++ b/src/officesense_scanner/platformio.ini @@ -18,6 +18,7 @@ board_build.partitions = default.csv build_flags = -DARDUINO_USB_CDC_ON_BOOT=1 -DBOARD_HAS_PSRAM + -DCORE_DEBUG_LEVEL=0 lib_deps = h2zero/NimBLE-Arduino diff --git a/src/officesense_scanner/src/main.cpp b/src/officesense_scanner/src/main.cpp index 51084da..92871fb 100644 --- a/src/officesense_scanner/src/main.cpp +++ b/src/officesense_scanner/src/main.cpp @@ -5,9 +5,14 @@ #include "freertos/queue.h" #include #include +#include +#include "esp_system.h" +Preferences prefs; +Config config; CB cb; -char MQTT_PUB_TOPIC[sizeof(MQTT_TOPIC) + sizeof(DEV_NAME) - 1]; +String MQTT_PUB_TOPIC; +String serial_buffer = ""; std::unordered_map tags; std::unordered_map uuid_cache; SemaphoreHandle_t uuid_mtx; @@ -27,7 +32,7 @@ void cleanupCache() { uint32_t age = now - it->second.last_check; - if (age > UUID_CACHE_CLEAN_TIMEOUT) + if (age > config.interval.uuid_cache_clean_timeout) { Serial.printf("Erasing %s from cache after being inactive for %dms.\n", it->first.c_str(), @@ -47,7 +52,7 @@ void cleanupTags() for (auto it = tags.begin(); it != tags.end();) { - if ((now - it->second.getLastSeen()) >= TAG_TIMEOUT) + if ((now - it->second.getLastSeen()) >= config.interval.tag_timeout) { Serial.printf("Erasing %s from memory after being inactive for %dms.\n", it->first.c_str(), @@ -69,7 +74,7 @@ void httpTask(void *) { HTTPClient http; - String url = UUID_CHECK_ENDPOINT + String(ev.uuid); + String url = config.api.url + config.api.uuid_check_endpoint + String("/") + String(ev.uuid); http.setTimeout(3000); http.setReuse(false); @@ -82,6 +87,19 @@ void httpTask(void *) int code = http.GET(); + if (code < 0) + { + xSemaphoreTake(uuid_mtx, portMAX_DELAY); + uuid_cache[ev.uuid] = { + UUIDState::RETRY, + millis()}; + + xSemaphoreGive(uuid_mtx); + + http.end(); + continue; + } + bool valid = (code == 200); http.end(); @@ -110,8 +128,8 @@ void mqttTask(void *) { while (!mqtt.connected()) { - Serial.printf("MQTT Disconnected. Connecting to %s:%d\n", MQTT_HOST, MQTT_PORT); - if (mqtt.connect(DEV_NAME, MQTT_USER, MQTT_PASS)) + Serial.printf("MQTT Disconnected. Connecting to %s:%d\n", config.mqtt.host.c_str(), config.mqtt.port); + if (mqtt.connect(config.dev_name.c_str(), config.mqtt.username.c_str(), config.mqtt.password.c_str())) Serial.println("MQTT connected."); vTaskDelay(pdMS_TO_TICKS(1000)); } @@ -125,7 +143,7 @@ void mqttTask(void *) ev.uuid, ev.ema); - bool ok = mqtt.publish(MQTT_PUB_TOPIC, payload); + bool ok = mqtt.publish(MQTT_PUB_TOPIC.c_str(), payload); if (!ok) Serial.println("Failed to publish on MQTT."); @@ -143,7 +161,7 @@ void processEvent(const BleEvent &event) uint32_t now = millis(); - if (it == uuid_cache.end()) + if (it == uuid_cache.end() || (it->second.state == UUIDState::RETRY)) { uuid_cache[event.uuid] = {UUIDState::PENDING, now}; @@ -158,7 +176,7 @@ void processEvent(const BleEvent &event) } if (it->second.state == UUIDState::INVALID && - now - it->second.last_check > UUID_CACHE_RETRY_TIMEOUT) + now - it->second.last_check > config.interval.uuid_cache_retry_timeout) { it->second.state = UUIDState::PENDING; it->second.last_check = now; @@ -202,9 +220,9 @@ void CB::onResult(const NimBLEAdvertisedDevice *d) return; NimBLEUUID uuid = d->getServiceUUID(0); - const std::string &name = d->getName(); + const String name(d->getName().c_str()); - if ((uuid.bitSize() != 128) || (name != TAG_NAME)) + if ((uuid.bitSize() != 128) || (name != config.tag_name)) return; BleEvent event; @@ -215,23 +233,170 @@ void CB::onResult(const NimBLEAdvertisedDevice *d) xQueueSend(ble_queue, &event, pdMS_TO_TICKS(5)); } +void saveConfig() +{ + prefs.begin("config", false); + + prefs.putUInt(CLEANUP_INTERVAL_CONFIG_KEY, config.interval.cleanup); + prefs.putUInt(TAG_TIMEOUT_CONFIG_KEY, config.interval.tag_timeout); + prefs.putUInt(UUID_CACHE_RETRY_TIMEOUT_CONFIG_KEY, config.interval.uuid_cache_retry_timeout); + prefs.putUInt(UUID_CACHE_CLEAN_TIMEOUT_CONFIG_KEY, config.interval.uuid_cache_clean_timeout); + + prefs.putString(API_URL_CONFIG_KEY, config.api.url); + prefs.putString(UUID_CHECK_ENDPOINT_CONFIG_KEY, config.api.uuid_check_endpoint); + + prefs.putString(MQTT_HOST_CONFIG_KEY, config.mqtt.host); + prefs.putUShort(MQTT_PORT_CONFIG_KEY, config.mqtt.port); + prefs.putString(MQTT_USER_CONFIG_KEY, config.mqtt.username); + prefs.putString(MQTT_PASS_CONFIG_KEY, config.mqtt.password); + prefs.putString(MQTT_TOPIC_CONFIG_KEY, config.mqtt.topic); + + prefs.putString(WIFI_SSID_CONFIG_KEY, config.wifi.ssid); + prefs.putString(WIFI_PASS_CONFIG_KEY, config.wifi.password); + + prefs.putString(DEV_NAME_CONFIG_KEY, config.dev_name); + prefs.putString(TAG_NAME_CONFIG_KEY, config.tag_name); + + prefs.end(); +} + +void loadConfig() +{ + prefs.begin("config", true); + + config.interval.cleanup = prefs.getUInt(CLEANUP_INTERVAL_CONFIG_KEY, CLEANUP_INTERVAL); + config.interval.tag_timeout = prefs.getUInt(TAG_TIMEOUT_CONFIG_KEY, TAG_TIMEOUT); + config.interval.uuid_cache_retry_timeout = prefs.getUInt(UUID_CACHE_RETRY_TIMEOUT_CONFIG_KEY, UUID_CACHE_RETRY_TIMEOUT); + config.interval.uuid_cache_clean_timeout = prefs.getUInt(UUID_CACHE_CLEAN_TIMEOUT_CONFIG_KEY, UUID_CACHE_CLEAN_TIMEOUT); + + config.api.url = prefs.getString(API_URL_CONFIG_KEY, API_URL); + config.api.uuid_check_endpoint = prefs.getString(UUID_CHECK_ENDPOINT_CONFIG_KEY, UUID_CHECK_ENDPOINT); + + config.mqtt.host = prefs.getString(MQTT_HOST_CONFIG_KEY, MQTT_HOST); + config.mqtt.port = prefs.getUShort(MQTT_PORT_CONFIG_KEY, MQTT_PORT); + config.mqtt.username = prefs.getString(MQTT_USER_CONFIG_KEY, MQTT_USER); + config.mqtt.password = prefs.getString(MQTT_PASS_CONFIG_KEY, MQTT_PASS); + config.mqtt.topic = prefs.getString(MQTT_TOPIC_CONFIG_KEY, MQTT_TOPIC); + + config.wifi.ssid = prefs.getString(WIFI_SSID_CONFIG_KEY, WIFI_SSID); + config.wifi.password = prefs.getString(WIFI_PASS_CONFIG_KEY, WIFI_PASS); + + config.dev_name = prefs.getString(DEV_NAME_CONFIG_KEY, DEV_NAME); + config.tag_name = prefs.getString(TAG_NAME_CONFIG_KEY, TAG_NAME); + + prefs.end(); +} + +void handleCommand(String line) +{ + if (line.startsWith("set ")) + { + int p1 = line.indexOf(' ', 4); + String key = line.substring(4, p1); + String value = line.substring(p1 + 1); + + if (key.length() == 0 || value.length() == 0) + return; + + if (key == CLEANUP_INTERVAL_CONFIG_KEY) + config.interval.cleanup = (uint32_t)value.toInt(); + else if (key == TAG_TIMEOUT_CONFIG_KEY) + config.interval.tag_timeout = (uint32_t)value.toInt(); + else if (key == UUID_CACHE_RETRY_TIMEOUT_CONFIG_KEY) + config.interval.uuid_cache_retry_timeout = (uint32_t)value.toInt(); + else if (key == UUID_CACHE_CLEAN_TIMEOUT_CONFIG_KEY) + config.interval.uuid_cache_clean_timeout = (uint32_t)value.toInt(); + else if (key == API_URL_CONFIG_KEY) + config.api.url = value; + else if (key == UUID_CHECK_ENDPOINT_CONFIG_KEY) + config.api.uuid_check_endpoint = value; + else if (key == MQTT_HOST_CONFIG_KEY) + config.mqtt.host = value; + else if (key == MQTT_PORT_CONFIG_KEY) + config.mqtt.port = value.toInt(); + else if (key == MQTT_USER_CONFIG_KEY) + config.mqtt.username = value; + else if (key == MQTT_PASS_CONFIG_KEY) + config.mqtt.password = value; + else if (key == MQTT_TOPIC_CONFIG_KEY) + config.mqtt.topic = value; + else if (key == WIFI_SSID_CONFIG_KEY) + config.wifi.ssid = value; + else if (key == WIFI_PASS_CONFIG_KEY) + config.wifi.password = value; + else if (key == DEV_NAME_CONFIG_KEY) + config.dev_name = value; + else if (key == TAG_NAME_CONFIG_KEY) + config.tag_name = value; + } + else if (line == "save") + saveConfig(); + else if (line.startsWith("show ")) + { + String key = line.substring(5); + + if (key.length() == 0) + return; + + if (key == CLEANUP_INTERVAL_CONFIG_KEY) + Serial.println(config.interval.cleanup); + else if (key == TAG_TIMEOUT_CONFIG_KEY) + Serial.println(config.interval.tag_timeout); + else if (key == UUID_CACHE_RETRY_TIMEOUT_CONFIG_KEY) + Serial.println(config.interval.uuid_cache_retry_timeout); + else if (key == UUID_CACHE_CLEAN_TIMEOUT_CONFIG_KEY) + Serial.println(config.interval.uuid_cache_clean_timeout); + else if (key == API_URL_CONFIG_KEY) + Serial.println(config.api.url); + else if (key == UUID_CHECK_ENDPOINT_CONFIG_KEY) + Serial.println(config.api.uuid_check_endpoint); + else if (key == MQTT_HOST_CONFIG_KEY) + Serial.println(config.mqtt.host); + else if (key == MQTT_PORT_CONFIG_KEY) + Serial.println(config.mqtt.port); + else if (key == MQTT_USER_CONFIG_KEY) + Serial.println(config.mqtt.username); + else if (key == MQTT_PASS_CONFIG_KEY) + Serial.println(config.mqtt.password); + else if (key == MQTT_TOPIC_CONFIG_KEY) + Serial.println(config.mqtt.topic); + else if (key == WIFI_SSID_CONFIG_KEY) + Serial.println(config.wifi.ssid); + else if (key == WIFI_PASS_CONFIG_KEY) + Serial.println(config.wifi.password); + else if (key == DEV_NAME_CONFIG_KEY) + Serial.println(config.dev_name); + else if (key == TAG_NAME_CONFIG_KEY) + Serial.println(config.tag_name); + } + else if (line == "reboot") + { + Serial.println("Rebooting..."); + Serial.flush(); + esp_restart(); + } + else if (line == "help") + { + Serial.println("Commands:"); + Serial.println(" set - Set a configuration value"); + Serial.println(" show - Show a configuration value"); + Serial.println(" save - Save configuration to non-volatile storage"); + Serial.println(" reboot - Reboot the device"); + Serial.println(" help - Show this help message"); + } +} + void setup() { Serial.begin(115200); - WiFi.begin(WIFI_SSID, WIFI_PASS); + loadConfig(); - while (WiFi.status() != WL_CONNECTED) - { - delay(500); - Serial.print("."); - } + WiFi.begin(config.wifi.ssid.c_str(), config.wifi.password.c_str()); - Serial.println("\nWiFi connected"); + MQTT_PUB_TOPIC = config.mqtt.topic + config.dev_name; - snprintf(MQTT_PUB_TOPIC, sizeof(MQTT_PUB_TOPIC), "%s%s", MQTT_TOPIC, DEV_NAME); - - mqtt.setServer(MQTT_HOST, MQTT_PORT); + mqtt.setServer(config.mqtt.host.c_str(), config.mqtt.port); mqtt.setKeepAlive(60); mqtt.setSocketTimeout(5); @@ -244,7 +409,7 @@ void setup() xTaskCreatePinnedToCore(mqttTask, "mqtt", 4096, NULL, 1, NULL, 1); xTaskCreatePinnedToCore(httpTask, "http", 4096, NULL, 1, NULL, 1); - NimBLEDevice::init(DEV_NAME); + NimBLEDevice::init(config.dev_name.c_str()); NimBLEScan *scan = NimBLEDevice::getScan(); @@ -264,10 +429,45 @@ void loop() static uint32_t last_cleanup = 0; - if (millis() - last_cleanup >= CLEANUP_INTERVAL) + if (millis() - last_cleanup >= config.interval.cleanup) { cleanupTags(); cleanupCache(); last_cleanup = millis(); } + + while (Serial.available()) + { + char c = Serial.read(); + + if (c == '\r') + continue; + + if (c == '\n') + { + Serial.print(c); + serial_buffer.trim(); + + if (serial_buffer.length() > 0) + handleCommand(serial_buffer); + + serial_buffer = ""; + + Serial.printf("%s> ", config.dev_name.c_str()); + } + else if (c == '\b') + { + if (serial_buffer.length() > 0) + { + serial_buffer.remove(serial_buffer.length() - 1); + + Serial.print("\b \b"); + } + } + else + { + Serial.print(c); + serial_buffer += c; + } + } } diff --git a/src/officesense_scanner/src/main.hpp b/src/officesense_scanner/src/main.hpp index 1c48f80..e9e449b 100644 --- a/src/officesense_scanner/src/main.hpp +++ b/src/officesense_scanner/src/main.hpp @@ -5,12 +5,29 @@ #include #include -#define CLEANUP_INTERVAL 5 * 1000 // ms -#define TAG_TIMEOUT 60 * 1000 // ms -#define UUID_CACHE_RETRY_TIMEOUT 5 * 60 * 1000 // ms +#define CLEANUP_INTERVAL_CONFIG_KEY "int.cln" +#define TAG_TIMEOUT_CONFIG_KEY "int.tagto" +#define UUID_CACHE_RETRY_TIMEOUT_CONFIG_KEY "int.urtry" +#define UUID_CACHE_CLEAN_TIMEOUT_CONFIG_KEY "int.ucclean" +#define API_URL_CONFIG_KEY "api.url" +#define UUID_CHECK_ENDPOINT_CONFIG_KEY "api.uuidchk" +#define MQTT_HOST_CONFIG_KEY "mq.host" +#define MQTT_PORT_CONFIG_KEY "mq.port" +#define MQTT_USER_CONFIG_KEY "mq.user" +#define MQTT_PASS_CONFIG_KEY "mq.pass" +#define MQTT_TOPIC_CONFIG_KEY "mq.topic" +#define WIFI_SSID_CONFIG_KEY "wf.ssid" +#define WIFI_PASS_CONFIG_KEY "wf.pass" +#define DEV_NAME_CONFIG_KEY "dev.name" +#define TAG_NAME_CONFIG_KEY "tag.name" + +#define CLEANUP_INTERVAL 5 * 1000 // ms +#define TAG_TIMEOUT 60 * 1000 // ms +#define UUID_CACHE_RETRY_TIMEOUT 5 * 60 * 1000 // ms #define UUID_CACHE_CLEAN_TIMEOUT 60 * 60 * 1000 // ms +#define API_URL "http://192.168.1.2" +#define UUID_CHECK_ENDPOINT "/check" #define TAG_NAME "X6TAG" -#define UUID_CHECK_ENDPOINT "http://192.168.1.2/check/" #define MQTT_HOST "192.168.1.2" #define MQTT_PORT 1883 #define MQTT_USER "user" @@ -20,6 +37,41 @@ #define WIFI_PASS "x32hbh54673ngccdsfa9" #define DEV_NAME "Scanner_Room_A" +struct Config +{ + struct Interval + { + uint32_t cleanup; + uint32_t tag_timeout; + uint32_t uuid_cache_retry_timeout; + uint32_t uuid_cache_clean_timeout; + } interval; + + struct API + { + String url; + String uuid_check_endpoint; + } api; + + struct MQTT + { + String host; + uint16_t port; + String username; + String password; + String topic; + } mqtt; + + struct WiFi + { + String ssid; + String password; + } wifi; + + String dev_name; + String tag_name; +}; + struct BleEvent { char uuid[37]; @@ -40,6 +92,7 @@ struct HttpEvent enum class UUIDState { PENDING, + RETRY, VALID, INVALID };