Fix BLE scan + touch logic + UUID + version read
Some checks failed
CI / android (push) Has been cancelled
CI / firmware (push) Has been cancelled

- Client: change passive BLE scan to active scan (setActiveScan(true))
  Server puts name/UUID in scan response; passive scan never
  received them, so isAdvertisingService() and getName() failed.
- Server: add INPUT_PULLUP on touch pins to prevent floating
  triggers when sensors disconnected
- Server: update BLE UUID characteristic in SET_ID handler
  (pUuidChar->setValue) so reconnecting clients see correct UUID
- Server: touch logic changed from t1Active/t2Active to
  !t1Active/!t2Active (door closed = relay ON)
- Android: flushReadBuffer before VERSION? to discard stale
  boot log output; use Regex for BUILD_NR parsing
- copy_firmware.sh: copy to firmware/server/ and firmware/client/
  subdirectories to match EspFlasher.assetPath()
- version.txt: server=20 client=5
This commit is contained in:
eddy 2026-08-03 16:38:26 +02:00
commit cd2d949f87
7 changed files with 64 additions and 31 deletions

View file

@ -440,6 +440,8 @@ class SettingsActivity : AppCompatActivity() {
showProgressDialog(getString(R.string.title_firmware_flash), getString(R.string.msg_checking_version), STYLE_SPINNER)
lifecycleScope.launch {
val expected = getExpectedFirmwareVersion()
Log.d(TAG, "doFlashing: expected firmware version=$expected, expectingReboot=$expectingReboot")
val version = readEspVersion(usbManager, device)
if (version == getExpectedFirmwareVersion() && !expectingReboot) {
Log.d(TAG, "Firmware version $version matches, up to date")
@ -583,7 +585,17 @@ class SettingsActivity : AppCompatActivity() {
}
private fun readEspVersion(usbManager: UsbManager, device: UsbDevice): String? {
val intf = UsbUtils.findCdcDataInterface(device) ?: return null
Log.d(TAG, "readEspVersion: device=${device.deviceName}, id=${device.deviceId}, interfaces=${device.interfaceCount}")
for (i in 0 until device.interfaceCount) {
val intf = device.getInterface(i)
Log.d(TAG, "readEspVersion: intf[$i]=class:0x${intf.interfaceClass.toString(16)} subclass:0x${intf.interfaceSubclass.toString(16)} proto:0x${intf.interfaceProtocol.toString(16)} eps=${intf.endpointCount}")
}
val intf = UsbUtils.findCdcDataInterface(device)
if (intf == null) {
Log.w(TAG, "readEspVersion: no CDC data interface (class 0x0A) found")
return null
}
Log.d(TAG, "readEspVersion: found CDC data iface=${intf.id}")
val connection = usbManager.openDevice(device) ?: return null
if (!connection.claimInterface(intf, true)) { connection.close(); return null }
@ -595,12 +607,18 @@ class SettingsActivity : AppCompatActivity() {
return try {
setupCdcControl(connection, device)
Thread.sleep(KEY_SETTLE_MS)
flushReadBuffer(connection, epIn)
val cmd = "VERSION?\n".toByteArray(StandardCharsets.US_ASCII)
connection.bulkTransfer(epOut, cmd, cmd.size, USB_BULK_TIMEOUT_MS)
val writeResult = connection.bulkTransfer(epOut, cmd, cmd.size, USB_BULK_TIMEOUT_MS)
Log.d(TAG, "readEspVersion: bulkTransfer OUT result=$writeResult (expected ${cmd.size})")
Thread.sleep(RESPONSE_WAIT_MS)
val response = readResponse(connection, epIn, VERSION_TIMEOUT_MS)
val versionLine = response.lines().firstOrNull { it.startsWith("BUILD_NR:") }
versionLine?.removePrefix("BUILD_NR:")?.trim()
Log.d(TAG, "readEspVersion: raw response='${response.replace("\r", "\\r").replace("\n", "\\n")}' (len=${response.length})")
val match = Regex("BUILD_NR:(\\d+)").find(response)
Log.d(TAG, "readEspVersion: regex match=$match, group1=${match?.groupValues?.get(1)}")
match?.groupValues?.get(1)
} finally {
connection.close()
}
@ -753,16 +771,20 @@ class SettingsActivity : AppCompatActivity() {
val sb = StringBuilder()
val startTime = System.currentTimeMillis()
var reads = 0
while (System.currentTimeMillis() - startTime < timeoutMs) {
val len = connection.bulkTransfer(epIn, buf, buf.size, READ_CHUNK_TIMEOUT_MS)
if (len > 0) {
reads++
sb.append(String(buf, 0, len, StandardCharsets.US_ASCII))
Log.d(TAG, "readResponse: chunk len=$len, sb now='${sb.toString().replace("\r","\\r").replace("\n","\\n")}'")
if ((sb.contains("HMAC_KEY:") || sb.contains("NO_KEY") || sb.contains("OK") || sb.contains("ERROR")) && sb.contains("\n")) {
break
}
}
}
Log.d(TAG, "readResponse: done after ${System.currentTimeMillis()-startTime}ms, ${reads} reads, response='${sb.toString().replace("\r","\\r").replace("\n","\\n")}'")
return sb.toString()
}

View file

@ -66,6 +66,7 @@ class MyScanCallbacks : public NimBLEScanCallbacks {
serverAddress = advertisedDevice->getAddress();
serverFound = true;
NimBLEDevice::getScan()->stop();
ESP_LOGI(TAG, "Found server: %s", advertisedDevice->getAddress().toString().c_str());
}
}
};
@ -220,8 +221,8 @@ void setup() {
allProvisioned = keyProvisioned && uuidProvisioned && serverProvisioned;
pinMode(TOUCH1_PIN, INPUT);
pinMode(TOUCH2_PIN, INPUT);
pinMode(TOUCH1_PIN, INPUT_PULLUP);
pinMode(TOUCH2_PIN, INPUT_PULLUP);
pinMode(BUTTON_PIN, INPUT);
if (allProvisioned) {
@ -231,7 +232,7 @@ void setup() {
pScan->setScanCallbacks(new MyScanCallbacks());
pScan->setInterval(97);
pScan->setWindow(37);
pScan->setActiveScan(false);
pScan->setActiveScan(true);
pScan->setMaxResults(0);
bleReady = true;
ESP_LOGI(TAG, "BLE: initialized, scanning for service UUID");
@ -286,7 +287,7 @@ void loop() {
pScan->setScanCallbacks(new MyScanCallbacks());
pScan->setInterval(97);
pScan->setWindow(37);
pScan->setActiveScan(false);
pScan->setActiveScan(true);
pScan->setMaxResults(0);
bleReady = true;
ESP_LOGI(TAG, "BLE: initialized after key provisioning");
@ -329,7 +330,7 @@ void loop() {
pScan->setScanCallbacks(new MyScanCallbacks());
pScan->setInterval(97);
pScan->setWindow(37);
pScan->setActiveScan(false);
pScan->setActiveScan(true);
pScan->setMaxResults(0);
bleReady = true;
ESP_LOGI(TAG, "BLE: initialized after server provisioning");

View file

@ -48,6 +48,7 @@ CRGB leds[NUM_LEDS];
#define FIRMWARE_VERSION FIRMWARE_VERSION_SERVER
NimBLECharacteristic *pCharacteristic;
NimBLECharacteristic *pUuidChar;
bool relay1State = false;
bool relay2State = false;
@ -401,8 +402,8 @@ void setup() {
ESP_LOGD(TAG, "Generated new UUID");
}
pinMode(TOUCH1_PIN, INPUT);
pinMode(TOUCH2_PIN, INPUT);
pinMode(TOUCH1_PIN, INPUT_PULLUP);
pinMode(TOUCH2_PIN, INPUT_PULLUP);
pinMode(BUTTON_PIN, INPUT);
pinMode(RELAY1_PIN, OUTPUT);
pinMode(RELAY2_PIN, OUTPUT);
@ -424,7 +425,7 @@ void setup() {
);
pCharacteristic->setCallbacks(new MyCharacteristicCallbacks());
NimBLECharacteristic *pUuidChar = pService->createCharacteristic(
pUuidChar = pService->createCharacteristic(
UUID_CHAR_UUID,
NIMBLE_PROPERTY::READ
);
@ -488,6 +489,7 @@ void loop() {
} else if (serialBuf == "ID?") {
Serial.println("SylDa_Server");
} else if (serialBuf == "VERSION?") {
Serial.flush();
Serial.print("BUILD_NR:");
Serial.println(FIRMWARE_VERSION);
} else if (serialBuf.startsWith("SET_KEY:")) {
@ -515,6 +517,7 @@ void loop() {
preferences.putBytes(NVS_UUID_NAME, deviceUuid, ESP_UUID_LEN);
preferences.end();
uuidProvisioned = true;
pUuidChar->setValue(deviceUuid, ESP_UUID_LEN);
Serial.println("OK");
Serial.println("UUID stored in NVS");
} else {
@ -585,9 +588,9 @@ void loop() {
bool btnActive = (millis() - btnChange > DEBOUNCE_MS) && btnStable;
if (!otaInProgress) {
relay1State = t1Active || btnActive ||
relay1State = !t1Active || btnActive ||
(connActive[0] && bleRelay1[0]) || (connActive[1] && bleRelay1[1]);
relay2State = t2Active ||
relay2State = !t2Active ||
(connActive[0] && bleRelay2[0]) || (connActive[1] && bleRelay2[1]);
} else {
relay1State = false;

View file

@ -1,22 +1,29 @@
#!/bin/bash
set -e
BINARY_DIR="$(cd "$(dirname "$0")/.." && pwd)/.pio/build/s3lite-server"
ASSETS_DIR="$(cd "$(dirname "$0")/.." && pwd)/android/app/src/main/assets/firmware"
PROJECT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
ASSETS_BASE="$PROJECT_DIR/android/app/src/main/assets/firmware"
mkdir -p "$ASSETS_DIR"
copy_binaries() {
local BINARY_DIR="$1"
local ASSETS_DIR="$2"
cp "$BINARY_DIR/bootloader.bin" "$ASSETS_DIR/"
cp "$BINARY_DIR/partitions.bin" "$ASSETS_DIR/"
cp "$BINARY_DIR/firmware.bin" "$ASSETS_DIR/"
mkdir -p "$ASSETS_DIR"
cp "$BINARY_DIR/bootloader.bin" "$ASSETS_DIR/"
cp "$BINARY_DIR/partitions.bin" "$ASSETS_DIR/"
cp "$BINARY_DIR/firmware.bin" "$ASSETS_DIR/"
BOOT_APP0=$(find ~/.platformio/packages/framework-arduinoespressif32 -name "boot_app0.bin" 2>/dev/null | head -1)
if [ -n "$BOOT_APP0" ]; then
BOOT_APP0=$(find ~/.platformio/packages/framework-arduinoespressif32 -name "boot_app0.bin" 2>/dev/null | head -1)
if [ -n "$BOOT_APP0" ]; then
cp "$BOOT_APP0" "$ASSETS_DIR/"
else
else
echo "ERROR: boot_app0.bin not found"
exit 1
fi
fi
echo "Firmware binaries copied to $ASSETS_DIR:"
ls -la "$ASSETS_DIR"
echo "Copied to $ASSETS_DIR:"
ls -la "$ASSETS_DIR"
}
copy_binaries "$PROJECT_DIR/.pio/build/s3lite-server" "$ASSETS_BASE/server"
copy_binaries "$PROJECT_DIR/.pio/build/s3lite-client" "$ASSETS_BASE/client"

View file

@ -1,2 +1,2 @@
server=17
client=3
server=20
client=5