@mhome/app-facade-protocol 1.40.1 → 1.42.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/contract/pod-commissioning-v1.md +134 -34
- package/fixtures/host-provision.completed.json +1 -0
- package/fixtures/pod-commission.awaiting-authorization.json +8 -1
- package/fixtures/pod-commission.failed.json +1 -0
- package/fixtures/pod-commission.reprovision-completed.json +1 -0
- package/fixtures/pod-discovery.snapshot.json +2 -0
- package/manifest/app-facade.v1.json +1 -1
- package/manifest/host-provision-targets.v1.json +1 -1
- package/manifest/hub-targets.v1.json +1 -1
- package/manifest/pod-targets.v1.json +11 -2
- package/manifest/routing.v1.json +1 -1
- package/manifest/targets.v1.json +1 -1
- package/package.json +1 -1
- package/protocol.json +1 -1
- package/schema/person.v1.schema.json +1 -1
- package/schema/pod-commission.v1.schema.json +7 -2
- package/schema/pod-discovery.v1.schema.json +8 -3
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
# Pod commissioning v1
|
|
2
2
|
|
|
3
|
-
A pod is a MeowLink end device that acts as
|
|
3
|
+
A pod is a MeowLink end device that acts as a User Client or a Space Client. This
|
|
4
4
|
contract is implementation-neutral: ESP-IDF on BLE-capable ESP32 chips is the
|
|
5
5
|
first implementation, not a requirement. Commissioners are the native Clients:
|
|
6
6
|
desktop/CLI Clientd, Android and iOS. The shared UI and CLI never talk BLE; they
|
|
7
7
|
call the `/local/pod/*` targets of their native Client.
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
Network provisioning and activation are separate transactions. BLE provisions
|
|
10
|
+
Wi-Fi; Ethernet and already-connected Wi-Fi skip it. Every initialization then
|
|
11
|
+
uses a direct native Client ↔ Pod LAN security-2 session. No Core relay is used.
|
|
12
|
+
The commissioner explicitly chooses `clientMode: "user" | "space"` during
|
|
13
|
+
`/local/pod/commission/authorize`. User mode uses the personal Pod credential.
|
|
14
|
+
Space mode uses a local Core credential signed by Lion; it carries no user
|
|
15
|
+
identity and has no cloud access/refresh token. Changing mode requires reset.
|
|
13
16
|
|
|
14
17
|
## 1. Device identity
|
|
15
18
|
|
|
@@ -47,7 +50,7 @@ credential invalidation, or inside a re-provision window. A commissioned pod doe
|
|
|
47
50
|
|
|
48
51
|
## 3. Secure session
|
|
49
52
|
|
|
50
|
-
|
|
53
|
+
Wi-Fi provisioning uses ESP protocomm over BLE GATT. Endpoints are GATT characteristics
|
|
51
54
|
named by their Characteristic User Description descriptor (`0x2901`). A
|
|
52
55
|
commissioner that cannot read descriptors falls back to fixed UUIDs: the service
|
|
53
56
|
UUID with bytes 2–3 replaced by `prov-ctrl` `0xFF4F`, `prov-scan` `0xFF50`,
|
|
@@ -58,7 +61,7 @@ custom endpoints in table order from `0xFF54` (`pod-info` `0xFF54`,
|
|
|
58
61
|
- Security: protocomm security 2 (SRP6a 3072-bit with SHA-512, then AES-256-GCM).
|
|
59
62
|
Username `meow`. Password: a 6-digit decimal code.
|
|
60
63
|
- Pods with a display generate a uniformly random code, precompute salt and
|
|
61
|
-
verifier at boot, and show
|
|
64
|
+
verifier at boot, and show it while connected over BLE or available for LAN initialization. A new
|
|
62
65
|
code is generated after a successful commissioning, after 5 failed handshakes,
|
|
63
66
|
or 10 minutes after it was first shown. Pods without a display are out of scope
|
|
64
67
|
for v1.
|
|
@@ -70,8 +73,8 @@ custom endpoints in table order from `0xFF54` (`pod-info` `0xFF54`,
|
|
|
70
73
|
`M` uses it as sent; `u` pads both to 384 bytes.
|
|
71
74
|
- The record nonce is 8 random bytes followed by a 32-bit big-endian counter
|
|
72
75
|
starting at 1, advanced after every encrypt and decrypt on both sides
|
|
73
|
-
(security 2 patch version 1; patch 0 keeps it fixed). Commissioners
|
|
74
|
-
patch
|
|
76
|
+
(security 2 patch version 1; patch 0 keeps it fixed). Commissioners require
|
|
77
|
+
patch version 1; fixed-nonce patch 0 is rejected. A lost or failed exchange leaves the two counters
|
|
75
78
|
unknown, so the commissioner abandons the secure session after any transport or
|
|
76
79
|
decryption failure. A new `SessionCmd0` restarts the handshake on the same link.
|
|
77
80
|
- While a device refuses handshakes after repeated wrong codes it clears the
|
|
@@ -81,8 +84,8 @@ custom endpoints in table order from `0xFF54` (`pod-info` `0xFF54`,
|
|
|
81
84
|
such as Insufficient Authorization), so after every rejected handshake the
|
|
82
85
|
commissioner reads `proto-ver` again and fails the session with `code_locked`
|
|
83
86
|
when either field is present. A pod session also fails with `code_locked` after
|
|
84
|
-
the fifth rejected code.
|
|
85
|
-
|
|
87
|
+
the fifth rejected code. Pods generate a fresh code after five rejected handshakes. Once network
|
|
88
|
+
configuration is saved, code rotation preserves that network.
|
|
86
89
|
- One BLE connection at a time; a second central receives a disconnect.
|
|
87
90
|
- Session deadline: 10 minutes from connect, or 2 minutes waiting for a
|
|
88
91
|
handshake. On expiry the pod discards all unpersisted state.
|
|
@@ -95,15 +98,17 @@ custom endpoints in table order from `0xFF54` (`pod-info` `0xFF54`,
|
|
|
95
98
|
| `prov-config` | yes | standard Wi-Fi set/apply/status |
|
|
96
99
|
| `prov-ctrl` | yes | standard reset after a failed join, before a retry |
|
|
97
100
|
| `pod-info` | yes | device information |
|
|
98
|
-
| `pod-credential` | yes | credential delivery
|
|
101
|
+
| `pod-credential` | yes | LAN credential delivery/status/finish; BLE accepts only reprovision status/finish |
|
|
99
102
|
|
|
100
|
-
Custom endpoint bodies are UTF-8 JSON, at most 480 bytes
|
|
103
|
+
Custom endpoint bodies are UTF-8 JSON, at most 480 bytes over BLE. LAN requests
|
|
104
|
+
and responses are bounded to 64 KiB including encryption overhead.
|
|
101
105
|
|
|
102
106
|
`pod-info` request `{}`, response:
|
|
103
107
|
|
|
104
108
|
```json
|
|
105
109
|
{
|
|
106
110
|
"protocol": 1,
|
|
111
|
+
"env": "prod",
|
|
107
112
|
"deviceId": "a0b1c2d3e4f5",
|
|
108
113
|
"model": "S1",
|
|
109
114
|
"platform": "esp32c5",
|
|
@@ -114,6 +119,9 @@ Custom endpoint bodies are UTF-8 JSON, at most 480 bytes in each direction.
|
|
|
114
119
|
}
|
|
115
120
|
```
|
|
116
121
|
|
|
122
|
+
`env` must match the native Client runtime (`prod`, `dev`, `e2e`).
|
|
123
|
+
`podId` is included when activation is in flight or durably completed, so a
|
|
124
|
+
new session can observe completion without issuing another credential.
|
|
117
125
|
`platform` is diagnostic only. `wifiConfigured` is true when the pod kept a
|
|
118
126
|
working network across logout; the commissioner then skips the Wi-Fi steps after
|
|
119
127
|
confirming connectivity with `prov-config` status. Inside a Wi-Fi change window
|
|
@@ -122,7 +130,7 @@ the response also carries `"mode":"reprovision"` and `wifiConfigured` is false
|
|
|
122
130
|
|
|
123
131
|
`pod-credential` requests:
|
|
124
132
|
|
|
125
|
-
- `{"op":"deliver","podId","refreshToken","scopeId","cloudApi","cloudWs"}` →
|
|
133
|
+
- `{"op":"deliver","clientMode":"user","podId","refreshToken","scopeId","cloudApi","cloudWs"}` →
|
|
126
134
|
`{"ok":true,"state":"activating"}`. Accepted only in `wifi_connected` outside a
|
|
127
135
|
Wi-Fi change window; otherwise `{"ok":false,"state":<current pod state>,"reason"}`
|
|
128
136
|
with `reason` `invalid_payload` (a missing or malformed field, including a
|
|
@@ -143,24 +151,55 @@ the response also carries `"mode":"reprovision"` and `wifiConfigured` is false
|
|
|
143
151
|
best-effort: the commissioner records `completed` before sending it.
|
|
144
152
|
|
|
145
153
|
Activation error codes: `time_sync_failed`, `cloud_unreachable`,
|
|
146
|
-
`refresh_rejected`, `auth_rejected`, `storage_failed` (the final commit, or in a
|
|
154
|
+
`local_hub_unavailable`, `refresh_rejected`, `auth_rejected`, `storage_failed` (the final commit, or in a
|
|
147
155
|
Wi-Fi change window saving the new network, failed).
|
|
148
156
|
|
|
149
|
-
The
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
157
|
+
The Pod commits Wi-Fi immediately after a successful join, before any credential
|
|
158
|
+
issuance. Activation commits only identity/binding data. Failed activation,
|
|
159
|
+
disconnection, code expiry and reboot preserve the successfully saved network.
|
|
160
|
+
A failed join rolls back only the incomplete network change.
|
|
161
|
+
|
|
162
|
+
### LAN discovery and channel
|
|
163
|
+
|
|
164
|
+
- Service: `_meow-pod-init._tcp.local.` while network-ready and uninitialized.
|
|
165
|
+
TXT: full `deviceId`, `v=1`, `env`, optional `model`; SRV/A/AAAA locate the
|
|
166
|
+
endpoint. A failed or expired pairing attempt does not remove this service.
|
|
167
|
+
- The same service works on Ethernet and Wi-Fi. BLE supplies the full device ID
|
|
168
|
+
and identity over its secure session; the short display ID is never the match
|
|
169
|
+
key. Discovery data is untrusted and is checked against encrypted `pod-info`.
|
|
170
|
+
- HTTP POST `/{endpoint}` with `Content-Type: application/octet-stream` and a
|
|
171
|
+
fresh UUID `X-Meow-Session`. Allowed endpoints: `proto-ver`, `prov-session`,
|
|
172
|
+
`pod-info`, `pod-credential`. Wi-Fi endpoints are unavailable over LAN.
|
|
173
|
+
Clients connect to the resolved socket directly, with proxies/redirects off.
|
|
174
|
+
- Run a fresh Security 2 patch-1 handshake on LAN. After BLE, reuse only the
|
|
175
|
+
temporarily held code, never the BLE session key or nonce. Ethernet setup
|
|
176
|
+
requests the code in the App UI. Business messages are AES-GCM protected.
|
|
177
|
+
- Each IP session has separate crypto state. Devices cap simultaneous sessions
|
|
178
|
+
at four; pending handshakes expire after two minutes, sessions after ten.
|
|
179
|
+
An encrypted `pod-credential {"op":"close"}` releases that temporary session.
|
|
180
|
+
- Stop init advertisement on durable completion. The existing session has a
|
|
181
|
+
short finish window for confirmation; normal business disconnection never
|
|
182
|
+
returns a completed device to initialization.
|
|
153
183
|
|
|
154
184
|
## 4. Pod state machine
|
|
155
185
|
|
|
156
186
|
```text
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
187
|
+
no network -> BLE secure -> join -> save Wi-Fi -> network ready
|
|
188
|
+
Ethernet / saved Wi-Fi ------------------------> network ready
|
|
189
|
+
network ready -> advertise init -> LAN secure -> authorize -> activate -> save identity
|
|
190
|
+
join failure -> end attempt; start Wi-Fi setup again
|
|
191
|
+
activation failure -> end attempt; keep network and init advertisement
|
|
192
|
+
pairing expiry -> discard temporary sessions/code; keep network; accept a new code
|
|
162
193
|
```
|
|
163
194
|
|
|
195
|
+
The App reports `discovering_lan` and `connecting_lan` during BLE handoff.
|
|
196
|
+
Discovery snapshots distinguish `scanning` (BLE), `lanBrowsing`, optional
|
|
197
|
+
`lanError`, and candidate `transport` (`ble` or `lan`). LAN candidates carry the
|
|
198
|
+
full `deviceId`; Bluetooth denial never blocks them. The App retries initialization
|
|
199
|
+
by selecting the LAN candidate, possibly re-entering the current code. It first
|
|
200
|
+
reads actual device state: `commissioned` completes immediately, `activating`
|
|
201
|
+
waits for the existing attempt, and a failed attempt may issue afresh.
|
|
202
|
+
|
|
164
203
|
Runtime states after commit:
|
|
165
204
|
|
|
166
205
|
- `commissioned`: normal operation.
|
|
@@ -316,7 +355,7 @@ and unexpired pending pods, each
|
|
|
316
355
|
|
|
317
356
|
All targets are handled by the native Client and never forwarded. Payloads are
|
|
318
357
|
domain input JSON. Clients without a usable Bluetooth adapter report
|
|
319
|
-
`adapter.state` and reject commissioning with `bluetooth_unavailable
|
|
358
|
+
`adapter.state` and reject BLE commissioning with `bluetooth_unavailable`; LAN candidates remain usable.
|
|
320
359
|
|
|
321
360
|
A rejected request uses the facade error envelope
|
|
322
361
|
`{"error","message","details":{"reason"}}`: `error` is `BAD_REQUEST` for an
|
|
@@ -394,9 +433,10 @@ example `storage_failed`) in `detail`. UIs show such a session as changing the
|
|
|
394
433
|
pod's Wi-Fi rather than adding a pod.
|
|
395
434
|
|
|
396
435
|
Session states, in order: `connecting`, `awaiting_code`, `securing`,
|
|
397
|
-
`reading_info`, `awaiting_wifi`, `joining_wifi`, `
|
|
436
|
+
`reading_info`, `awaiting_wifi`, `joining_wifi`, `discovering_lan`,
|
|
437
|
+
`connecting_lan`, `awaiting_authorization`,
|
|
398
438
|
`issuing`, `delivering`, `activating`, `completed`; terminal `failed`,
|
|
399
|
-
`timed_out`. Wi-Fi states are skipped when the pod reports a
|
|
439
|
+
`timed_out`. LAN candidates skip all Wi-Fi states. Wi-Fi states are also skipped when the pod reports a
|
|
400
440
|
configured network and `prov-config` status reports it connected; while that
|
|
401
441
|
status is `connecting` the commissioner keeps polling, and only after a failure
|
|
402
442
|
does it reset Wi-Fi (`prov-ctrl`) and offer new credentials. The commissioner
|
|
@@ -407,10 +447,11 @@ scan runs waits for it. `revision` increases on every observable change.
|
|
|
407
447
|
`delivering` on it is `activateBefore` plus 30 seconds.
|
|
408
448
|
|
|
409
449
|
Only the device's durable `commissioned` response confirms successful setup.
|
|
410
|
-
Lost
|
|
450
|
+
Lost LAN delivery confirmation or activation status fails the attempt, even
|
|
411
451
|
when Lion has already activated its credential. Expiry fails or times out the
|
|
412
452
|
attempt. The commissioner does not recover interrupted setup through Lion's
|
|
413
|
-
credential status. The user
|
|
453
|
+
credential status. The user selects the network-ready device again, establishes
|
|
454
|
+
a fresh LAN session and reads its actual activation status.
|
|
414
455
|
|
|
415
456
|
A refused `deliver` fails with `delivery_failed` carrying the pod's `reason`
|
|
416
457
|
(`invalid_payload` or `wrong_state`) in `detail`. When the pod
|
|
@@ -423,14 +464,73 @@ app is in the background (Android foreground service of type
|
|
|
423
464
|
|
|
424
465
|
Session error codes: `bluetooth_unavailable`, `device_busy`, `disconnected`,
|
|
425
466
|
`code_rejected` (retry allowed), `code_locked`, `wifi_auth_failed`,
|
|
426
|
-
`wifi_not_found`, `wifi_failed`, `issue_failed`, `delivery_failed`,
|
|
467
|
+
`wifi_not_found`, `wifi_failed`, `lan_unavailable`, `device_mismatch`, `issue_failed`, `delivery_failed`,
|
|
427
468
|
`activation_failed` (with the pod's activation code, or `not_activated`, in
|
|
428
469
|
`detail`), `session_timeout`. `code_locked` is terminal: the device shows a new
|
|
429
470
|
code once it accepts handshakes again. `failed` and `timed_out` always carry `error`. A rejected
|
|
430
|
-
code returns to `awaiting_code` with `code_rejected`; a failed join
|
|
431
|
-
`
|
|
432
|
-
without revoking credentials.
|
|
433
|
-
activation outcome; unused pending cloud credentials expire automatically.
|
|
471
|
+
code returns to `awaiting_code` with `code_rejected`; a failed Pod join ends in
|
|
472
|
+
`failed` with the `wifi_*` code. No other state carries `error`. Terminal states release the link and radio
|
|
473
|
+
without revoking credentials. Retry over LAN after an uncertain activation outcome; unused pending cloud credentials expire automatically.
|
|
434
474
|
|
|
435
475
|
The schemas are `schema/pod-discovery.v1.schema.json` and
|
|
436
476
|
`schema/pod-commission.v1.schema.json`.
|
|
477
|
+
|
|
478
|
+
|
|
479
|
+
## 8. Space Client local credential
|
|
480
|
+
|
|
481
|
+
`POST /api/v1/pod/space/credential/issue` uses the assisting App's user
|
|
482
|
+
`Authorization` and `ScopeId`, with the same device identity request as personal
|
|
483
|
+
issuance. Any current member may assist. The Space must be local and have one
|
|
484
|
+
published Hub with business and Host TLS identities. Cloud Spaces must complete
|
|
485
|
+
Hub setup first. The issuer creates a fresh `appClientId` (`a:<random id>`) and
|
|
486
|
+
signs a local JWT using the existing Space signing key and local-client audience.
|
|
487
|
+
|
|
488
|
+
Claims are `token_type: local_space_client_access`, `sub: <scopeId>`,
|
|
489
|
+
`tenant_id`, `scope_id`, `hub_id`, `app_client_id`, `jti`, `iat`, `exp`, `is_test`.
|
|
490
|
+
The expiry follows existing long-lived User local credentials. No `userId`,
|
|
491
|
+
initializer identity, `podId` or `issuedScopeId` grants authority. User local
|
|
492
|
+
credentials retain `local_client_access` and must not contain `app_client_id`.
|
|
493
|
+
Personal Pod issuance no longer stores `issuedScopeId`.
|
|
494
|
+
|
|
495
|
+
Lion sends `{jwtToken, clientSource:"pod"}` to the authenticated Hub Bridge
|
|
496
|
+
`/hub/client/space/register`. Core verifies signature, audience, issuer, current
|
|
497
|
+
Hub, environment, Space and canonical installation ID, and stores a pending
|
|
498
|
+
credential. First authentication must occur within ten minutes of JWT issuance.
|
|
499
|
+
The response is `{credentialId, status:"pending", activateBefore}`. Lion returns
|
|
500
|
+
`{credentialId, appClientId, jwtToken, activateBefore, hubIdentity}` only after
|
|
501
|
+
registration succeeds. The Hub identity includes its business P-256 key and
|
|
502
|
+
Host TLS public key, bound to `tenantId`, `scopeId`, `hubId` and `hostId`.
|
|
503
|
+
|
|
504
|
+
The secured LAN `pod-credential` delivery is:
|
|
505
|
+
|
|
506
|
+
```json
|
|
507
|
+
{"op":"deliver","clientMode":"space","credentialId":"…","appClientId":"a:…","jwtToken":"…","tenantId":"…","scopeId":"…","hubIdentity":{}}
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
The actual `hubIdentity` is the complete issuer response. User credential fields
|
|
511
|
+
(`refreshToken`, cloud endpoints, `podId`) are rejected in this variant. Space
|
|
512
|
+
credential fields are rejected in the User variant. LAN credential plaintext is
|
|
513
|
+
bounded to 8192 bytes; BLE credential delivery remains disabled.
|
|
514
|
+
|
|
515
|
+
The Pod discovers the matching runtime environment and Space's Hub, pins TLS,
|
|
516
|
+
verifies the signed Hub proof, and authenticates with the local JWT and signed
|
|
517
|
+
`appClientId`. Core atomically activates the pending credential after all binding
|
|
518
|
+
checks. The Pod requires a Space principal for the same Space, installation and
|
|
519
|
+
credential in the authenticated response, then durably saves the profile. Only
|
|
520
|
+
then does LAN setup report completion. The LAN status field named `podId` is an
|
|
521
|
+
enrollment correlation ID: for Space mode it carries `credentialId`, never the
|
|
522
|
+
installation ID or acting principal.
|
|
523
|
+
|
|
524
|
+
After activation, reconnects do not require Lion or renew a cloud session. The
|
|
525
|
+
same Core verifies the JWT and local registration offline, with its cached Scope
|
|
526
|
+
verification key. Failed activation preserves working Wi-Fi and leaves LAN
|
|
527
|
+
commissioning available. Retry may require the pairing code again. Unused pending
|
|
528
|
+
credentials cannot activate after the deadline. Factory reset deletes the local
|
|
529
|
+
credential and identity key; no server-side revoke workflow is introduced.
|
|
530
|
+
|
|
531
|
+
Core carries `AuthenticatedClient` through WS, dispatch, plugin admission,
|
|
532
|
+
prepared actions, dialogs and presence. A Space Client can READ/WRITE its Space;
|
|
533
|
+
MANAGE, personal resources and Host user administration are rejected. It joins
|
|
534
|
+
the canonical Space-client conversation group, never an initializer's threads.
|
|
535
|
+
The billing owner fallback is not an acting identity. Host management tokens are
|
|
536
|
+
independent and are never issued by this flow.
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
"candidate": {
|
|
6
6
|
"candidateId": "ble:1A2B3C4D",
|
|
7
7
|
"kind": "pod",
|
|
8
|
+
"transport": "ble",
|
|
8
9
|
"name": "MeowPod S1",
|
|
9
10
|
"model": "S1",
|
|
10
11
|
"shortId": "1A2B3C4D",
|
|
@@ -23,7 +24,13 @@
|
|
|
23
24
|
"authorization": {
|
|
24
25
|
"userId": "user-1",
|
|
25
26
|
"userName": "Ada",
|
|
26
|
-
"scopes": [
|
|
27
|
+
"scopes": [
|
|
28
|
+
{
|
|
29
|
+
"scopeId": "scope-1",
|
|
30
|
+
"name": "Home",
|
|
31
|
+
"local": true
|
|
32
|
+
}
|
|
33
|
+
],
|
|
27
34
|
"defaultScopeId": "scope-1"
|
|
28
35
|
}
|
|
29
36
|
}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"revision": 4,
|
|
3
|
+
"lanBrowsing": false,
|
|
3
4
|
"scanning": true,
|
|
4
5
|
"adapter": { "state": "ready" },
|
|
5
6
|
"candidates": [
|
|
6
7
|
{
|
|
7
8
|
"candidateId": "ble:1A2B3C4D",
|
|
8
9
|
"kind": "pod",
|
|
10
|
+
"transport": "ble",
|
|
9
11
|
"name": "MeowPod S1",
|
|
10
12
|
"model": "S1",
|
|
11
13
|
"shortId": "1A2B3C4D",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"manifest": "mhome.pod.targets.v1",
|
|
3
|
-
"contractVersion": "1.
|
|
3
|
+
"contractVersion": "1.42.0",
|
|
4
4
|
"contract": "contract/pod-commissioning-v1.md",
|
|
5
5
|
"localTargets": [
|
|
6
6
|
"/local/pod/discovery/start",
|
|
@@ -67,11 +67,13 @@
|
|
|
67
67
|
"cloud": {
|
|
68
68
|
"issue": "pod/credential/issue",
|
|
69
69
|
"status": "pod/credential/status",
|
|
70
|
-
"statusSchema": "schema/pod-credential-status.v1.schema.json"
|
|
70
|
+
"statusSchema": "schema/pod-credential-status.v1.schema.json",
|
|
71
|
+
"spaceIssue": "pod/space/credential/issue"
|
|
71
72
|
},
|
|
72
73
|
"activationErrorCodes": [
|
|
73
74
|
"time_sync_failed",
|
|
74
75
|
"cloud_unreachable",
|
|
76
|
+
"local_hub_unavailable",
|
|
75
77
|
"refresh_rejected",
|
|
76
78
|
"auth_rejected",
|
|
77
79
|
"storage_failed"
|
|
@@ -96,5 +98,12 @@
|
|
|
96
98
|
"scope_not_offered",
|
|
97
99
|
"cloud_unreachable_for_device",
|
|
98
100
|
"busy"
|
|
101
|
+
],
|
|
102
|
+
"lan": {
|
|
103
|
+
"credentialMaxBytes": 8192
|
|
104
|
+
},
|
|
105
|
+
"clientModes": [
|
|
106
|
+
"user",
|
|
107
|
+
"space"
|
|
99
108
|
]
|
|
100
109
|
}
|
package/manifest/routing.v1.json
CHANGED
package/manifest/targets.v1.json
CHANGED
package/package.json
CHANGED
package/protocol.json
CHANGED
|
@@ -16,6 +16,8 @@
|
|
|
16
16
|
"reading_info",
|
|
17
17
|
"awaiting_wifi",
|
|
18
18
|
"joining_wifi",
|
|
19
|
+
"discovering_lan",
|
|
20
|
+
"connecting_lan",
|
|
19
21
|
"awaiting_authorization",
|
|
20
22
|
"issuing",
|
|
21
23
|
"delivering",
|
|
@@ -64,10 +66,11 @@
|
|
|
64
66
|
"items": {
|
|
65
67
|
"type": "object",
|
|
66
68
|
"additionalProperties": false,
|
|
67
|
-
"required": ["scopeId", "name"],
|
|
69
|
+
"required": ["scopeId", "name", "local"],
|
|
68
70
|
"properties": {
|
|
69
71
|
"scopeId": { "type": "string", "minLength": 1 },
|
|
70
|
-
"name": { "type": "string" }
|
|
72
|
+
"name": { "type": "string" },
|
|
73
|
+
"local": { "type": "boolean" }
|
|
71
74
|
}
|
|
72
75
|
}
|
|
73
76
|
},
|
|
@@ -86,6 +89,8 @@
|
|
|
86
89
|
"bluetooth_unavailable",
|
|
87
90
|
"device_busy",
|
|
88
91
|
"disconnected",
|
|
92
|
+
"lan_unavailable",
|
|
93
|
+
"device_mismatch",
|
|
89
94
|
"code_rejected",
|
|
90
95
|
"code_locked",
|
|
91
96
|
"wifi_auth_failed",
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$id": "https://schemas.mhome.ai/app-facade/pod-discovery.v1.schema.json",
|
|
4
|
-
"title": "Native-client BLE discovery snapshot (pods and Hosts)",
|
|
4
|
+
"title": "Native-client BLE and LAN discovery snapshot (pods and Hosts)",
|
|
5
5
|
"type": "object",
|
|
6
6
|
"additionalProperties": false,
|
|
7
|
-
"required": ["revision", "scanning", "adapter", "candidates"],
|
|
7
|
+
"required": ["revision", "scanning", "lanBrowsing", "adapter", "candidates"],
|
|
8
8
|
"properties": {
|
|
9
9
|
"revision": { "type": "integer", "minimum": 0 },
|
|
10
10
|
"scanning": { "type": "boolean" },
|
|
11
|
+
"lanBrowsing": { "type": "boolean" },
|
|
12
|
+
"lanError": { "type": "string" },
|
|
11
13
|
"adapter": { "$ref": "#/$defs/adapter" },
|
|
12
14
|
"candidates": { "type": "array", "items": { "$ref": "#/$defs/candidate" } }
|
|
13
15
|
},
|
|
@@ -27,6 +29,7 @@
|
|
|
27
29
|
"required": [
|
|
28
30
|
"candidateId",
|
|
29
31
|
"kind",
|
|
32
|
+
"transport",
|
|
30
33
|
"name",
|
|
31
34
|
"shortId",
|
|
32
35
|
"rssi",
|
|
@@ -37,9 +40,11 @@
|
|
|
37
40
|
"properties": {
|
|
38
41
|
"candidateId": { "type": "string", "minLength": 1 },
|
|
39
42
|
"kind": { "enum": ["pod", "host"] },
|
|
43
|
+
"transport": { "enum": ["ble", "lan"] },
|
|
44
|
+
"deviceId": { "type": "string", "minLength": 1, "maxLength": 64 },
|
|
40
45
|
"name": { "type": "string", "minLength": 1 },
|
|
41
46
|
"model": { "type": "string" },
|
|
42
|
-
"shortId": { "type": "string", "
|
|
47
|
+
"shortId": { "type": "string", "minLength": 1, "maxLength": 64 },
|
|
43
48
|
"rssi": { "type": "integer" },
|
|
44
49
|
"commissionable": { "type": "boolean" },
|
|
45
50
|
"wifiConfigured": { "type": "boolean" },
|