From f8c690d6a5ef4f57d25e96b12c41d705872640d3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 26 Dec 2025 16:34:15 +0000 Subject: [PATCH 1/4] Initial plan From 9ba168c3c6b7db24ef128f6ac359a252ef54fe13 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 26 Dec 2025 16:38:21 +0000 Subject: [PATCH 2/4] Add /api/devices endpoint to list available Jura devices Co-authored-by: 8de2fdb0 <89734465+8de2fdb0@users.noreply.github.com> --- src/api_server.cpp | 24 ++++++++++++++++++++++++ src/jura_controller.cpp | 32 ++++++++++++++++++++++++++++++++ src/jura_controller.h | 3 +++ src/jura_protocol.cpp | 24 ++++++++++++++++++++++++ src/jura_protocol.h | 3 +++ test-api.sh | 1 + 6 files changed, 87 insertions(+) diff --git a/src/api_server.cpp b/src/api_server.cpp index 4c97238..ead0bc1 100644 --- a/src/api_server.cpp +++ b/src/api_server.cpp @@ -43,6 +43,25 @@ ApiServer::ApiServer(int port) res.set_content(response.dump(), "application/json"); }); + // List devices endpoint + pImpl->server->Get("/api/devices", [this, setCorsHeaders](const httplib::Request&, httplib::Response& res) { + try { + json response = controller_->listDevices(); + setCorsHeaders(res); + res.set_content(response.dump(), "application/json"); + } catch (const std::exception& e) { + json response = { + {"success", false}, + {"error", e.what()}, + {"devices", json::array()}, + {"count", 0} + }; + setCorsHeaders(res); + res.status = 500; + res.set_content(response.dump(), "application/json"); + } + }); + // Connect to device endpoint pImpl->server->Post("/api/connect", [this, setCorsHeaders](const httplib::Request& req, httplib::Response& res) { try { @@ -172,6 +191,11 @@ ApiServer::ApiServer(int port) {"method", "GET"}, {"description", "Get current connection status"} }, + { + {"path", "/api/devices"}, + {"method", "GET"}, + {"description", "List available Jura devices"} + }, { {"path", "/api/connect"}, {"method", "POST"}, diff --git a/src/jura_controller.cpp b/src/jura_controller.cpp index 9d153f3..e9eb528 100644 --- a/src/jura_controller.cpp +++ b/src/jura_controller.cpp @@ -34,6 +34,38 @@ bool JuraController::isConnected() const { return pImpl->protocol->isConnected(); } +nlohmann::json JuraController::listDevices() { + nlohmann::json result; + + try { + std::vector devices = pImpl->protocol->listDevices(); + + // Filter to only include Jura devices + // In a real implementation, this would check device names, + // service UUIDs, or other characteristics to identify Jura devices + nlohmann::json deviceList = nlohmann::json::array(); + + for (const auto& deviceAddress : devices) { + nlohmann::json device; + device["address"] = deviceAddress; + device["name"] = "Jura Coffee Maker"; // In production, query actual device name + device["type"] = "jura"; + deviceList.push_back(device); + } + + result["success"] = true; + result["devices"] = deviceList; + result["count"] = deviceList.size(); + } catch (const std::exception& e) { + result["success"] = false; + result["error"] = e.what(); + result["devices"] = nlohmann::json::array(); + result["count"] = 0; + } + + return result; +} + nlohmann::json JuraController::getStatus() { nlohmann::json status; status["connected"] = pImpl->protocol->isConnected(); diff --git a/src/jura_controller.h b/src/jura_controller.h index f952814..3dfb48c 100644 --- a/src/jura_controller.h +++ b/src/jura_controller.h @@ -18,6 +18,9 @@ class JuraController { bool connect(const std::string& device_address); bool disconnect(); bool isConnected() const; + + // Device discovery + nlohmann::json listDevices(); // Coffee maker commands nlohmann::json getStatus(); diff --git a/src/jura_protocol.cpp b/src/jura_protocol.cpp index 73dd8e4..739c237 100644 --- a/src/jura_protocol.cpp +++ b/src/jura_protocol.cpp @@ -75,6 +75,30 @@ bool JuraProtocol::isConnected() const { return connected_; } +std::vector JuraProtocol::listDevices() { + // TODO: Actual device scanning using protocol-bt-cpp + // This would use BLE scanning to discover nearby Bluetooth devices + // and filter for devices that match Jura device characteristics + + std::cout << "Scanning for Jura devices..." << std::endl; + + // Simulate device discovery + // In production, this would: + // 1. Scan for BLE devices + // 2. Filter by service UUIDs or device names matching Jura devices + // 3. Return list of device addresses + + std::vector devices = { + "AA:BB:CC:DD:EE:01", // Simulated Jura device 1 + "AA:BB:CC:DD:EE:02", // Simulated Jura device 2 + "AA:BB:CC:DD:EE:03" // Simulated Jura device 3 + }; + + std::cout << "Found " << devices.size() << " Jura device(s)" << std::endl; + + return devices; +} + std::string JuraProtocol::sendCommand(const std::string& command) { if (!connected_) { return "ERROR: Not connected"; diff --git a/src/jura_protocol.h b/src/jura_protocol.h index a4f255d..d17b75e 100644 --- a/src/jura_protocol.h +++ b/src/jura_protocol.h @@ -20,6 +20,9 @@ class JuraProtocol { bool connectDevice(const std::string& device_address); bool disconnectDevice(); bool isConnected() const; + + // Device discovery + std::vector listDevices(); // Protocol commands std::string sendCommand(const std::string& command); diff --git a/test-api.sh b/test-api.sh index f1234c7..91fccdc 100755 --- a/test-api.sh +++ b/test-api.sh @@ -40,6 +40,7 @@ test_endpoint() { test_endpoint "Health Check" "GET" "/health" "" test_endpoint "API Documentation" "GET" "/api" "" test_endpoint "Initial Status" "GET" "/api/status" "" +test_endpoint "List Devices" "GET" "/api/devices" "" test_endpoint "Connect to Device" "POST" "/api/connect" '{"device_address":"AA:BB:CC:DD:EE:FF"}' test_endpoint "Status After Connection" "GET" "/api/status" "" test_endpoint "Device Info" "GET" "/api/device-info" "" From b9e3ac51e74e6d78f7468ce297f8c3599d2057fe Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 26 Dec 2025 16:40:22 +0000 Subject: [PATCH 3/4] Update example client with List Devices button Co-authored-by: 8de2fdb0 <89734465+8de2fdb0@users.noreply.github.com> --- example-client.html | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/example-client.html b/example-client.html index b5ef96e..378be3c 100644 --- a/example-client.html +++ b/example-client.html @@ -66,6 +66,7 @@

☕ Jura Coffee Maker API Client

Connection

+ @@ -119,6 +120,11 @@

Custom Command

} } + async function listDevices() { + const result = await apiCall('/api/devices'); + document.getElementById('connectionResponse').textContent = JSON.stringify(result, null, 2); + } + async function connect() { const deviceAddress = document.getElementById('deviceAddress').value; const result = await apiCall('/api/connect', 'POST', { device_address: deviceAddress }); From c7cdbbf05249b10b209f1e1bf500154c95155944 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 26 Dec 2025 16:44:05 +0000 Subject: [PATCH 4/4] Update README with /api/devices endpoint documentation Co-authored-by: 8de2fdb0 <89734465+8de2fdb0@users.noreply.github.com> --- README.md | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/README.md b/README.md index de2dbbf..4f459fa 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,29 @@ Get current connection status. } ``` +### GET /api/devices +List available Jura devices. + +**Response:** +```json +{ + "success": true, + "count": 3, + "devices": [ + { + "address": "AA:BB:CC:DD:EE:01", + "name": "Jura Coffee Maker", + "type": "jura" + }, + { + "address": "AA:BB:CC:DD:EE:02", + "name": "Jura Coffee Maker", + "type": "jura" + } + ] +} +``` + ### POST /api/connect Connect to a Jura device. @@ -154,6 +177,11 @@ Get information about the connected device. ### Using curl +List available devices: +```bash +curl http://localhost:8080/api/devices +``` + Connect to device: ```bash curl -X POST http://localhost:8080/api/connect \ @@ -176,6 +204,11 @@ curl http://localhost:8080/api/status ### Using JavaScript/Fetch ```javascript +// List available devices +fetch('http://localhost:8080/api/devices') + .then(res => res.json()) + .then(data => console.log(data)); + // Connect to device fetch('http://localhost:8080/api/connect', { method: 'POST',