Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down Expand Up @@ -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 \
Expand All @@ -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',
Expand Down
6 changes: 6 additions & 0 deletions example-client.html
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ <h1>☕ Jura Coffee Maker API Client</h1>

<div class="section">
<h2>Connection</h2>
<button onclick="listDevices()">List Devices</button>
<input type="text" id="deviceAddress" placeholder="AA:BB:CC:DD:EE:FF" value="AA:BB:CC:DD:EE:FF">
<button onclick="connect()">Connect</button>
<button onclick="disconnect()">Disconnect</button>
Expand Down Expand Up @@ -119,6 +120,11 @@ <h2>Custom Command</h2>
}
}

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 });
Expand Down
24 changes: 24 additions & 0 deletions src/api_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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"},
Expand Down
32 changes: 32 additions & 0 deletions src/jura_controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,38 @@ bool JuraController::isConnected() const {
return pImpl->protocol->isConnected();
}

nlohmann::json JuraController::listDevices() {
nlohmann::json result;

try {
std::vector<std::string> 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();
Expand Down
3 changes: 3 additions & 0 deletions src/jura_controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
24 changes: 24 additions & 0 deletions src/jura_protocol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,30 @@ bool JuraProtocol::isConnected() const {
return connected_;
}

std::vector<std::string> 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<std::string> 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";
Expand Down
3 changes: 3 additions & 0 deletions src/jura_protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ class JuraProtocol {
bool connectDevice(const std::string& device_address);
bool disconnectDevice();
bool isConnected() const;

// Device discovery
std::vector<std::string> listDevices();

// Protocol commands
std::string sendCommand(const std::string& command);
Expand Down
1 change: 1 addition & 0 deletions test-api.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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" ""
Expand Down