@shyntech-proximity/sensor-app 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +270 -0
- package/index.js +143 -0
- package/package.json +19 -0
package/README.md
ADDED
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
# Proximity Sensor Service
|
|
2
|
+
|
|
3
|
+
The **Proximity Sensor Service** is a real-time physical–digital bridge that ingests **radio proximity signals** (Wi-Fi, Wi-Fi Direct, BLE) from nearby devices and resolves **nearby vendors and inventories** using SSID / identifier matching.
|
|
4
|
+
|
|
5
|
+
It enables **hyperlocal discovery**, **foot-traffic monetization**, and **ambient commerce** without user interaction.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 1. Scope & Responsibilities
|
|
10
|
+
|
|
11
|
+
### What this service does
|
|
12
|
+
|
|
13
|
+
| Area | Responsibility |
|
|
14
|
+
| -------------------- | -------------------------------------------- |
|
|
15
|
+
| Signal ingestion | Receive Wi-Fi / Wi-Fi P2P / BLE scan data |
|
|
16
|
+
| Persistence | Store scan events for analytics & replay |
|
|
17
|
+
| Proximity resolution | Match detected identifiers to vendors |
|
|
18
|
+
| Caching | Maintain fast, short-lived proximity state |
|
|
19
|
+
| Web relay | Serve nearby vendor inventory to web clients |
|
|
20
|
+
|
|
21
|
+
### What this service does NOT do
|
|
22
|
+
|
|
23
|
+
| Excluded | Reason |
|
|
24
|
+
| ------------------ | ------------------------------------ |
|
|
25
|
+
| Vendor CRUD | Handled by Vendor service |
|
|
26
|
+
| Inventory mutation | Read-only from proximity perspective |
|
|
27
|
+
| Authentication | Sensors are assumed trusted |
|
|
28
|
+
| Payments | Out of scope |
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## 2. Supported Proximity Technologies
|
|
33
|
+
|
|
34
|
+
| Technology | Status | Purpose | Matching Key |
|
|
35
|
+
| ---------------------- | ------------- | ------------------------ | ---------------- |
|
|
36
|
+
| **Wi-Fi** | ✅ Implemented | Primary proximity signal | SSID |
|
|
37
|
+
| **Wi-Fi Direct (P2P)** | ✅ Implemented | Peer discovery, mesh | SSID / Device ID |
|
|
38
|
+
| **BLE** | 🟡 Planned | Ultra-low power beacons | UUID / MAC |
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## 3. High-Level Architecture
|
|
43
|
+
|
|
44
|
+
| Component | Role |
|
|
45
|
+
| ----------------------- | --------------------------- |
|
|
46
|
+
| Native proximity device | Scans radio environment |
|
|
47
|
+
| Socket server | Real-time ingestion |
|
|
48
|
+
| DeviceScan store | Historical scan persistence |
|
|
49
|
+
| Vendor store | Known physical endpoints |
|
|
50
|
+
| Proximity cache | Low-latency resolution |
|
|
51
|
+
| Web socket namespace | Frontend notifications |
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## 4. Socket Namespaces
|
|
56
|
+
|
|
57
|
+
### Namespace Overview
|
|
58
|
+
|
|
59
|
+
| Namespace | Client Type | Purpose |
|
|
60
|
+
| ------------------- | ------------------ | -------------------------------- |
|
|
61
|
+
| `/proximity/native` | IoT / Edge devices | Send scan results |
|
|
62
|
+
| `/proximity/web` | Browser clients | Trigger & receive proximity data |
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## 5. Socket Event Matrix
|
|
67
|
+
|
|
68
|
+
### Server → Device
|
|
69
|
+
|
|
70
|
+
| Event | Frequency | Description |
|
|
71
|
+
| ---------------- | --------- | ----------------------- |
|
|
72
|
+
| `start_scanning` | Every 4s | Requests new scan cycle |
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
### Device → Server (Wi-Fi)
|
|
77
|
+
|
|
78
|
+
| Event | Payload | Description |
|
|
79
|
+
| ------------------- | ------------------ | ------------------- |
|
|
80
|
+
| `wifi::scan_result` | Wi-Fi scan payload | Standard Wi-Fi scan |
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
### Device → Server (Wi-Fi P2P)
|
|
85
|
+
|
|
86
|
+
| Event | Payload | Description |
|
|
87
|
+
| ---------------------- | ---------------- | --------------------- |
|
|
88
|
+
| `wifip2p::scan_result` | P2P scan payload | Mesh / peer discovery |
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
### Web Client Events
|
|
93
|
+
|
|
94
|
+
| Event | Direction | Description |
|
|
95
|
+
| -------------------------- | ------------ | ------------------------ |
|
|
96
|
+
| `PROXIMITY_SCAN::RUN_SCAN` | Web → Server | Trigger proximity lookup |
|
|
97
|
+
| `PROXIMITY_SCAN` | Server → Web | Return nearby vendors |
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## 6. REST API Surface
|
|
102
|
+
|
|
103
|
+
### Endpoint Summary
|
|
104
|
+
|
|
105
|
+
| Method | Endpoint | Purpose |
|
|
106
|
+
| ------ | -------------------------- | ---------------------- |
|
|
107
|
+
| GET | `/api/proximity/inventory` | Resolve nearby vendors |
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
### Identification Headers
|
|
112
|
+
|
|
113
|
+
| Header | Optional | Purpose |
|
|
114
|
+
| -------------- | -------- | --------------------------- |
|
|
115
|
+
| `x-device-sig` | Yes | Persistent device signature |
|
|
116
|
+
| `public_ip` | Yes | Network-level identity |
|
|
117
|
+
| `x-ws-token` | Yes | WebSocket fallback |
|
|
118
|
+
|
|
119
|
+
> The service automatically selects the **best available key**.
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## 7. Proximity Resolution Flow
|
|
124
|
+
|
|
125
|
+
| Step | Action |
|
|
126
|
+
| ---- | ------------------------------ |
|
|
127
|
+
| 1 | Device performs scan |
|
|
128
|
+
| 2 | Scan results sent via socket |
|
|
129
|
+
| 3 | Scan persisted to database |
|
|
130
|
+
| 4 | SSIDs / identifiers extracted |
|
|
131
|
+
| 5 | Vendors matched by identifiers |
|
|
132
|
+
| 6 | Result cached |
|
|
133
|
+
| 7 | Web client requests inventory |
|
|
134
|
+
| 8 | Cached vendors returned |
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## 8. Data Models
|
|
139
|
+
|
|
140
|
+
### 8.1 Wi-Fi / Wi-Fi P2P Scan Payload
|
|
141
|
+
|
|
142
|
+
| Field | Type | Required | Description |
|
|
143
|
+
| ----------------- | ---------- | -------- | -------------------- |
|
|
144
|
+
| `device_id` | string | No | Device identifier |
|
|
145
|
+
| `deviceSignature` | string | No | Persistent signature |
|
|
146
|
+
| `public_ip` | string | No | Network IP |
|
|
147
|
+
| `timestamp` | ISO string | Yes | Scan time |
|
|
148
|
+
| `scan_meta` | object | No | Scan metadata |
|
|
149
|
+
| `detected_wifi` | array | Yes | Detected networks |
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
### 8.2 Detected Network
|
|
154
|
+
|
|
155
|
+
| Field | Type | Description |
|
|
156
|
+
| ----------- | ------ | ----------------- |
|
|
157
|
+
| `ssid` | string | Network name |
|
|
158
|
+
| `rssi` | number | Signal strength |
|
|
159
|
+
| `frequency` | number | Channel frequency |
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
### 8.3 BLE Scan Payload (Planned)
|
|
164
|
+
|
|
165
|
+
| Field | Type | Description |
|
|
166
|
+
| ----------- | ------ | -------------------- |
|
|
167
|
+
| `device_id` | string | BLE scanner |
|
|
168
|
+
| `beacons` | array | Detected BLE beacons |
|
|
169
|
+
| `uuid` | string | Beacon UUID |
|
|
170
|
+
| `major` | number | Beacon major |
|
|
171
|
+
| `minor` | number | Beacon minor |
|
|
172
|
+
| `rssi` | number | Signal strength |
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## 9. Proximity Cache Structure
|
|
177
|
+
|
|
178
|
+
| Key | Description |
|
|
179
|
+
| -------------- | ------------------------- |
|
|
180
|
+
| `ssids` | Last detected identifiers |
|
|
181
|
+
| `timestamp` | Last scan time |
|
|
182
|
+
| `socketId` | Active connection |
|
|
183
|
+
| `persistentId` | Device identity |
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## 10. Vendor Matching Logic
|
|
188
|
+
|
|
189
|
+
| Signal Type | Matching Strategy |
|
|
190
|
+
| ----------- | -------------------------------------- |
|
|
191
|
+
| Wi-Fi | SSID ∈ Vendor.SSID |
|
|
192
|
+
| Wi-Fi P2P | SSID ∈ Vendor.SSID |
|
|
193
|
+
| BLE | UUID ↔ Vendor beacon mapping (planned) |
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## 11. Error Handling Matrix
|
|
198
|
+
|
|
199
|
+
| Scenario | Response |
|
|
200
|
+
| ----------------- | ------------------ |
|
|
201
|
+
| Invalid payload | Error ACK |
|
|
202
|
+
| Empty scan | `stores_count = 0` |
|
|
203
|
+
| No vendor match | Valid empty result |
|
|
204
|
+
| DB failure | Error + logged |
|
|
205
|
+
| Socket disconnect | Scan loop stopped |
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## 12. Security Model
|
|
210
|
+
|
|
211
|
+
| Aspect | Current State |
|
|
212
|
+
| ----------------- | --------------- |
|
|
213
|
+
| Authentication | None |
|
|
214
|
+
| Authorization | None |
|
|
215
|
+
| Trust model | Device-based |
|
|
216
|
+
| Replay protection | Timestamp-based |
|
|
217
|
+
| Rate limiting | Not implemented |
|
|
218
|
+
|
|
219
|
+
> Designed for **trusted edge devices**. Hardenable later.
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## 13. Local Development
|
|
224
|
+
|
|
225
|
+
### Requirements
|
|
226
|
+
|
|
227
|
+
| Dependency | Version |
|
|
228
|
+
| ---------- | ------- |
|
|
229
|
+
| Node.js | ≥ 18 |
|
|
230
|
+
| MongoDB | ≥ 5 |
|
|
231
|
+
| Socket.IO | v4 |
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
### Run Locally
|
|
236
|
+
|
|
237
|
+
```bash
|
|
238
|
+
npm install
|
|
239
|
+
npm run dev
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
## 14. Future Enhancements
|
|
245
|
+
|
|
246
|
+
| Feature | Status |
|
|
247
|
+
| ------------------------ | ------- |
|
|
248
|
+
| BLE beacon ingestion | Planned |
|
|
249
|
+
| Movement delta detection | Planned |
|
|
250
|
+
| Confidence scoring | Planned |
|
|
251
|
+
| Multi-sensor fusion | Planned |
|
|
252
|
+
| Edge mesh propagation | Planned |
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
## 15. Related Docs
|
|
257
|
+
|
|
258
|
+
| Document | Purpose |
|
|
259
|
+
| -------------- | ----------------------------- |
|
|
260
|
+
| `openapi.yaml` | REST API spec |
|
|
261
|
+
| Vendor API | Vendor & inventory management |
|
|
262
|
+
| QA Matrix | Test coverage |
|
|
263
|
+
| SRS | Functional requirements |
|
|
264
|
+
|
|
265
|
+
---
|
|
266
|
+
|
|
267
|
+
## 16. Ownership
|
|
268
|
+
|
|
269
|
+
**Proximity Platform – Sensor Layer**
|
|
270
|
+
Built for **ambient, real-world intelligence**.
|
package/index.js
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { DeviceScan } from "../models/DeviceScan.js";
|
|
2
|
+
import { Vendor } from "../models/Vendor.js";
|
|
3
|
+
import axios from "axios";
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
export const initSocket = (io, proximityCache) => {
|
|
8
|
+
const nativeNamespace = io.of("/proximity/native");
|
|
9
|
+
|
|
10
|
+
nativeNamespace.on("connection", (socket) => {
|
|
11
|
+
const persistentId = socket.handshake.query.persistentId || socket.id;
|
|
12
|
+
console.log(`Proximity device connected: ${persistentId} (socket: ${socket.id})`);
|
|
13
|
+
|
|
14
|
+
// Send periodic scan requests
|
|
15
|
+
const scan = () => { console.log("[EMITTING SCAN REQUEST]"); socket.emit("start_scanning");}
|
|
16
|
+
const scanInterval = setInterval(scan, 4000);
|
|
17
|
+
|
|
18
|
+
// Receive scan result from proximity sensor
|
|
19
|
+
socket.on("wifi::scan_result", async (payload, ack) => {
|
|
20
|
+
try {
|
|
21
|
+
const { device_id, public_ip, detected_wifi, timestamp, scan_meta, deviceSignature } = payload;
|
|
22
|
+
|
|
23
|
+
// Choose best available unique key for device
|
|
24
|
+
const key = public_ip || deviceSignature || persistentId;
|
|
25
|
+
|
|
26
|
+
console.log(`[SCAN RESULT] From ${persistentId}:`, {
|
|
27
|
+
detected_wifi_count: detected_wifi?.length || 0,
|
|
28
|
+
...payload
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// Save scan data
|
|
32
|
+
await DeviceScan.create({
|
|
33
|
+
device_id,
|
|
34
|
+
public_ip,
|
|
35
|
+
detected_wifi,
|
|
36
|
+
timestamp,
|
|
37
|
+
scan_meta,
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// Find nearby stores by SSID
|
|
41
|
+
const ssids = (detected_wifi || []).map((w) => w.ssid);
|
|
42
|
+
const stores = await Vendor.find({ ssid: { $in: ssids } }).lean();
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
// Check if that there's any changes between current datapoint and previous datapoints/
|
|
46
|
+
// Data points are dectected current and previous {stores, devicescans} value
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
if (ack) ack({ status: "ok", stores_count: stores.length });
|
|
50
|
+
} catch (e) {
|
|
51
|
+
console.error("scan_result error:", e);
|
|
52
|
+
if (ack) ack({ status: "error", error: e.message });
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
// === Receive Wi-Fi Direct scan results from nearby nodes ===
|
|
58
|
+
socket.on("wifip2p::scan_result", async (payload, ack) => {
|
|
59
|
+
console.log(payload)
|
|
60
|
+
try {
|
|
61
|
+
const {
|
|
62
|
+
device_id, public_ip, detected_wifi, timestamp, scan_meta, deviceSignature,
|
|
63
|
+
} = payload || {};
|
|
64
|
+
|
|
65
|
+
const key = public_ip || deviceSignature || persistentId;
|
|
66
|
+
const wifiCount = detected_wifi?.length || 0;
|
|
67
|
+
|
|
68
|
+
console.log(`📶 [SCAN RESULT] From ${device_id || "unknown"} →`, {
|
|
69
|
+
detected_wifi_count: wifiCount,
|
|
70
|
+
timestamp,
|
|
71
|
+
scan_meta,
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// 🧠 Save scan data (to DB, file, or local storage)
|
|
75
|
+
await DeviceScan.create({
|
|
76
|
+
device_id,
|
|
77
|
+
public_ip,
|
|
78
|
+
detected_wifi,
|
|
79
|
+
timestamp,
|
|
80
|
+
scan_meta,
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// 🏪 Identify known SSIDs linked to nearby “stores” or endpoints
|
|
84
|
+
const ssids = (detected_wifi || []).map((w) => w.ssid).filter(Boolean);
|
|
85
|
+
const stores = await Vendor.find({ ssid: { $in: ssids } }).lean();
|
|
86
|
+
|
|
87
|
+
// 🔒 Cache the device’s proximity data for rapid local queries
|
|
88
|
+
proximityCache[key] = {
|
|
89
|
+
ssids,
|
|
90
|
+
timestamp: Date.now(),
|
|
91
|
+
socketId: socket.id,
|
|
92
|
+
persistentId,
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
// ✅ Respond back to sender (ACK)
|
|
96
|
+
if (ack) ack({ status: "ok", stores_count: stores.length });
|
|
97
|
+
|
|
98
|
+
console.log(`✅ [Processed] ${wifiCount} networks, ${stores.length} matches.`);
|
|
99
|
+
} catch (e) {
|
|
100
|
+
console.error("❌ scan_result error:", e);
|
|
101
|
+
if (ack) ack({ status: "error", error: e.message });
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
socket.on("disconnect", () => {
|
|
107
|
+
console.log(`Device disconnected: ${persistentId} (socket: ${socket.id})`);
|
|
108
|
+
clearInterval(scanInterval);
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
const webNamespace = io.of("/proximity/web");
|
|
116
|
+
|
|
117
|
+
webNamespace.on("connection", socket => {
|
|
118
|
+
console.log("Server=>WebClient Socket Connted", socket.id)
|
|
119
|
+
socket.on("PROXIMITY_SCAN::RUN_SCAN", async(payload)=>{
|
|
120
|
+
try{
|
|
121
|
+
const res = await axios.get("http://10.48.59.128:5000/api/proximity/inventory", {
|
|
122
|
+
headers: {
|
|
123
|
+
"x-device-sig": payload.persistentId,
|
|
124
|
+
//public_ip: await fetchPublicIP(),
|
|
125
|
+
},
|
|
126
|
+
})
|
|
127
|
+
console.log(payload)
|
|
128
|
+
if(res.data.length > 0){
|
|
129
|
+
console.log("[EMITTING RESULT TO WEB]")
|
|
130
|
+
socket.emit("PROXIMITY_SCAN", {data:res.data});
|
|
131
|
+
}
|
|
132
|
+
else if(res.data.length == 0){
|
|
133
|
+
console.log("[EMITTING RESULT TO WEB]")
|
|
134
|
+
console.log(res.data);
|
|
135
|
+
//socket.emit("PROXIMITY_SCAN", {data:res.data});
|
|
136
|
+
}
|
|
137
|
+
}catch(e){
|
|
138
|
+
console.log(payload?.persistentId)
|
|
139
|
+
}
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
})
|
|
143
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@shyntech-proximity/sensor-app",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"main": "index.js",
|
|
5
|
+
"files": [
|
|
6
|
+
"dist",
|
|
7
|
+
"src"
|
|
8
|
+
],
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "",
|
|
11
|
+
"prepublishOnly": "npm run build"
|
|
12
|
+
},
|
|
13
|
+
"publishConfig": {
|
|
14
|
+
"@shyntech:registry": "https://gitlab.com/api/v4/projects/78157101/packages/npm/"
|
|
15
|
+
},
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"typescript": "^5.9.3"
|
|
18
|
+
}
|
|
19
|
+
}
|