# Network Scanning Comparison: add-hub Tool vs list-all-devices Script
## Executive Summary
The `add-hub` tool and `list-all-devices` script use **completely different approaches** for finding Plugwise hubs:
- **list-all-devices.ts**: No network scanning - uses pre-configured IPs from `.env`
- **add-hub tool**: Full network scan - tries all 254 IPs with provided password
## Detailed Comparison
### list-all-devices.ts Approach
**File**: `/scripts/list-all-devices.ts`
**Method**: Direct connection to known hubs
```typescript
// 1. Parse .env for HUB1, HUB1IP, HUB2, HUB2IP, etc.
function parseHubs(): Array<{ name: string, host: string, password: string }> {
const hubs: Array<{ name: string, host: string, password: string }> = [];
let hubNum = 1;
while (true) {
const hubId = process.env[`HUB${hubNum}`]; // Password
const hubIp = process.env[`HUB${hubNum}IP`]; // IP address
if (!hubId || !hubIp) {
break;
}
hubs.push({
name: `HUB${hubNum}`,
host: hubIp, // Known IP
password: hubId
});
hubNum++;
}
return hubs;
}
// 2. Connect directly to each known IP
const client = new PlugwiseClient({
host: hub.host, // Uses the known IP from .env
password: hub.password
});
const gatewayInfo = await client.connect();
```
**Characteristics**:
- ✅ Fast - only connects to known IPs
- ✅ Reliable - no network scanning overhead
- ❌ Requires pre-configuration in `.env`
- ❌ Cannot discover new hubs automatically
- ⏱️ Time: ~1-2 seconds per hub (connection time only)
---
### add-hub Tool Approach
**Files**:
- `/src/mcp/tools/add-hub.tool.ts`
- `/src/services/hub-discovery.service.ts`
**Method**: Full network scan with brute force IP discovery
```typescript
// 1. User provides only the hub name/password
const result = await discoveryService.addHubByName(hubName);
// 2. HubDiscoveryService.addHubByName() method:
async addHubByName(hubName: string) {
// First, check saved hub file
const existingHub = await this.loadHubFromFile(hubName);
if (existingHub) {
// Try saved IP first
try {
const testClient = new PlugwiseClient({
host: existingHub.ip,
password: hubName
});
const gatewayInfo = await testClient.connect();
// Success - use saved IP
return { success: true, hub: updatedHub };
} catch (error) {
// Saved IP failed, continue to network scan
}
}
// 3. Scan entire network
const hub = await this.scanForSpecificHub(networkToScan, hubName);
}
// 4. scanForSpecificHub() - THE ACTUAL SCANNING:
private async scanForSpecificHub(network: string, hubName: string) {
const [baseIp] = network.split('/');
const [octet1, octet2, octet3] = baseIp.split('.');
const networkBase = `${octet1}.${octet2}.${octet3}`;
const scanPromises: Promise<DiscoveredHub | null>[] = [];
// Try ALL IPs from .1 to .254
for (let lastOctet = 1; lastOctet <= 254; lastOctet++) {
const ip = `${networkBase}.${lastOctet}`;
scanPromises.push(
(async () => {
try {
const testClient = new PlugwiseClient({
host: ip, // Try THIS specific IP
password: hubName // With provided password
});
// 2-second timeout per IP
const timeoutPromise = new Promise<never>((_, reject) =>
setTimeout(() => reject(new Error('timeout')), 2000)
);
const gatewayInfo = await Promise.race([
testClient.connect(),
timeoutPromise
]);
if (gatewayInfo) {
return hub; // Found it!
}
} catch (error) {
// Ignore failures, keep scanning
}
return null;
})()
);
}
// Wait for ALL 254 connection attempts
const results = await Promise.all(scanPromises);
return results.find(hub => hub !== null) || null;
}
```
**Characteristics**:
- ✅ Can discover new hubs without pre-configuration
- ✅ Saves discovered hubs to `/hubs` folder for future use
- ❌ Slow - tests up to 254 IPs
- ❌ Resource intensive - 254 parallel connection attempts
- ⏱️ Time: ~2-5 seconds (limited by timeout, runs in parallel)
---
## Key Differences
| Aspect | list-all-devices | add-hub Tool |
|--------|-----------------|--------------|
| **Configuration** | Requires `.env` with HUBxIP | Only needs hub password |
| **Discovery** | No discovery | Full network scan |
| **IPs Tested** | Only known IPs (1-5 typical) | All 254 IPs in subnet |
| **Parallelization** | Sequential connections | 254 parallel attempts |
| **Timeout per IP** | 10 seconds (default) | 2 seconds |
| **Speed** | Fast (2-10 seconds total) | Moderate (2-5 seconds) |
| **Use Case** | Known hub management | Hub discovery |
| **Storage** | Uses `.env` only | Saves to `/hubs/*.json` |
---
## Network Scan Performance Analysis
### add-hub Tool Scanning Behavior:
1. **Parallel Execution**: All 254 IPs are tested simultaneously
```typescript
const scanPromises: Promise<DiscoveredHub | null>[] = [];
// Creates 254 promises
for (let lastOctet = 1; lastOctet <= 254; lastOctet++) { ... }
await Promise.all(scanPromises); // Waits for all
```
2. **Timeout Strategy**: 2-second timeout per IP
- If hub found: Returns immediately when first success
- If hub not found: Waits full 2 seconds for all attempts
- Network hosts that don't exist: May timeout quickly (depends on network stack)
3. **Early Return Optimization**:
```typescript
const results = await Promise.all(scanPromises);
return results.find(hub => hub !== null) || null;
```
- The code waits for ALL promises to complete
- Then returns the first successful result
- **Potential Improvement**: Could use `Promise.race()` to return as soon as ANY hub is found
---
## Potential Issues with add-hub Scanning
### Issue 1: No Early Exit
**Current**: Waits for all 254 attempts even if hub found in first 10 IPs
**Impact**: Wastes time waiting for timeouts on remaining IPs
**Solution**:
```typescript
// Use Promise.race() or implement cancellation
const results = await Promise.race(
scanPromises.map(p => p.then(result => result ? result : null))
);
```
### Issue 2: Timeout Too Short?
**Current**: 2-second timeout
**Impact**: Might be too aggressive for slow networks or busy hubs
**Recommendation**: Consider increasing to 3-5 seconds
### Issue 3: Resource Intensive
**Current**: 254 simultaneous HTTP connections
**Impact**: May overwhelm network stack or hub
**Solution**: Consider batched scanning (e.g., 50 IPs at a time)
---
## Recommendations
### For list-all-devices.ts:
✅ Current approach is optimal for its use case (known hubs)
### For add-hub Tool:
1. **Add Early Exit**:
```typescript
// Stop scanning once hub is found
let foundHub: DiscoveredHub | null = null;
const scanPromises = [];
for (let i = 1; i <= 254; i++) {
scanPromises.push(
scanSingleIP(i).then(hub => {
if (hub && !foundHub) {
foundHub = hub;
// Cancel remaining scans
}
return hub;
})
);
}
```
2. **Increase Timeout**: Change from 2000ms to 3000ms
3. **Add Progress Logging**:
```typescript
console.log(`Scanning ${networkBase}.1-254...`);
let checked = 0;
// Log progress every 50 IPs
```
4. **Consider Batched Scanning**: Test 50 IPs at a time instead of all 254
---
## Conclusion
The `add-hub` tool **IS scanning the network** correctly - it tests all 254 IPs in the subnet. The difference with `list-all-devices` is:
- **list-all-devices**: Doesn't scan - uses known IPs
- **add-hub**: Scans everything - discovers unknown hubs
The scanning approach is legitimate but could be optimized for:
- Early exit when hub found
- Better resource management
- More user feedback during scan