@camstack/addon-export-hap 1.2.134 → 1.2.140
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/dist/hap-export.addon.js +950 -161
- package/dist/hap-export.addon.mjs +951 -161
- package/package.json +1 -1
package/dist/hap-export.addon.js
CHANGED
|
@@ -25470,6 +25470,23 @@ var videoclipsCapability = {
|
|
|
25470
25470
|
deviceId: number(),
|
|
25471
25471
|
clipId: string().min(1),
|
|
25472
25472
|
/**
|
|
25473
|
+
* WHICH provider holds the bytes — the `addonId` a
|
|
25474
|
+
* {@link ClipSourceSchema} row carries. **Required**, for the reason
|
|
25475
|
+
* `listClips` states one method above and for a second one this method
|
|
25476
|
+
* learned the hard way.
|
|
25477
|
+
*
|
|
25478
|
+
* The caller is the stream broker, and the broker lives in
|
|
25479
|
+
* `addon-pipeline` — the same addon that registers the RECORDER's
|
|
25480
|
+
* videoclips provider. With no provider named, the in-process
|
|
25481
|
+
* resolution handed it its own sibling, which implements this method
|
|
25482
|
+
* solely to explain that an analytics visit has no file behind it. So
|
|
25483
|
+
* every onboard clip answered with that sentence, a flash of video and
|
|
25484
|
+
* nothing more, while the SAME call from outside the addon reached the
|
|
25485
|
+
* right provider and returned the bytes (measured on 3628,
|
|
25486
|
+
* 2026-09-21).
|
|
25487
|
+
*/
|
|
25488
|
+
provider: string().min(1),
|
|
25489
|
+
/**
|
|
25473
25490
|
* Which twin to fetch, on the mapping D549 15 already fixed:
|
|
25474
25491
|
* `low | mid` → the sub file, `high` → the main twin. `auto` is not
|
|
25475
25492
|
* accepted here for the same reason it is not accepted by
|
|
@@ -31233,7 +31250,7 @@ method(object({
|
|
|
31233
31250
|
auth: "admin"
|
|
31234
31251
|
}), method(object({ deviceId: number() }), RecordingConfigSchema, {
|
|
31235
31252
|
kind: "query",
|
|
31236
|
-
auth: "
|
|
31253
|
+
auth: "protected"
|
|
31237
31254
|
}), method(object({
|
|
31238
31255
|
deviceId: number(),
|
|
31239
31256
|
profile: string(),
|
|
@@ -33480,6 +33497,12 @@ DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeate
|
|
|
33480
33497
|
new Set(Object.values(DeviceType));
|
|
33481
33498
|
DeviceFeature.BatteryOperated;
|
|
33482
33499
|
Object.freeze({
|
|
33500
|
+
"accessories.getStatus": {
|
|
33501
|
+
capName: "accessories",
|
|
33502
|
+
capScope: "device",
|
|
33503
|
+
addonId: null,
|
|
33504
|
+
access: "view"
|
|
33505
|
+
},
|
|
33483
33506
|
"accessories.setChildHidden": {
|
|
33484
33507
|
capName: "accessories",
|
|
33485
33508
|
capScope: "device",
|
|
@@ -33762,6 +33785,12 @@ Object.freeze({
|
|
|
33762
33785
|
addonId: null,
|
|
33763
33786
|
access: "view"
|
|
33764
33787
|
},
|
|
33788
|
+
"airQualitySensor.getStatus": {
|
|
33789
|
+
capName: "air-quality-sensor",
|
|
33790
|
+
capScope: "device",
|
|
33791
|
+
addonId: null,
|
|
33792
|
+
access: "view"
|
|
33793
|
+
},
|
|
33765
33794
|
"alarmPanel.arm": {
|
|
33766
33795
|
capName: "alarm-panel",
|
|
33767
33796
|
capScope: "device",
|
|
@@ -33774,6 +33803,12 @@ Object.freeze({
|
|
|
33774
33803
|
addonId: null,
|
|
33775
33804
|
access: "create"
|
|
33776
33805
|
},
|
|
33806
|
+
"alarmPanel.getStatus": {
|
|
33807
|
+
capName: "alarm-panel",
|
|
33808
|
+
capScope: "device",
|
|
33809
|
+
addonId: null,
|
|
33810
|
+
access: "view"
|
|
33811
|
+
},
|
|
33777
33812
|
"alarmPanel.trigger": {
|
|
33778
33813
|
capName: "alarm-panel",
|
|
33779
33814
|
capScope: "device",
|
|
@@ -33822,6 +33857,30 @@ Object.freeze({
|
|
|
33822
33857
|
addonId: null,
|
|
33823
33858
|
access: "create"
|
|
33824
33859
|
},
|
|
33860
|
+
"ambientLightSensor.getStatus": {
|
|
33861
|
+
capName: "ambient-light-sensor",
|
|
33862
|
+
capScope: "device",
|
|
33863
|
+
addonId: null,
|
|
33864
|
+
access: "view"
|
|
33865
|
+
},
|
|
33866
|
+
"audioAnalysis.applyDeviceSettingsPatch": {
|
|
33867
|
+
capName: "audio-analysis",
|
|
33868
|
+
capScope: "device",
|
|
33869
|
+
addonId: null,
|
|
33870
|
+
access: "create"
|
|
33871
|
+
},
|
|
33872
|
+
"audioAnalysis.getDeviceLiveContribution": {
|
|
33873
|
+
capName: "audio-analysis",
|
|
33874
|
+
capScope: "device",
|
|
33875
|
+
addonId: null,
|
|
33876
|
+
access: "view"
|
|
33877
|
+
},
|
|
33878
|
+
"audioAnalysis.getDeviceSettingsContribution": {
|
|
33879
|
+
capName: "audio-analysis",
|
|
33880
|
+
capScope: "device",
|
|
33881
|
+
addonId: null,
|
|
33882
|
+
access: "view"
|
|
33883
|
+
},
|
|
33825
33884
|
"audioAnalysis.resolveDeviceSettings": {
|
|
33826
33885
|
capName: "audio-analysis",
|
|
33827
33886
|
capScope: "device",
|
|
@@ -33984,6 +34043,12 @@ Object.freeze({
|
|
|
33984
34043
|
addonId: null,
|
|
33985
34044
|
access: "create"
|
|
33986
34045
|
},
|
|
34046
|
+
"automationControl.getStatus": {
|
|
34047
|
+
capName: "automation-control",
|
|
34048
|
+
capScope: "device",
|
|
34049
|
+
addonId: null,
|
|
34050
|
+
access: "view"
|
|
34051
|
+
},
|
|
33987
34052
|
"automationControl.trigger": {
|
|
33988
34053
|
capName: "automation-control",
|
|
33989
34054
|
capScope: "device",
|
|
@@ -34080,12 +34145,30 @@ Object.freeze({
|
|
|
34080
34145
|
addonId: null,
|
|
34081
34146
|
access: "create"
|
|
34082
34147
|
},
|
|
34148
|
+
"battery.getStatus": {
|
|
34149
|
+
capName: "battery",
|
|
34150
|
+
capScope: "device",
|
|
34151
|
+
addonId: null,
|
|
34152
|
+
access: "view"
|
|
34153
|
+
},
|
|
34083
34154
|
"battery.wakeForStream": {
|
|
34084
34155
|
capName: "battery",
|
|
34085
34156
|
capScope: "device",
|
|
34086
34157
|
addonId: null,
|
|
34087
34158
|
access: "create"
|
|
34088
34159
|
},
|
|
34160
|
+
"binary.getStatus": {
|
|
34161
|
+
capName: "binary",
|
|
34162
|
+
capScope: "device",
|
|
34163
|
+
addonId: null,
|
|
34164
|
+
access: "view"
|
|
34165
|
+
},
|
|
34166
|
+
"brightness.getStatus": {
|
|
34167
|
+
capName: "brightness",
|
|
34168
|
+
capScope: "device",
|
|
34169
|
+
addonId: null,
|
|
34170
|
+
access: "view"
|
|
34171
|
+
},
|
|
34089
34172
|
"brightness.setBrightness": {
|
|
34090
34173
|
capName: "brightness",
|
|
34091
34174
|
capScope: "device",
|
|
@@ -34200,6 +34283,30 @@ Object.freeze({
|
|
|
34200
34283
|
addonId: null,
|
|
34201
34284
|
access: "view"
|
|
34202
34285
|
},
|
|
34286
|
+
"cameraCredentials.getStatus": {
|
|
34287
|
+
capName: "camera-credentials",
|
|
34288
|
+
capScope: "device",
|
|
34289
|
+
addonId: null,
|
|
34290
|
+
access: "view"
|
|
34291
|
+
},
|
|
34292
|
+
"cameraGridLayout.applyDeviceSettingsPatch": {
|
|
34293
|
+
capName: "camera-grid-layout",
|
|
34294
|
+
capScope: "device",
|
|
34295
|
+
addonId: null,
|
|
34296
|
+
access: "create"
|
|
34297
|
+
},
|
|
34298
|
+
"cameraGridLayout.getDeviceLiveContribution": {
|
|
34299
|
+
capName: "camera-grid-layout",
|
|
34300
|
+
capScope: "device",
|
|
34301
|
+
addonId: null,
|
|
34302
|
+
access: "view"
|
|
34303
|
+
},
|
|
34304
|
+
"cameraGridLayout.getDeviceSettingsContribution": {
|
|
34305
|
+
capName: "camera-grid-layout",
|
|
34306
|
+
capScope: "device",
|
|
34307
|
+
addonId: null,
|
|
34308
|
+
access: "view"
|
|
34309
|
+
},
|
|
34203
34310
|
"cameraGridLayout.getLayout": {
|
|
34204
34311
|
capName: "camera-grid-layout",
|
|
34205
34312
|
capScope: "device",
|
|
@@ -34212,6 +34319,24 @@ Object.freeze({
|
|
|
34212
34319
|
addonId: null,
|
|
34213
34320
|
access: "create"
|
|
34214
34321
|
},
|
|
34322
|
+
"cameraPipelineConfig.applyDeviceSettingsPatch": {
|
|
34323
|
+
capName: "camera-pipeline-config",
|
|
34324
|
+
capScope: "device",
|
|
34325
|
+
addonId: null,
|
|
34326
|
+
access: "create"
|
|
34327
|
+
},
|
|
34328
|
+
"cameraPipelineConfig.getDeviceLiveContribution": {
|
|
34329
|
+
capName: "camera-pipeline-config",
|
|
34330
|
+
capScope: "device",
|
|
34331
|
+
addonId: null,
|
|
34332
|
+
access: "view"
|
|
34333
|
+
},
|
|
34334
|
+
"cameraPipelineConfig.getDeviceSettingsContribution": {
|
|
34335
|
+
capName: "camera-pipeline-config",
|
|
34336
|
+
capScope: "device",
|
|
34337
|
+
addonId: null,
|
|
34338
|
+
access: "view"
|
|
34339
|
+
},
|
|
34215
34340
|
"cameraStreams.getBrokerStreams": {
|
|
34216
34341
|
capName: "camera-streams",
|
|
34217
34342
|
capScope: "device",
|
|
@@ -34242,6 +34367,18 @@ Object.freeze({
|
|
|
34242
34367
|
addonId: null,
|
|
34243
34368
|
access: "view"
|
|
34244
34369
|
},
|
|
34370
|
+
"carbonMonoxide.getStatus": {
|
|
34371
|
+
capName: "carbon-monoxide",
|
|
34372
|
+
capScope: "device",
|
|
34373
|
+
addonId: null,
|
|
34374
|
+
access: "view"
|
|
34375
|
+
},
|
|
34376
|
+
"climateControl.getStatus": {
|
|
34377
|
+
capName: "climate-control",
|
|
34378
|
+
capScope: "device",
|
|
34379
|
+
addonId: null,
|
|
34380
|
+
access: "view"
|
|
34381
|
+
},
|
|
34245
34382
|
"climateControl.setFanMode": {
|
|
34246
34383
|
capName: "climate-control",
|
|
34247
34384
|
capScope: "device",
|
|
@@ -34290,6 +34427,12 @@ Object.freeze({
|
|
|
34290
34427
|
addonId: null,
|
|
34291
34428
|
access: "create"
|
|
34292
34429
|
},
|
|
34430
|
+
"color.getStatus": {
|
|
34431
|
+
capName: "color",
|
|
34432
|
+
capScope: "device",
|
|
34433
|
+
addonId: null,
|
|
34434
|
+
access: "view"
|
|
34435
|
+
},
|
|
34293
34436
|
"color.setColor": {
|
|
34294
34437
|
capName: "color",
|
|
34295
34438
|
capScope: "device",
|
|
@@ -34308,12 +34451,36 @@ Object.freeze({
|
|
|
34308
34451
|
addonId: null,
|
|
34309
34452
|
access: "create"
|
|
34310
34453
|
},
|
|
34454
|
+
"connectivity.getStatus": {
|
|
34455
|
+
capName: "connectivity",
|
|
34456
|
+
capScope: "device",
|
|
34457
|
+
addonId: null,
|
|
34458
|
+
access: "view"
|
|
34459
|
+
},
|
|
34460
|
+
"consumables.getStatus": {
|
|
34461
|
+
capName: "consumables",
|
|
34462
|
+
capScope: "device",
|
|
34463
|
+
addonId: null,
|
|
34464
|
+
access: "view"
|
|
34465
|
+
},
|
|
34311
34466
|
"consumables.reset": {
|
|
34312
34467
|
capName: "consumables",
|
|
34313
34468
|
capScope: "device",
|
|
34314
34469
|
addonId: null,
|
|
34315
34470
|
access: "delete"
|
|
34316
34471
|
},
|
|
34472
|
+
"contact.getStatus": {
|
|
34473
|
+
capName: "contact",
|
|
34474
|
+
capScope: "device",
|
|
34475
|
+
addonId: null,
|
|
34476
|
+
access: "view"
|
|
34477
|
+
},
|
|
34478
|
+
"control.getStatus": {
|
|
34479
|
+
capName: "control",
|
|
34480
|
+
capScope: "device",
|
|
34481
|
+
addonId: null,
|
|
34482
|
+
access: "view"
|
|
34483
|
+
},
|
|
34317
34484
|
"control.setValue": {
|
|
34318
34485
|
capName: "control",
|
|
34319
34486
|
capScope: "device",
|
|
@@ -34380,6 +34547,12 @@ Object.freeze({
|
|
|
34380
34547
|
addonId: null,
|
|
34381
34548
|
access: "create"
|
|
34382
34549
|
},
|
|
34550
|
+
"cover.getStatus": {
|
|
34551
|
+
capName: "cover",
|
|
34552
|
+
capScope: "device",
|
|
34553
|
+
addonId: null,
|
|
34554
|
+
access: "view"
|
|
34555
|
+
},
|
|
34383
34556
|
"cover.open": {
|
|
34384
34557
|
capName: "cover",
|
|
34385
34558
|
capScope: "device",
|
|
@@ -34512,6 +34685,12 @@ Object.freeze({
|
|
|
34512
34685
|
addonId: null,
|
|
34513
34686
|
access: "view"
|
|
34514
34687
|
},
|
|
34688
|
+
"dayNight.getStatus": {
|
|
34689
|
+
capName: "day-night",
|
|
34690
|
+
capScope: "device",
|
|
34691
|
+
addonId: null,
|
|
34692
|
+
access: "view"
|
|
34693
|
+
},
|
|
34515
34694
|
"dayNight.setSettings": {
|
|
34516
34695
|
capName: "day-night",
|
|
34517
34696
|
capScope: "device",
|
|
@@ -34602,6 +34781,24 @@ Object.freeze({
|
|
|
34602
34781
|
addonId: null,
|
|
34603
34782
|
access: "view"
|
|
34604
34783
|
},
|
|
34784
|
+
"detectionPipeline.applyDeviceSettingsPatch": {
|
|
34785
|
+
capName: "detection-pipeline",
|
|
34786
|
+
capScope: "device",
|
|
34787
|
+
addonId: null,
|
|
34788
|
+
access: "create"
|
|
34789
|
+
},
|
|
34790
|
+
"detectionPipeline.getDeviceLiveContribution": {
|
|
34791
|
+
capName: "detection-pipeline",
|
|
34792
|
+
capScope: "device",
|
|
34793
|
+
addonId: null,
|
|
34794
|
+
access: "view"
|
|
34795
|
+
},
|
|
34796
|
+
"detectionPipeline.getDeviceSettingsContribution": {
|
|
34797
|
+
capName: "detection-pipeline",
|
|
34798
|
+
capScope: "device",
|
|
34799
|
+
addonId: null,
|
|
34800
|
+
access: "view"
|
|
34801
|
+
},
|
|
34605
34802
|
"deviceAdoption.adopt": {
|
|
34606
34803
|
capName: "device-adoption",
|
|
34607
34804
|
capScope: "system",
|
|
@@ -34614,6 +34811,12 @@ Object.freeze({
|
|
|
34614
34811
|
addonId: null,
|
|
34615
34812
|
access: "view"
|
|
34616
34813
|
},
|
|
34814
|
+
"deviceAdoption.getStatus": {
|
|
34815
|
+
capName: "device-adoption",
|
|
34816
|
+
capScope: "system",
|
|
34817
|
+
addonId: null,
|
|
34818
|
+
access: "view"
|
|
34819
|
+
},
|
|
34617
34820
|
"deviceAdoption.listCandidateFilters": {
|
|
34618
34821
|
capName: "device-adoption",
|
|
34619
34822
|
capScope: "system",
|
|
@@ -34650,6 +34853,12 @@ Object.freeze({
|
|
|
34650
34853
|
addonId: null,
|
|
34651
34854
|
access: "create"
|
|
34652
34855
|
},
|
|
34856
|
+
"deviceDiscovery.getStatus": {
|
|
34857
|
+
capName: "device-discovery",
|
|
34858
|
+
capScope: "device",
|
|
34859
|
+
addonId: null,
|
|
34860
|
+
access: "view"
|
|
34861
|
+
},
|
|
34653
34862
|
"deviceDiscovery.listDiscovered": {
|
|
34654
34863
|
capName: "device-discovery",
|
|
34655
34864
|
capScope: "device",
|
|
@@ -34668,12 +34877,30 @@ Object.freeze({
|
|
|
34668
34877
|
addonId: null,
|
|
34669
34878
|
access: "create"
|
|
34670
34879
|
},
|
|
34880
|
+
"deviceExport.applyDeviceSettingsPatch": {
|
|
34881
|
+
capName: "device-export",
|
|
34882
|
+
capScope: "system",
|
|
34883
|
+
addonId: null,
|
|
34884
|
+
access: "create"
|
|
34885
|
+
},
|
|
34671
34886
|
"deviceExport.exposeDevice": {
|
|
34672
34887
|
capName: "device-export",
|
|
34673
34888
|
capScope: "system",
|
|
34674
34889
|
addonId: null,
|
|
34675
34890
|
access: "create"
|
|
34676
34891
|
},
|
|
34892
|
+
"deviceExport.getDeviceLiveContribution": {
|
|
34893
|
+
capName: "device-export",
|
|
34894
|
+
capScope: "system",
|
|
34895
|
+
addonId: null,
|
|
34896
|
+
access: "view"
|
|
34897
|
+
},
|
|
34898
|
+
"deviceExport.getDeviceSettingsContribution": {
|
|
34899
|
+
capName: "device-export",
|
|
34900
|
+
capScope: "system",
|
|
34901
|
+
addonId: null,
|
|
34902
|
+
access: "view"
|
|
34903
|
+
},
|
|
34677
34904
|
"deviceExport.getStatus": {
|
|
34678
34905
|
capName: "device-export",
|
|
34679
34906
|
capScope: "system",
|
|
@@ -34770,6 +34997,12 @@ Object.freeze({
|
|
|
34770
34997
|
addonId: null,
|
|
34771
34998
|
access: "create"
|
|
34772
34999
|
},
|
|
35000
|
+
"deviceManager.applyDeviceSettingsPatch": {
|
|
35001
|
+
capName: "device-manager",
|
|
35002
|
+
capScope: "system",
|
|
35003
|
+
addonId: null,
|
|
35004
|
+
access: "create"
|
|
35005
|
+
},
|
|
34773
35006
|
"deviceManager.applyInitialMeta": {
|
|
34774
35007
|
capName: "device-manager",
|
|
34775
35008
|
capScope: "system",
|
|
@@ -34872,6 +35105,12 @@ Object.freeze({
|
|
|
34872
35105
|
addonId: null,
|
|
34873
35106
|
access: "view"
|
|
34874
35107
|
},
|
|
35108
|
+
"deviceManager.getDeviceLiveContribution": {
|
|
35109
|
+
capName: "device-manager",
|
|
35110
|
+
capScope: "system",
|
|
35111
|
+
addonId: null,
|
|
35112
|
+
access: "view"
|
|
35113
|
+
},
|
|
34875
35114
|
"deviceManager.getDeviceLiveInfoAggregate": {
|
|
34876
35115
|
capName: "device-manager",
|
|
34877
35116
|
capScope: "system",
|
|
@@ -34884,6 +35123,12 @@ Object.freeze({
|
|
|
34884
35123
|
addonId: null,
|
|
34885
35124
|
access: "view"
|
|
34886
35125
|
},
|
|
35126
|
+
"deviceManager.getDeviceSettingsContribution": {
|
|
35127
|
+
capName: "device-manager",
|
|
35128
|
+
capScope: "system",
|
|
35129
|
+
addonId: null,
|
|
35130
|
+
access: "view"
|
|
35131
|
+
},
|
|
34887
35132
|
"deviceManager.getDeviceStatusAggregate": {
|
|
34888
35133
|
capName: "device-manager",
|
|
34889
35134
|
capScope: "system",
|
|
@@ -35376,6 +35621,36 @@ Object.freeze({
|
|
|
35376
35621
|
addonId: null,
|
|
35377
35622
|
access: "create"
|
|
35378
35623
|
},
|
|
35624
|
+
"deviceStatus.getStatus": {
|
|
35625
|
+
capName: "device-status",
|
|
35626
|
+
capScope: "device",
|
|
35627
|
+
addonId: null,
|
|
35628
|
+
access: "view"
|
|
35629
|
+
},
|
|
35630
|
+
"doorbell.applyDeviceSettingsPatch": {
|
|
35631
|
+
capName: "doorbell",
|
|
35632
|
+
capScope: "device",
|
|
35633
|
+
addonId: null,
|
|
35634
|
+
access: "create"
|
|
35635
|
+
},
|
|
35636
|
+
"doorbell.getDeviceLiveContribution": {
|
|
35637
|
+
capName: "doorbell",
|
|
35638
|
+
capScope: "device",
|
|
35639
|
+
addonId: null,
|
|
35640
|
+
access: "view"
|
|
35641
|
+
},
|
|
35642
|
+
"doorbell.getDeviceSettingsContribution": {
|
|
35643
|
+
capName: "doorbell",
|
|
35644
|
+
capScope: "device",
|
|
35645
|
+
addonId: null,
|
|
35646
|
+
access: "view"
|
|
35647
|
+
},
|
|
35648
|
+
"doorbell.getStatus": {
|
|
35649
|
+
capName: "doorbell",
|
|
35650
|
+
capScope: "device",
|
|
35651
|
+
addonId: null,
|
|
35652
|
+
access: "view"
|
|
35653
|
+
},
|
|
35379
35654
|
"embeddingEncoder.encode": {
|
|
35380
35655
|
capName: "embedding-encoder",
|
|
35381
35656
|
capScope: "system",
|
|
@@ -35394,6 +35669,18 @@ Object.freeze({
|
|
|
35394
35669
|
addonId: null,
|
|
35395
35670
|
access: "view"
|
|
35396
35671
|
},
|
|
35672
|
+
"enumSensor.getStatus": {
|
|
35673
|
+
capName: "enum-sensor",
|
|
35674
|
+
capScope: "device",
|
|
35675
|
+
addonId: null,
|
|
35676
|
+
access: "view"
|
|
35677
|
+
},
|
|
35678
|
+
"eventEmitter.getStatus": {
|
|
35679
|
+
capName: "event-emitter",
|
|
35680
|
+
capScope: "device",
|
|
35681
|
+
addonId: null,
|
|
35682
|
+
access: "view"
|
|
35683
|
+
},
|
|
35397
35684
|
"events.getEventClipUrl": {
|
|
35398
35685
|
capName: "events",
|
|
35399
35686
|
capScope: "device",
|
|
@@ -35514,6 +35801,12 @@ Object.freeze({
|
|
|
35514
35801
|
addonId: null,
|
|
35515
35802
|
access: "view"
|
|
35516
35803
|
},
|
|
35804
|
+
"fanControl.getStatus": {
|
|
35805
|
+
capName: "fan-control",
|
|
35806
|
+
capScope: "device",
|
|
35807
|
+
addonId: null,
|
|
35808
|
+
access: "view"
|
|
35809
|
+
},
|
|
35517
35810
|
"fanControl.setDirection": {
|
|
35518
35811
|
capName: "fan-control",
|
|
35519
35812
|
capScope: "device",
|
|
@@ -35538,6 +35831,12 @@ Object.freeze({
|
|
|
35538
35831
|
addonId: null,
|
|
35539
35832
|
access: "create"
|
|
35540
35833
|
},
|
|
35834
|
+
"featureProbe.getStatus": {
|
|
35835
|
+
capName: "feature-probe",
|
|
35836
|
+
capScope: "device",
|
|
35837
|
+
addonId: null,
|
|
35838
|
+
access: "view"
|
|
35839
|
+
},
|
|
35541
35840
|
"filesystemBrowse.browse": {
|
|
35542
35841
|
capName: "filesystem-browse",
|
|
35543
35842
|
capScope: "system",
|
|
@@ -35556,6 +35855,24 @@ Object.freeze({
|
|
|
35556
35855
|
addonId: null,
|
|
35557
35856
|
access: "view"
|
|
35558
35857
|
},
|
|
35858
|
+
"flood.getStatus": {
|
|
35859
|
+
capName: "flood",
|
|
35860
|
+
capScope: "device",
|
|
35861
|
+
addonId: null,
|
|
35862
|
+
access: "view"
|
|
35863
|
+
},
|
|
35864
|
+
"gas.getStatus": {
|
|
35865
|
+
capName: "gas",
|
|
35866
|
+
capScope: "device",
|
|
35867
|
+
addonId: null,
|
|
35868
|
+
access: "view"
|
|
35869
|
+
},
|
|
35870
|
+
"humidifier.getStatus": {
|
|
35871
|
+
capName: "humidifier",
|
|
35872
|
+
capScope: "device",
|
|
35873
|
+
addonId: null,
|
|
35874
|
+
access: "view"
|
|
35875
|
+
},
|
|
35559
35876
|
"humidifier.setMode": {
|
|
35560
35877
|
capName: "humidifier",
|
|
35561
35878
|
capScope: "device",
|
|
@@ -35574,12 +35891,30 @@ Object.freeze({
|
|
|
35574
35891
|
addonId: null,
|
|
35575
35892
|
access: "create"
|
|
35576
35893
|
},
|
|
35894
|
+
"humiditySensor.getStatus": {
|
|
35895
|
+
capName: "humidity-sensor",
|
|
35896
|
+
capScope: "device",
|
|
35897
|
+
addonId: null,
|
|
35898
|
+
access: "view"
|
|
35899
|
+
},
|
|
35900
|
+
"image.getStatus": {
|
|
35901
|
+
capName: "image",
|
|
35902
|
+
capScope: "device",
|
|
35903
|
+
addonId: null,
|
|
35904
|
+
access: "view"
|
|
35905
|
+
},
|
|
35577
35906
|
"imageSettings.getOptions": {
|
|
35578
35907
|
capName: "image-settings",
|
|
35579
35908
|
capScope: "device",
|
|
35580
35909
|
addonId: null,
|
|
35581
35910
|
access: "view"
|
|
35582
35911
|
},
|
|
35912
|
+
"imageSettings.getStatus": {
|
|
35913
|
+
capName: "image-settings",
|
|
35914
|
+
capScope: "device",
|
|
35915
|
+
addonId: null,
|
|
35916
|
+
access: "view"
|
|
35917
|
+
},
|
|
35583
35918
|
"imageSettings.setSettings": {
|
|
35584
35919
|
capName: "image-settings",
|
|
35585
35920
|
capScope: "device",
|
|
@@ -35652,6 +35987,12 @@ Object.freeze({
|
|
|
35652
35987
|
addonId: null,
|
|
35653
35988
|
access: "create"
|
|
35654
35989
|
},
|
|
35990
|
+
"intercom.getStatus": {
|
|
35991
|
+
capName: "intercom",
|
|
35992
|
+
capScope: "device",
|
|
35993
|
+
addonId: null,
|
|
35994
|
+
access: "view"
|
|
35995
|
+
},
|
|
35655
35996
|
"intercom.handleAnswer": {
|
|
35656
35997
|
capName: "intercom",
|
|
35657
35998
|
capScope: "device",
|
|
@@ -35688,6 +36029,12 @@ Object.freeze({
|
|
|
35688
36029
|
addonId: null,
|
|
35689
36030
|
access: "create"
|
|
35690
36031
|
},
|
|
36032
|
+
"lawnMowerControl.getStatus": {
|
|
36033
|
+
capName: "lawn-mower-control",
|
|
36034
|
+
capScope: "device",
|
|
36035
|
+
addonId: null,
|
|
36036
|
+
access: "view"
|
|
36037
|
+
},
|
|
35691
36038
|
"lawnMowerControl.pause": {
|
|
35692
36039
|
capName: "lawn-mower-control",
|
|
35693
36040
|
capScope: "device",
|
|
@@ -35970,6 +36317,12 @@ Object.freeze({
|
|
|
35970
36317
|
addonId: null,
|
|
35971
36318
|
access: "create"
|
|
35972
36319
|
},
|
|
36320
|
+
"lockControl.getStatus": {
|
|
36321
|
+
capName: "lock-control",
|
|
36322
|
+
capScope: "device",
|
|
36323
|
+
addonId: null,
|
|
36324
|
+
access: "view"
|
|
36325
|
+
},
|
|
35973
36326
|
"lockControl.lock": {
|
|
35974
36327
|
capName: "lock-control",
|
|
35975
36328
|
capScope: "device",
|
|
@@ -36018,6 +36371,12 @@ Object.freeze({
|
|
|
36018
36371
|
addonId: null,
|
|
36019
36372
|
access: "view"
|
|
36020
36373
|
},
|
|
36374
|
+
"mediaPlayer.getStatus": {
|
|
36375
|
+
capName: "media-player",
|
|
36376
|
+
capScope: "device",
|
|
36377
|
+
addonId: null,
|
|
36378
|
+
access: "view"
|
|
36379
|
+
},
|
|
36021
36380
|
"mediaPlayer.next": {
|
|
36022
36381
|
capName: "media-player",
|
|
36023
36382
|
capScope: "device",
|
|
@@ -36210,6 +36569,12 @@ Object.freeze({
|
|
|
36210
36569
|
addonId: null,
|
|
36211
36570
|
access: "create"
|
|
36212
36571
|
},
|
|
36572
|
+
"motion.getStatus": {
|
|
36573
|
+
capName: "motion",
|
|
36574
|
+
capScope: "device",
|
|
36575
|
+
addonId: null,
|
|
36576
|
+
access: "view"
|
|
36577
|
+
},
|
|
36213
36578
|
"motion.isDetected": {
|
|
36214
36579
|
capName: "motion",
|
|
36215
36580
|
capScope: "device",
|
|
@@ -36222,6 +36587,24 @@ Object.freeze({
|
|
|
36222
36587
|
addonId: null,
|
|
36223
36588
|
access: "create"
|
|
36224
36589
|
},
|
|
36590
|
+
"motionDetection.applyDeviceSettingsPatch": {
|
|
36591
|
+
capName: "motion-detection",
|
|
36592
|
+
capScope: "device",
|
|
36593
|
+
addonId: null,
|
|
36594
|
+
access: "create"
|
|
36595
|
+
},
|
|
36596
|
+
"motionDetection.getDeviceLiveContribution": {
|
|
36597
|
+
capName: "motion-detection",
|
|
36598
|
+
capScope: "device",
|
|
36599
|
+
addonId: null,
|
|
36600
|
+
access: "view"
|
|
36601
|
+
},
|
|
36602
|
+
"motionDetection.getDeviceSettingsContribution": {
|
|
36603
|
+
capName: "motion-detection",
|
|
36604
|
+
capScope: "device",
|
|
36605
|
+
addonId: null,
|
|
36606
|
+
access: "view"
|
|
36607
|
+
},
|
|
36225
36608
|
"motionDetection.removeCamera": {
|
|
36226
36609
|
capName: "motion-detection",
|
|
36227
36610
|
capScope: "device",
|
|
@@ -36234,6 +36617,12 @@ Object.freeze({
|
|
|
36234
36617
|
addonId: null,
|
|
36235
36618
|
access: "delete"
|
|
36236
36619
|
},
|
|
36620
|
+
"motionTrigger.getStatus": {
|
|
36621
|
+
capName: "motion-trigger",
|
|
36622
|
+
capScope: "device",
|
|
36623
|
+
addonId: null,
|
|
36624
|
+
access: "view"
|
|
36625
|
+
},
|
|
36237
36626
|
"motionTrigger.setMotionTrigger": {
|
|
36238
36627
|
capName: "motion-trigger",
|
|
36239
36628
|
capScope: "device",
|
|
@@ -36246,6 +36635,12 @@ Object.freeze({
|
|
|
36246
36635
|
addonId: null,
|
|
36247
36636
|
access: "view"
|
|
36248
36637
|
},
|
|
36638
|
+
"motionZones.getStatus": {
|
|
36639
|
+
capName: "motion-zones",
|
|
36640
|
+
capScope: "device",
|
|
36641
|
+
addonId: null,
|
|
36642
|
+
access: "view"
|
|
36643
|
+
},
|
|
36249
36644
|
"motionZones.setZone": {
|
|
36250
36645
|
capName: "motion-zones",
|
|
36251
36646
|
capScope: "device",
|
|
@@ -36306,6 +36701,12 @@ Object.freeze({
|
|
|
36306
36701
|
addonId: null,
|
|
36307
36702
|
access: "view"
|
|
36308
36703
|
},
|
|
36704
|
+
"nativeObjectDetection.getStatus": {
|
|
36705
|
+
capName: "native-object-detection",
|
|
36706
|
+
capScope: "device",
|
|
36707
|
+
addonId: null,
|
|
36708
|
+
access: "view"
|
|
36709
|
+
},
|
|
36309
36710
|
"nativeObjectDetection.setEnabled": {
|
|
36310
36711
|
capName: "native-object-detection",
|
|
36311
36712
|
capScope: "device",
|
|
@@ -36324,6 +36725,12 @@ Object.freeze({
|
|
|
36324
36725
|
addonId: null,
|
|
36325
36726
|
access: "view"
|
|
36326
36727
|
},
|
|
36728
|
+
"navigation.getStatus": {
|
|
36729
|
+
capName: "navigation",
|
|
36730
|
+
capScope: "device",
|
|
36731
|
+
addonId: null,
|
|
36732
|
+
access: "view"
|
|
36733
|
+
},
|
|
36327
36734
|
"navigation.goToPoint": {
|
|
36328
36735
|
capName: "navigation",
|
|
36329
36736
|
capScope: "device",
|
|
@@ -36408,6 +36815,12 @@ Object.freeze({
|
|
|
36408
36815
|
addonId: null,
|
|
36409
36816
|
access: "create"
|
|
36410
36817
|
},
|
|
36818
|
+
"networkLink.getStatus": {
|
|
36819
|
+
capName: "network-link",
|
|
36820
|
+
capScope: "device",
|
|
36821
|
+
addonId: null,
|
|
36822
|
+
access: "view"
|
|
36823
|
+
},
|
|
36411
36824
|
"networkQuality.getAllStats": {
|
|
36412
36825
|
capName: "network-quality",
|
|
36413
36826
|
capScope: "system",
|
|
@@ -36666,18 +37079,36 @@ Object.freeze({
|
|
|
36666
37079
|
addonId: null,
|
|
36667
37080
|
access: "create"
|
|
36668
37081
|
},
|
|
37082
|
+
"notifier.getStatus": {
|
|
37083
|
+
capName: "notifier",
|
|
37084
|
+
capScope: "device",
|
|
37085
|
+
addonId: null,
|
|
37086
|
+
access: "view"
|
|
37087
|
+
},
|
|
36669
37088
|
"notifier.send": {
|
|
36670
37089
|
capName: "notifier",
|
|
36671
37090
|
capScope: "device",
|
|
36672
37091
|
addonId: null,
|
|
36673
37092
|
access: "create"
|
|
36674
37093
|
},
|
|
37094
|
+
"numericSensor.getStatus": {
|
|
37095
|
+
capName: "numeric-sensor",
|
|
37096
|
+
capScope: "device",
|
|
37097
|
+
addonId: null,
|
|
37098
|
+
access: "view"
|
|
37099
|
+
},
|
|
36675
37100
|
"oauthIntegration.getDescriptor": {
|
|
36676
37101
|
capName: "oauth-integration",
|
|
36677
37102
|
capScope: "system",
|
|
36678
37103
|
addonId: null,
|
|
36679
37104
|
access: "view"
|
|
36680
37105
|
},
|
|
37106
|
+
"osd.getStatus": {
|
|
37107
|
+
capName: "osd",
|
|
37108
|
+
capScope: "device",
|
|
37109
|
+
addonId: null,
|
|
37110
|
+
access: "view"
|
|
37111
|
+
},
|
|
36681
37112
|
"osd.setOverlay": {
|
|
36682
37113
|
capName: "osd",
|
|
36683
37114
|
capScope: "device",
|
|
@@ -36750,6 +37181,12 @@ Object.freeze({
|
|
|
36750
37181
|
addonId: null,
|
|
36751
37182
|
access: "create"
|
|
36752
37183
|
},
|
|
37184
|
+
"petFeeder.getStatus": {
|
|
37185
|
+
capName: "pet-feeder",
|
|
37186
|
+
capScope: "device",
|
|
37187
|
+
addonId: null,
|
|
37188
|
+
access: "view"
|
|
37189
|
+
},
|
|
36753
37190
|
"petFeeder.markFoodReplenished": {
|
|
36754
37191
|
capName: "pet-feeder",
|
|
36755
37192
|
capScope: "device",
|
|
@@ -36792,6 +37229,12 @@ Object.freeze({
|
|
|
36792
37229
|
addonId: null,
|
|
36793
37230
|
access: "create"
|
|
36794
37231
|
},
|
|
37232
|
+
"pipelineAnalytics.applyDeviceSettingsPatch": {
|
|
37233
|
+
capName: "pipeline-analytics",
|
|
37234
|
+
capScope: "device",
|
|
37235
|
+
addonId: null,
|
|
37236
|
+
access: "create"
|
|
37237
|
+
},
|
|
36795
37238
|
"pipelineAnalytics.cancelRelocateMedia": {
|
|
36796
37239
|
capName: "pipeline-analytics",
|
|
36797
37240
|
capScope: "device",
|
|
@@ -36858,6 +37301,18 @@ Object.freeze({
|
|
|
36858
37301
|
addonId: null,
|
|
36859
37302
|
access: "view"
|
|
36860
37303
|
},
|
|
37304
|
+
"pipelineAnalytics.getDeviceLiveContribution": {
|
|
37305
|
+
capName: "pipeline-analytics",
|
|
37306
|
+
capScope: "device",
|
|
37307
|
+
addonId: null,
|
|
37308
|
+
access: "view"
|
|
37309
|
+
},
|
|
37310
|
+
"pipelineAnalytics.getDeviceSettingsContribution": {
|
|
37311
|
+
capName: "pipeline-analytics",
|
|
37312
|
+
capScope: "device",
|
|
37313
|
+
addonId: null,
|
|
37314
|
+
access: "view"
|
|
37315
|
+
},
|
|
36861
37316
|
"pipelineAnalytics.getEventDensity": {
|
|
36862
37317
|
capName: "pipeline-analytics",
|
|
36863
37318
|
capScope: "device",
|
|
@@ -37428,6 +37883,12 @@ Object.freeze({
|
|
|
37428
37883
|
addonId: null,
|
|
37429
37884
|
access: "view"
|
|
37430
37885
|
},
|
|
37886
|
+
"pipelineOrchestrator.applyDeviceSettingsPatch": {
|
|
37887
|
+
capName: "pipeline-orchestrator",
|
|
37888
|
+
capScope: "system",
|
|
37889
|
+
addonId: null,
|
|
37890
|
+
access: "create"
|
|
37891
|
+
},
|
|
37431
37892
|
"pipelineOrchestrator.assignAudio": {
|
|
37432
37893
|
capName: "pipeline-orchestrator",
|
|
37433
37894
|
capScope: "system",
|
|
@@ -37518,6 +37979,18 @@ Object.freeze({
|
|
|
37518
37979
|
addonId: null,
|
|
37519
37980
|
access: "view"
|
|
37520
37981
|
},
|
|
37982
|
+
"pipelineOrchestrator.getDeviceLiveContribution": {
|
|
37983
|
+
capName: "pipeline-orchestrator",
|
|
37984
|
+
capScope: "system",
|
|
37985
|
+
addonId: null,
|
|
37986
|
+
access: "view"
|
|
37987
|
+
},
|
|
37988
|
+
"pipelineOrchestrator.getDeviceSettingsContribution": {
|
|
37989
|
+
capName: "pipeline-orchestrator",
|
|
37990
|
+
capScope: "system",
|
|
37991
|
+
addonId: null,
|
|
37992
|
+
access: "view"
|
|
37993
|
+
},
|
|
37521
37994
|
"pipelineOrchestrator.getGlobalMetrics": {
|
|
37522
37995
|
capName: "pipeline-orchestrator",
|
|
37523
37996
|
capScope: "system",
|
|
@@ -37926,12 +38399,36 @@ Object.freeze({
|
|
|
37926
38399
|
addonId: null,
|
|
37927
38400
|
access: "view"
|
|
37928
38401
|
},
|
|
38402
|
+
"powerMeter.getStatus": {
|
|
38403
|
+
capName: "power-meter",
|
|
38404
|
+
capScope: "device",
|
|
38405
|
+
addonId: null,
|
|
38406
|
+
access: "view"
|
|
38407
|
+
},
|
|
38408
|
+
"presence.getStatus": {
|
|
38409
|
+
capName: "presence",
|
|
38410
|
+
capScope: "device",
|
|
38411
|
+
addonId: null,
|
|
38412
|
+
access: "view"
|
|
38413
|
+
},
|
|
38414
|
+
"pressureSensor.getStatus": {
|
|
38415
|
+
capName: "pressure-sensor",
|
|
38416
|
+
capScope: "device",
|
|
38417
|
+
addonId: null,
|
|
38418
|
+
access: "view"
|
|
38419
|
+
},
|
|
37929
38420
|
"privacyMask.getOptions": {
|
|
37930
38421
|
capName: "privacy-mask",
|
|
37931
38422
|
capScope: "device",
|
|
37932
38423
|
addonId: null,
|
|
37933
38424
|
access: "view"
|
|
37934
38425
|
},
|
|
38426
|
+
"privacyMask.getStatus": {
|
|
38427
|
+
capName: "privacy-mask",
|
|
38428
|
+
capScope: "device",
|
|
38429
|
+
addonId: null,
|
|
38430
|
+
access: "view"
|
|
38431
|
+
},
|
|
37935
38432
|
"privacyMask.setAudioEnabled": {
|
|
37936
38433
|
capName: "privacy-mask",
|
|
37937
38434
|
capScope: "device",
|
|
@@ -37992,6 +38489,12 @@ Object.freeze({
|
|
|
37992
38489
|
addonId: null,
|
|
37993
38490
|
access: "view"
|
|
37994
38491
|
},
|
|
38492
|
+
"ptz.getStatus": {
|
|
38493
|
+
capName: "ptz",
|
|
38494
|
+
capScope: "device",
|
|
38495
|
+
addonId: null,
|
|
38496
|
+
access: "view"
|
|
38497
|
+
},
|
|
37995
38498
|
"ptz.goHome": {
|
|
37996
38499
|
capName: "ptz",
|
|
37997
38500
|
capScope: "device",
|
|
@@ -38070,6 +38573,12 @@ Object.freeze({
|
|
|
38070
38573
|
addonId: null,
|
|
38071
38574
|
access: "create"
|
|
38072
38575
|
},
|
|
38576
|
+
"recording.applyDeviceSettingsPatch": {
|
|
38577
|
+
capName: "recording",
|
|
38578
|
+
capScope: "system",
|
|
38579
|
+
addonId: null,
|
|
38580
|
+
access: "create"
|
|
38581
|
+
},
|
|
38073
38582
|
"recording.cancelRelocateJob": {
|
|
38074
38583
|
capName: "recording",
|
|
38075
38584
|
capScope: "system",
|
|
@@ -38118,6 +38627,18 @@ Object.freeze({
|
|
|
38118
38627
|
addonId: null,
|
|
38119
38628
|
access: "view"
|
|
38120
38629
|
},
|
|
38630
|
+
"recording.getDeviceLiveContribution": {
|
|
38631
|
+
capName: "recording",
|
|
38632
|
+
capScope: "system",
|
|
38633
|
+
addonId: null,
|
|
38634
|
+
access: "view"
|
|
38635
|
+
},
|
|
38636
|
+
"recording.getDeviceSettingsContribution": {
|
|
38637
|
+
capName: "recording",
|
|
38638
|
+
capScope: "system",
|
|
38639
|
+
addonId: null,
|
|
38640
|
+
access: "view"
|
|
38641
|
+
},
|
|
38121
38642
|
"recording.getPlacement": {
|
|
38122
38643
|
capName: "recording",
|
|
38123
38644
|
capScope: "system",
|
|
@@ -38136,6 +38657,12 @@ Object.freeze({
|
|
|
38136
38657
|
addonId: null,
|
|
38137
38658
|
access: "view"
|
|
38138
38659
|
},
|
|
38660
|
+
"recording.getStatus": {
|
|
38661
|
+
capName: "recording",
|
|
38662
|
+
capScope: "system",
|
|
38663
|
+
addonId: null,
|
|
38664
|
+
access: "view"
|
|
38665
|
+
},
|
|
38139
38666
|
"recording.getStorageMigrationMoveStatus": {
|
|
38140
38667
|
capName: "recording",
|
|
38141
38668
|
capScope: "system",
|
|
@@ -38340,6 +38867,12 @@ Object.freeze({
|
|
|
38340
38867
|
addonId: null,
|
|
38341
38868
|
access: "delete"
|
|
38342
38869
|
},
|
|
38870
|
+
"sceneMonitor.getStatus": {
|
|
38871
|
+
capName: "scene-monitor",
|
|
38872
|
+
capScope: "device",
|
|
38873
|
+
addonId: null,
|
|
38874
|
+
access: "view"
|
|
38875
|
+
},
|
|
38343
38876
|
"sceneMonitor.listScenes": {
|
|
38344
38877
|
capName: "scene-monitor",
|
|
38345
38878
|
capScope: "device",
|
|
@@ -38370,6 +38903,12 @@ Object.freeze({
|
|
|
38370
38903
|
addonId: null,
|
|
38371
38904
|
access: "create"
|
|
38372
38905
|
},
|
|
38906
|
+
"scriptRunner.getStatus": {
|
|
38907
|
+
capName: "script-runner",
|
|
38908
|
+
capScope: "device",
|
|
38909
|
+
addonId: null,
|
|
38910
|
+
access: "view"
|
|
38911
|
+
},
|
|
38373
38912
|
"scriptRunner.run": {
|
|
38374
38913
|
capName: "script-runner",
|
|
38375
38914
|
capScope: "device",
|
|
@@ -38502,6 +39041,12 @@ Object.freeze({
|
|
|
38502
39041
|
addonId: null,
|
|
38503
39042
|
access: "create"
|
|
38504
39043
|
},
|
|
39044
|
+
"smoke.getStatus": {
|
|
39045
|
+
capName: "smoke",
|
|
39046
|
+
capScope: "device",
|
|
39047
|
+
addonId: null,
|
|
39048
|
+
access: "view"
|
|
39049
|
+
},
|
|
38505
39050
|
"smtpProvider.getStatus": {
|
|
38506
39051
|
capName: "smtp-provider",
|
|
38507
39052
|
capScope: "system",
|
|
@@ -38520,12 +39065,30 @@ Object.freeze({
|
|
|
38520
39065
|
addonId: null,
|
|
38521
39066
|
access: "view"
|
|
38522
39067
|
},
|
|
39068
|
+
"snapshot.applyDeviceSettingsPatch": {
|
|
39069
|
+
capName: "snapshot",
|
|
39070
|
+
capScope: "device",
|
|
39071
|
+
addonId: null,
|
|
39072
|
+
access: "create"
|
|
39073
|
+
},
|
|
38523
39074
|
"snapshot.getDebugState": {
|
|
38524
39075
|
capName: "snapshot",
|
|
38525
39076
|
capScope: "device",
|
|
38526
39077
|
addonId: null,
|
|
38527
39078
|
access: "view"
|
|
38528
39079
|
},
|
|
39080
|
+
"snapshot.getDeviceLiveContribution": {
|
|
39081
|
+
capName: "snapshot",
|
|
39082
|
+
capScope: "device",
|
|
39083
|
+
addonId: null,
|
|
39084
|
+
access: "view"
|
|
39085
|
+
},
|
|
39086
|
+
"snapshot.getDeviceSettingsContribution": {
|
|
39087
|
+
capName: "snapshot",
|
|
39088
|
+
capScope: "device",
|
|
39089
|
+
addonId: null,
|
|
39090
|
+
access: "view"
|
|
39091
|
+
},
|
|
38529
39092
|
"snapshot.getSnapshot": {
|
|
38530
39093
|
capName: "snapshot",
|
|
38531
39094
|
capScope: "device",
|
|
@@ -38544,6 +39107,12 @@ Object.freeze({
|
|
|
38544
39107
|
addonId: null,
|
|
38545
39108
|
access: "view"
|
|
38546
39109
|
},
|
|
39110
|
+
"snapshot.getStatus": {
|
|
39111
|
+
capName: "snapshot",
|
|
39112
|
+
capScope: "device",
|
|
39113
|
+
addonId: null,
|
|
39114
|
+
access: "view"
|
|
39115
|
+
},
|
|
38547
39116
|
"snapshot.invalidateCache": {
|
|
38548
39117
|
capName: "snapshot",
|
|
38549
39118
|
capScope: "device",
|
|
@@ -38880,6 +39449,12 @@ Object.freeze({
|
|
|
38880
39449
|
addonId: null,
|
|
38881
39450
|
access: "create"
|
|
38882
39451
|
},
|
|
39452
|
+
"streamBroker.applyDeviceSettingsPatch": {
|
|
39453
|
+
capName: "stream-broker",
|
|
39454
|
+
capScope: "system",
|
|
39455
|
+
addonId: null,
|
|
39456
|
+
access: "create"
|
|
39457
|
+
},
|
|
38883
39458
|
"streamBroker.assignProfile": {
|
|
38884
39459
|
capName: "stream-broker",
|
|
38885
39460
|
capScope: "system",
|
|
@@ -38916,6 +39491,18 @@ Object.freeze({
|
|
|
38916
39491
|
addonId: null,
|
|
38917
39492
|
access: "view"
|
|
38918
39493
|
},
|
|
39494
|
+
"streamBroker.getDeviceLiveContribution": {
|
|
39495
|
+
capName: "stream-broker",
|
|
39496
|
+
capScope: "system",
|
|
39497
|
+
addonId: null,
|
|
39498
|
+
access: "view"
|
|
39499
|
+
},
|
|
39500
|
+
"streamBroker.getDeviceSettingsContribution": {
|
|
39501
|
+
capName: "stream-broker",
|
|
39502
|
+
capScope: "system",
|
|
39503
|
+
addonId: null,
|
|
39504
|
+
access: "view"
|
|
39505
|
+
},
|
|
38919
39506
|
"streamBroker.getPreBufferInfo": {
|
|
38920
39507
|
capName: "stream-broker",
|
|
38921
39508
|
capScope: "system",
|
|
@@ -39114,6 +39701,12 @@ Object.freeze({
|
|
|
39114
39701
|
addonId: null,
|
|
39115
39702
|
access: "view"
|
|
39116
39703
|
},
|
|
39704
|
+
"streamParams.getStatus": {
|
|
39705
|
+
capName: "stream-params",
|
|
39706
|
+
capScope: "device",
|
|
39707
|
+
addonId: null,
|
|
39708
|
+
access: "view"
|
|
39709
|
+
},
|
|
39117
39710
|
"streamParams.setProfile": {
|
|
39118
39711
|
capName: "stream-params",
|
|
39119
39712
|
capScope: "device",
|
|
@@ -39126,6 +39719,12 @@ Object.freeze({
|
|
|
39126
39719
|
addonId: null,
|
|
39127
39720
|
access: "view"
|
|
39128
39721
|
},
|
|
39722
|
+
"switch.getStatus": {
|
|
39723
|
+
capName: "switch",
|
|
39724
|
+
capScope: "device",
|
|
39725
|
+
addonId: null,
|
|
39726
|
+
access: "view"
|
|
39727
|
+
},
|
|
39129
39728
|
"switch.setState": {
|
|
39130
39729
|
capName: "switch",
|
|
39131
39730
|
capScope: "device",
|
|
@@ -39222,6 +39821,18 @@ Object.freeze({
|
|
|
39222
39821
|
addonId: null,
|
|
39223
39822
|
access: "create"
|
|
39224
39823
|
},
|
|
39824
|
+
"tamper.getStatus": {
|
|
39825
|
+
capName: "tamper",
|
|
39826
|
+
capScope: "device",
|
|
39827
|
+
addonId: null,
|
|
39828
|
+
access: "view"
|
|
39829
|
+
},
|
|
39830
|
+
"temperatureSensor.getStatus": {
|
|
39831
|
+
capName: "temperature-sensor",
|
|
39832
|
+
capScope: "device",
|
|
39833
|
+
addonId: null,
|
|
39834
|
+
access: "view"
|
|
39835
|
+
},
|
|
39225
39836
|
"terminalSession.adoptLegacyMonitor": {
|
|
39226
39837
|
capName: "terminal-session",
|
|
39227
39838
|
capScope: "system",
|
|
@@ -39318,6 +39929,12 @@ Object.freeze({
|
|
|
39318
39929
|
addonId: null,
|
|
39319
39930
|
access: "view"
|
|
39320
39931
|
},
|
|
39932
|
+
"update.getStatus": {
|
|
39933
|
+
capName: "update",
|
|
39934
|
+
capScope: "device",
|
|
39935
|
+
addonId: null,
|
|
39936
|
+
access: "view"
|
|
39937
|
+
},
|
|
39321
39938
|
"update.installUpdate": {
|
|
39322
39939
|
capName: "update",
|
|
39323
39940
|
capScope: "device",
|
|
@@ -39540,6 +40157,12 @@ Object.freeze({
|
|
|
39540
40157
|
addonId: null,
|
|
39541
40158
|
access: "create"
|
|
39542
40159
|
},
|
|
40160
|
+
"vacuumControl.getStatus": {
|
|
40161
|
+
capName: "vacuum-control",
|
|
40162
|
+
capScope: "device",
|
|
40163
|
+
addonId: null,
|
|
40164
|
+
access: "view"
|
|
40165
|
+
},
|
|
39543
40166
|
"vacuumControl.locate": {
|
|
39544
40167
|
capName: "vacuum-control",
|
|
39545
40168
|
capScope: "device",
|
|
@@ -39582,6 +40205,12 @@ Object.freeze({
|
|
|
39582
40205
|
addonId: null,
|
|
39583
40206
|
access: "create"
|
|
39584
40207
|
},
|
|
40208
|
+
"valve.getStatus": {
|
|
40209
|
+
capName: "valve",
|
|
40210
|
+
capScope: "device",
|
|
40211
|
+
addonId: null,
|
|
40212
|
+
access: "view"
|
|
40213
|
+
},
|
|
39585
40214
|
"valve.open": {
|
|
39586
40215
|
capName: "valve",
|
|
39587
40216
|
capScope: "device",
|
|
@@ -39654,6 +40283,12 @@ Object.freeze({
|
|
|
39654
40283
|
addonId: null,
|
|
39655
40284
|
access: "create"
|
|
39656
40285
|
},
|
|
40286
|
+
"vibration.getStatus": {
|
|
40287
|
+
capName: "vibration",
|
|
40288
|
+
capScope: "device",
|
|
40289
|
+
addonId: null,
|
|
40290
|
+
access: "view"
|
|
40291
|
+
},
|
|
39657
40292
|
"videoclips.getClipPlayback": {
|
|
39658
40293
|
capName: "videoclips",
|
|
39659
40294
|
capScope: "device",
|
|
@@ -39690,6 +40325,12 @@ Object.freeze({
|
|
|
39690
40325
|
addonId: null,
|
|
39691
40326
|
access: "view"
|
|
39692
40327
|
},
|
|
40328
|
+
"waterHeater.getStatus": {
|
|
40329
|
+
capName: "water-heater",
|
|
40330
|
+
capScope: "device",
|
|
40331
|
+
addonId: null,
|
|
40332
|
+
access: "view"
|
|
40333
|
+
},
|
|
39693
40334
|
"waterHeater.setAway": {
|
|
39694
40335
|
capName: "water-heater",
|
|
39695
40336
|
capScope: "device",
|
|
@@ -39708,6 +40349,12 @@ Object.freeze({
|
|
|
39708
40349
|
addonId: null,
|
|
39709
40350
|
access: "create"
|
|
39710
40351
|
},
|
|
40352
|
+
"weather.getStatus": {
|
|
40353
|
+
capName: "weather",
|
|
40354
|
+
capScope: "device",
|
|
40355
|
+
addonId: null,
|
|
40356
|
+
access: "view"
|
|
40357
|
+
},
|
|
39711
40358
|
"webrtcSession.addIceCandidate": {
|
|
39712
40359
|
capName: "webrtc-session",
|
|
39713
40360
|
capScope: "device",
|
|
@@ -90670,6 +91317,153 @@ function createClipThumbnailMinter(input) {
|
|
|
90670
91317
|
};
|
|
90671
91318
|
}
|
|
90672
91319
|
//#endregion
|
|
91320
|
+
//#region src/hksv/recording-active.ts
|
|
91321
|
+
/**
|
|
91322
|
+
* `true`/`false` as HomeKit holds it, or `null` when this accessory does not
|
|
91323
|
+
* offer recording at all.
|
|
91324
|
+
*/
|
|
91325
|
+
function readHomekitRecordingActive(accessories) {
|
|
91326
|
+
for (const accessory of accessories) {
|
|
91327
|
+
const service = accessory.getService(import_dist.Service.CameraRecordingManagement);
|
|
91328
|
+
if (service === void 0) continue;
|
|
91329
|
+
const value = service.getCharacteristic(import_dist.Characteristic.Active).value;
|
|
91330
|
+
if (typeof value === "number") return value === 1;
|
|
91331
|
+
if (typeof value === "boolean") return value;
|
|
91332
|
+
return null;
|
|
91333
|
+
}
|
|
91334
|
+
return null;
|
|
91335
|
+
}
|
|
91336
|
+
/**
|
|
91337
|
+
* One sentence for the settings page: what HomeKit says, or why it was never
|
|
91338
|
+
* asked.
|
|
91339
|
+
*
|
|
91340
|
+
* The cost stays in the text even though the switch is gone. It is still the
|
|
91341
|
+
* operator's to understand — a camera recording here runs a permanent ffmpeg —
|
|
91342
|
+
* and a status line that reported only the state would have quietly dropped
|
|
91343
|
+
* the one number that decides whether to turn it on.
|
|
91344
|
+
*/
|
|
91345
|
+
function describeHomekitRecording(active, lastBuild) {
|
|
91346
|
+
if (active === true) return "HomeKit is recording this camera. Turn it off in the Home app (Camera settings → “Stream”), not here — iOS owns this switch and keeps it across reboots. While it is on, this camera runs a permanent prebuffer (~0.7% of one CPU core on the copy branch).";
|
|
91347
|
+
if (active === false) return "This camera offers recording and HomeKit has it off. Turn it on in the Home app (Camera settings → “Stream and Allow Recording”); it needs iCloud+ and a home hub. Nothing runs here until you do.";
|
|
91348
|
+
if (lastBuild !== null && !lastBuild.advertised) return `Recording is not offered for this camera: ${lastBuild.detail ?? "the accessory could not advertise it"}.`;
|
|
91349
|
+
return "Not known yet — this camera’s accessory has not published its recording service in this process. It appears once the accessory is built.";
|
|
91350
|
+
}
|
|
91351
|
+
//#endregion
|
|
91352
|
+
//#region src/hksv/recording-source.ts
|
|
91353
|
+
/** The tallest frame the recording path will hold in its prebuffer. */
|
|
91354
|
+
var MAX_RECORDING_HEIGHT = 1080;
|
|
91355
|
+
/** HKSV takes H.264 only — AAC audio and H.264 video, no negotiation. */
|
|
91356
|
+
var RECORDABLE_CODEC = "h264";
|
|
91357
|
+
/**
|
|
91358
|
+
* Pick the slot the recording child pulls.
|
|
91359
|
+
*
|
|
91360
|
+
* Deliberately NOT `pickPreferredRtspEntry`: that picker resolves the operator's
|
|
91361
|
+
* LIVE preference and, on `auto`, steers by the resolution iOS negotiated for a
|
|
91362
|
+
* live session — neither is a fact about recording, and on 615 it selects `mid`,
|
|
91363
|
+
* a 10 fps slot. Recording has one criterion, applied here and nowhere else:
|
|
91364
|
+
* the largest copyable frame that does not exceed {@link MAX_RECORDING_HEIGHT}.
|
|
91365
|
+
*/
|
|
91366
|
+
function pickRecordingSource(entries, options = {}) {
|
|
91367
|
+
const enabled = entries.filter((e) => e.enabled);
|
|
91368
|
+
if (enabled.length === 0) return {
|
|
91369
|
+
ok: false,
|
|
91370
|
+
refusal: "no-enabled-stream"
|
|
91371
|
+
};
|
|
91372
|
+
const h264 = enabled.filter((e) => normaliseCodec(e.codec) === RECORDABLE_CODEC);
|
|
91373
|
+
const pool = h264.length > 0 ? h264 : options.allowTranscode === true ? enabled : [];
|
|
91374
|
+
if (pool.length === 0) return {
|
|
91375
|
+
ok: false,
|
|
91376
|
+
refusal: "no-h264-stream"
|
|
91377
|
+
};
|
|
91378
|
+
const transcode = h264.length === 0;
|
|
91379
|
+
const sized = pool.filter(hasUsableResolution);
|
|
91380
|
+
if (sized.length === 0) return {
|
|
91381
|
+
ok: false,
|
|
91382
|
+
refusal: "no-resolution"
|
|
91383
|
+
};
|
|
91384
|
+
const withinCeiling = sized.filter((e) => height(e) <= MAX_RECORDING_HEIGHT);
|
|
91385
|
+
const within = withinCeiling.length > 0;
|
|
91386
|
+
const best = [...within ? withinCeiling : sized].sort((a, b) => within ? height(b) - height(a) : height(a) - height(b))[0];
|
|
91387
|
+
if (best === void 0 || best.resolution === void 0) return {
|
|
91388
|
+
ok: false,
|
|
91389
|
+
refusal: "no-resolution"
|
|
91390
|
+
};
|
|
91391
|
+
return {
|
|
91392
|
+
ok: true,
|
|
91393
|
+
source: {
|
|
91394
|
+
brokerId: best.brokerId,
|
|
91395
|
+
profile: best.profile ?? best.brokerId,
|
|
91396
|
+
transcode,
|
|
91397
|
+
url: best.url,
|
|
91398
|
+
mutedUrl: best.mutedUrl,
|
|
91399
|
+
width: best.resolution.width,
|
|
91400
|
+
height: best.resolution.height
|
|
91401
|
+
}
|
|
91402
|
+
};
|
|
91403
|
+
}
|
|
91404
|
+
/** A one-line reason for the log — silence about a withdrawn service reads as a bug. */
|
|
91405
|
+
function refusalReason(refusal) {
|
|
91406
|
+
switch (refusal) {
|
|
91407
|
+
case "no-enabled-stream": return "the camera has no enabled RTSP profile";
|
|
91408
|
+
case "no-h264-stream": return "every enabled profile is H.265 — HKSV takes H.264 only, and a permanent transcode costs 128x a copy";
|
|
91409
|
+
case "no-resolution": return "no enabled profile declares a resolution, so nothing honest could be advertised";
|
|
91410
|
+
}
|
|
91411
|
+
}
|
|
91412
|
+
function height(entry) {
|
|
91413
|
+
return entry.resolution?.height ?? 0;
|
|
91414
|
+
}
|
|
91415
|
+
function hasUsableResolution(entry) {
|
|
91416
|
+
const r = entry.resolution;
|
|
91417
|
+
return r !== void 0 && r.width > 0 && r.height > 0;
|
|
91418
|
+
}
|
|
91419
|
+
/** Publishers spell H.265 four ways; the same normalisation the broker uses. */
|
|
91420
|
+
function normaliseCodec(codec) {
|
|
91421
|
+
return (codec ?? "").toLowerCase().replace(/[.\s-]/g, "");
|
|
91422
|
+
}
|
|
91423
|
+
//#endregion
|
|
91424
|
+
//#region src/hksv/recordability-token.ts
|
|
91425
|
+
/** No slot is recordable. A real answer, and a fingerprint-moving one. */
|
|
91426
|
+
var RECORDABILITY_NONE = "rec:none";
|
|
91427
|
+
/**
|
|
91428
|
+
* The slot HKSV would record from, as a fingerprint token.
|
|
91429
|
+
*
|
|
91430
|
+
* `null` when `entries` is null — the profiles could not be read, which is not
|
|
91431
|
+
* a claim about the camera.
|
|
91432
|
+
*/
|
|
91433
|
+
function recordabilityToken(entries, options = {}) {
|
|
91434
|
+
if (entries === null) return null;
|
|
91435
|
+
const choice = pickRecordingSource(entries, options);
|
|
91436
|
+
return choice.ok ? `rec:${choice.source.profile}${choice.source.transcode ? "+x" : ""}` : RECORDABILITY_NONE;
|
|
91437
|
+
}
|
|
91438
|
+
var TOKEN_SUFFIX = /\|(rec:[^|]*)$/;
|
|
91439
|
+
/**
|
|
91440
|
+
* Attach the recording token to a device-shape fingerprint.
|
|
91441
|
+
*
|
|
91442
|
+
* On an unreadable read the persisted token is carried forward — but only onto
|
|
91443
|
+
* the base it was persisted against. If the device's SHAPE also changed, that
|
|
91444
|
+
* change is a rebuild in its own right and the token has nothing to say about
|
|
91445
|
+
* it; inventing one there would advertise a recording slot nobody read.
|
|
91446
|
+
*/
|
|
91447
|
+
function withRecordabilityToken(input) {
|
|
91448
|
+
if (input.token !== null) return `${input.base}|${input.token}`;
|
|
91449
|
+
const carried = input.persisted?.match(TOKEN_SUFFIX);
|
|
91450
|
+
if (carried === null || carried === void 0) return input.base;
|
|
91451
|
+
return carried.input?.slice(0, carried.index) === input.base ? `${input.base}|${carried[1]}` : input.base;
|
|
91452
|
+
}
|
|
91453
|
+
/**
|
|
91454
|
+
* What this camera could record, as one fingerprint token.
|
|
91455
|
+
*
|
|
91456
|
+
* There used to be an `rec:off` here, for a per-camera switch of ours. That
|
|
91457
|
+
* switch is gone (D589): whether HomeKit RECORDS is HomeKit's own persisted
|
|
91458
|
+
* characteristic, it does not change the accessory's shape, and a rebuild is
|
|
91459
|
+
* about shape. What still belongs here is the CAPABILITY — which slot, and
|
|
91460
|
+
* whether serving it means running an encoder — because those are two
|
|
91461
|
+
* different accessories to build.
|
|
91462
|
+
*/
|
|
91463
|
+
function recordabilityTokenFor(input) {
|
|
91464
|
+
return recordabilityToken(input.entries, { allowTranscode: input.allowTranscode !== false });
|
|
91465
|
+
}
|
|
91466
|
+
//#endregion
|
|
90673
91467
|
//#region src/hksv/videoclips-plane.ts
|
|
90674
91468
|
/**
|
|
90675
91469
|
* The two data-plane routes behind the HomeKit clip source.
|
|
@@ -90932,8 +91726,9 @@ function createHksvClipPlanes(deps) {
|
|
|
90932
91726
|
*
|
|
90933
91727
|
* ## The source EXISTS because of HomeKit, and is not a switch
|
|
90934
91728
|
*
|
|
90935
|
-
* A camera has this source because it is exported to HomeKit
|
|
90936
|
-
*
|
|
91729
|
+
* A camera has this source because it is exported to HomeKit and HomeKit has
|
|
91730
|
+
* not said no to recording it; un-export it, or switch recording off in the
|
|
91731
|
+
* Home app, and the row is gone (D550, D569 § 5, D589).
|
|
90937
91732
|
* There is deliberately no enable control of its own — a knob over somebody
|
|
90938
91733
|
* else's decision is D62's defect. `keepClips` is NOT that gate either: it
|
|
90939
91734
|
* governs the TEE, and the clips already kept remain the truth about this
|
|
@@ -90980,7 +91775,7 @@ function createHksvVideoclipsProvider(deps) {
|
|
|
90980
91775
|
*/
|
|
90981
91776
|
async function measure(deviceId) {
|
|
90982
91777
|
const facts = deps.describeCamera(deviceId);
|
|
90983
|
-
if (!facts.exported ||
|
|
91778
|
+
if (!facts.exported || facts.homekitRecording === false) return null;
|
|
90984
91779
|
const catalog = await deps.readCatalog(deviceId);
|
|
90985
91780
|
return {
|
|
90986
91781
|
availability: availabilityFor(facts, catalog),
|
|
@@ -106335,6 +107130,72 @@ function buildRecordingOptions(input) {
|
|
|
106335
107130
|
};
|
|
106336
107131
|
}
|
|
106337
107132
|
//#endregion
|
|
107133
|
+
//#region src/hksv/recording-invocation.ts
|
|
107134
|
+
/**
|
|
107135
|
+
* The resolution the accessory may advertise, which is the one it can deliver.
|
|
107136
|
+
*
|
|
107137
|
+
* A copy is advertised at its source size whatever that is — there is no
|
|
107138
|
+
* encoder to resize with, and advertising a size we cannot produce is the
|
|
107139
|
+
* "stream that does not match its own advertisement" defect in miniature.
|
|
107140
|
+
* A transcode above the ceiling is fitted down, because with an encoder in the
|
|
107141
|
+
* pipeline the 6.35 MB 4K fragment is a choice rather than a fact, and iOS
|
|
107142
|
+
* renders HKSV clips at 1080p regardless.
|
|
107143
|
+
*/
|
|
107144
|
+
function recordingOutput(source) {
|
|
107145
|
+
if (!source.transcode || source.height <= 1080) return {
|
|
107146
|
+
width: source.width,
|
|
107147
|
+
height: source.height,
|
|
107148
|
+
scaled: false
|
|
107149
|
+
};
|
|
107150
|
+
return {
|
|
107151
|
+
width: Math.max(2, Math.round(source.width * MAX_RECORDING_HEIGHT / source.height / 2) * 2),
|
|
107152
|
+
height: MAX_RECORDING_HEIGHT,
|
|
107153
|
+
scaled: true
|
|
107154
|
+
};
|
|
107155
|
+
}
|
|
107156
|
+
/** The invocation, minus the sink and sidecar the child owns. */
|
|
107157
|
+
function buildRecordingInvocation(input) {
|
|
107158
|
+
const { source } = input;
|
|
107159
|
+
const audio = input.audioActive ? {
|
|
107160
|
+
kind: "encode",
|
|
107161
|
+
codec: "aac",
|
|
107162
|
+
bitrateKbps: 32,
|
|
107163
|
+
sampleRateHz: HKSV_AUDIO_SAMPLE_RATE_HZ,
|
|
107164
|
+
channels: 1
|
|
107165
|
+
} : { kind: "none" };
|
|
107166
|
+
const out = recordingOutput(source);
|
|
107167
|
+
const video = source.transcode ? {
|
|
107168
|
+
kind: "encode",
|
|
107169
|
+
encoder: "libx264",
|
|
107170
|
+
preset: "veryfast",
|
|
107171
|
+
profile: "main",
|
|
107172
|
+
level: "4.0",
|
|
107173
|
+
pixelFormat: "yuv420p",
|
|
107174
|
+
forceKeyFramesSeconds: Math.max(1, Math.round(input.fragmentMs / 1e3)),
|
|
107175
|
+
bf: 0,
|
|
107176
|
+
...out.scaled ? { scale: {
|
|
107177
|
+
mode: "fit",
|
|
107178
|
+
width: out.width,
|
|
107179
|
+
height: out.height
|
|
107180
|
+
} } : {}
|
|
107181
|
+
} : { kind: "copy" };
|
|
107182
|
+
return {
|
|
107183
|
+
logLevel: "error",
|
|
107184
|
+
decodeHwAccel: source.transcode ? input.decodeHwAccel : null,
|
|
107185
|
+
input: {
|
|
107186
|
+
url: input.audioActive ? source.url : source.mutedUrl,
|
|
107187
|
+
rtspTransport: "tcp",
|
|
107188
|
+
...source.transcode && input.decodeInputArgs !== void 0 && input.decodeInputArgs.length > 0 ? { extraArgs: input.decodeInputArgs } : {},
|
|
107189
|
+
analyzeDurationUs: 1e6,
|
|
107190
|
+
probeSizeBytes: 1e6
|
|
107191
|
+
},
|
|
107192
|
+
video,
|
|
107193
|
+
audio,
|
|
107194
|
+
threadCount: 0,
|
|
107195
|
+
outputArgs: []
|
|
107196
|
+
};
|
|
107197
|
+
}
|
|
107198
|
+
//#endregion
|
|
106338
107199
|
//#region src/hksv/fragment-source.ts
|
|
106339
107200
|
/**
|
|
106340
107201
|
* How far back the prebuffer ring reaches.
|
|
@@ -106502,6 +107363,7 @@ var HksvFragmentSource = class {
|
|
|
106502
107363
|
meta: {
|
|
106503
107364
|
brokerId: this.input.source.brokerId,
|
|
106504
107365
|
resolution: `${this.input.source.width}x${this.input.source.height}`,
|
|
107366
|
+
branch: this.input.source.transcode ? "transcode" : "copy",
|
|
106505
107367
|
fragmentMs: this.input.fragmentMs,
|
|
106506
107368
|
audioActive: this.audioActive,
|
|
106507
107369
|
windowMs: PREBUFFER_WINDOW_MS
|
|
@@ -106566,27 +107428,13 @@ var HksvFragmentSource = class {
|
|
|
106566
107428
|
* takes AAC only — which the same measurement priced at 0.4 % of a core.
|
|
106567
107429
|
*/
|
|
106568
107430
|
buildInvocation() {
|
|
106569
|
-
|
|
106570
|
-
|
|
106571
|
-
|
|
106572
|
-
|
|
106573
|
-
|
|
106574
|
-
|
|
106575
|
-
}
|
|
106576
|
-
return {
|
|
106577
|
-
logLevel: "error",
|
|
106578
|
-
decodeHwAccel: null,
|
|
106579
|
-
input: {
|
|
106580
|
-
url: this.audioActive ? this.input.source.url : this.input.source.mutedUrl,
|
|
106581
|
-
rtspTransport: "tcp",
|
|
106582
|
-
analyzeDurationUs: 1e6,
|
|
106583
|
-
probeSizeBytes: 1e6
|
|
106584
|
-
},
|
|
106585
|
-
video: { kind: "copy" },
|
|
106586
|
-
audio,
|
|
106587
|
-
threadCount: 0,
|
|
106588
|
-
outputArgs: []
|
|
106589
|
-
};
|
|
107431
|
+
return buildRecordingInvocation({
|
|
107432
|
+
source: this.input.source,
|
|
107433
|
+
audioActive: this.audioActive,
|
|
107434
|
+
fragmentMs: this.input.fragmentMs,
|
|
107435
|
+
decodeHwAccel: this.input.decodeHwAccel ?? null,
|
|
107436
|
+
...this.input.decodeInputArgs === void 0 ? {} : { decodeInputArgs: this.input.decodeInputArgs }
|
|
107437
|
+
});
|
|
106590
107438
|
}
|
|
106591
107439
|
};
|
|
106592
107440
|
//#endregion
|
|
@@ -106946,74 +107794,6 @@ var HksvRecordingDelegate = class {
|
|
|
106946
107794
|
}
|
|
106947
107795
|
};
|
|
106948
107796
|
//#endregion
|
|
106949
|
-
//#region src/hksv/recording-source.ts
|
|
106950
|
-
/** The tallest frame the recording path will hold in its prebuffer. */
|
|
106951
|
-
var MAX_RECORDING_HEIGHT = 1080;
|
|
106952
|
-
/** HKSV takes H.264 only — AAC audio and H.264 video, no negotiation. */
|
|
106953
|
-
var RECORDABLE_CODEC = "h264";
|
|
106954
|
-
/**
|
|
106955
|
-
* Pick the slot the recording child pulls.
|
|
106956
|
-
*
|
|
106957
|
-
* Deliberately NOT `pickPreferredRtspEntry`: that picker resolves the operator's
|
|
106958
|
-
* LIVE preference and, on `auto`, steers by the resolution iOS negotiated for a
|
|
106959
|
-
* live session — neither is a fact about recording, and on 615 it selects `mid`,
|
|
106960
|
-
* a 10 fps slot. Recording has one criterion, applied here and nowhere else:
|
|
106961
|
-
* the largest copyable frame that does not exceed {@link MAX_RECORDING_HEIGHT}.
|
|
106962
|
-
*/
|
|
106963
|
-
function pickRecordingSource(entries) {
|
|
106964
|
-
const enabled = entries.filter((e) => e.enabled);
|
|
106965
|
-
if (enabled.length === 0) return {
|
|
106966
|
-
ok: false,
|
|
106967
|
-
refusal: "no-enabled-stream"
|
|
106968
|
-
};
|
|
106969
|
-
const h264 = enabled.filter((e) => normaliseCodec(e.codec) === RECORDABLE_CODEC);
|
|
106970
|
-
if (h264.length === 0) return {
|
|
106971
|
-
ok: false,
|
|
106972
|
-
refusal: "no-h264-stream"
|
|
106973
|
-
};
|
|
106974
|
-
const sized = h264.filter(hasUsableResolution);
|
|
106975
|
-
if (sized.length === 0) return {
|
|
106976
|
-
ok: false,
|
|
106977
|
-
refusal: "no-resolution"
|
|
106978
|
-
};
|
|
106979
|
-
const withinCeiling = sized.filter((e) => height(e) <= MAX_RECORDING_HEIGHT);
|
|
106980
|
-
const best = [...withinCeiling.length > 0 ? withinCeiling : sized].sort((a, b) => withinCeiling.length > 0 ? height(b) - height(a) : height(a) - height(b))[0];
|
|
106981
|
-
if (best === void 0 || best.resolution === void 0) return {
|
|
106982
|
-
ok: false,
|
|
106983
|
-
refusal: "no-resolution"
|
|
106984
|
-
};
|
|
106985
|
-
return {
|
|
106986
|
-
ok: true,
|
|
106987
|
-
source: {
|
|
106988
|
-
brokerId: best.brokerId,
|
|
106989
|
-
profile: best.profile ?? best.brokerId,
|
|
106990
|
-
url: best.url,
|
|
106991
|
-
mutedUrl: best.mutedUrl,
|
|
106992
|
-
width: best.resolution.width,
|
|
106993
|
-
height: best.resolution.height
|
|
106994
|
-
}
|
|
106995
|
-
};
|
|
106996
|
-
}
|
|
106997
|
-
/** A one-line reason for the log — silence about a withdrawn service reads as a bug. */
|
|
106998
|
-
function refusalReason(refusal) {
|
|
106999
|
-
switch (refusal) {
|
|
107000
|
-
case "no-enabled-stream": return "the camera has no enabled RTSP profile";
|
|
107001
|
-
case "no-h264-stream": return "every enabled profile is H.265 — HKSV takes H.264 only, and a permanent transcode costs 128x a copy";
|
|
107002
|
-
case "no-resolution": return "no enabled profile declares a resolution, so nothing honest could be advertised";
|
|
107003
|
-
}
|
|
107004
|
-
}
|
|
107005
|
-
function height(entry) {
|
|
107006
|
-
return entry.resolution?.height ?? 0;
|
|
107007
|
-
}
|
|
107008
|
-
function hasUsableResolution(entry) {
|
|
107009
|
-
const r = entry.resolution;
|
|
107010
|
-
return r !== void 0 && r.width > 0 && r.height > 0;
|
|
107011
|
-
}
|
|
107012
|
-
/** Publishers spell H.265 four ways; the same normalisation the broker uses. */
|
|
107013
|
-
function normaliseCodec(codec) {
|
|
107014
|
-
return (codec ?? "").toLowerCase().replace(/[.\s-]/g, "");
|
|
107015
|
-
}
|
|
107016
|
-
//#endregion
|
|
107017
107797
|
//#region src/hksv/build-recording.ts
|
|
107018
107798
|
/**
|
|
107019
107799
|
* Assemble HomeKit Secure Video for one camera — the ADVERTISEMENT and the
|
|
@@ -107065,7 +107845,7 @@ async function buildHksvRecording(input) {
|
|
|
107065
107845
|
note("profiles-unreadable", "cameraStreams.getProfileRtspEntries could not be read");
|
|
107066
107846
|
return null;
|
|
107067
107847
|
}
|
|
107068
|
-
const choice = pickRecordingSource(entries);
|
|
107848
|
+
const choice = pickRecordingSource(entries, { allowTranscode: bctx.options.hapDeviceSettings?.allowTranscode !== false });
|
|
107069
107849
|
if (!choice.ok) {
|
|
107070
107850
|
log.info("export-hap: HKSV withheld — no recordable stream", { meta: {
|
|
107071
107851
|
refusal: choice.refusal,
|
|
@@ -107075,9 +107855,10 @@ async function buildHksvRecording(input) {
|
|
|
107075
107855
|
return null;
|
|
107076
107856
|
}
|
|
107077
107857
|
const source = choice.source;
|
|
107858
|
+
const decodeHwAccel = source.transcode ? await resolveDecodeHwAccel(bctx, log) : null;
|
|
107078
107859
|
const gopMs = await readSourceGopMs(bctx, source.width, source.height);
|
|
107079
|
-
const fragmentLengthMs = deriveFragmentLengthMs(gopMs);
|
|
107080
|
-
if (fragmentLengthMs === null) {
|
|
107860
|
+
const fragmentLengthMs = source.transcode ? HKSV_FRAGMENT_LENGTHS_MS[0] : deriveFragmentLengthMs(gopMs);
|
|
107861
|
+
if (fragmentLengthMs === void 0 || fragmentLengthMs === null) {
|
|
107081
107862
|
log.warn("export-hap: HKSV withheld — the camera key-frame interval is longer than any fragment length we advertise", { meta: {
|
|
107082
107863
|
gopMs,
|
|
107083
107864
|
brokerId: source.brokerId
|
|
@@ -107088,9 +107869,10 @@ async function buildHksvRecording(input) {
|
|
|
107088
107869
|
const parsedProfile = CamProfileSchema.safeParse(source.profile);
|
|
107089
107870
|
const recordedProfile = parsedProfile.success ? parsedProfile.data : null;
|
|
107090
107871
|
const fps = resolveFps(input.fpsByProfile, source.profile);
|
|
107872
|
+
const out = recordingOutput(source);
|
|
107091
107873
|
const options = buildRecordingOptions({
|
|
107092
|
-
width:
|
|
107093
|
-
height:
|
|
107874
|
+
width: out.width,
|
|
107875
|
+
height: out.height,
|
|
107094
107876
|
fps,
|
|
107095
107877
|
fragmentLengthMs
|
|
107096
107878
|
});
|
|
@@ -107100,8 +107882,8 @@ async function buildHksvRecording(input) {
|
|
|
107100
107882
|
logger: log,
|
|
107101
107883
|
deviceId: numericDeviceId,
|
|
107102
107884
|
store: clipStore,
|
|
107103
|
-
width:
|
|
107104
|
-
height:
|
|
107885
|
+
width: out.width,
|
|
107886
|
+
height: out.height,
|
|
107105
107887
|
fragmentMs: fragmentLengthMs,
|
|
107106
107888
|
...recordedProfile === null ? {} : { profile: recordedProfile }
|
|
107107
107889
|
});
|
|
@@ -107120,14 +107902,21 @@ async function buildHksvRecording(input) {
|
|
|
107120
107902
|
spawnFn: node_child_process.spawn,
|
|
107121
107903
|
source,
|
|
107122
107904
|
fragmentMs,
|
|
107123
|
-
audioActive
|
|
107905
|
+
audioActive,
|
|
107906
|
+
decodeHwAccel: decodeHwAccel?.hwaccel ?? null,
|
|
107907
|
+
...decodeHwAccel === null || decodeHwAccel.extraInputArgs.length === 0 ? {} : { decodeInputArgs: decodeHwAccel.extraInputArgs }
|
|
107124
107908
|
})
|
|
107125
107909
|
});
|
|
107126
107910
|
const advertisedResolution = options.video.resolutions[0];
|
|
107127
107911
|
log.info("export-hap: HKSV ADVERTISED — recording is offered for this camera", { meta: {
|
|
107128
107912
|
brokerId: source.brokerId,
|
|
107129
107913
|
profile: source.profile,
|
|
107130
|
-
resolution: `${
|
|
107914
|
+
resolution: `${out.width}x${out.height}`,
|
|
107915
|
+
branch: source.transcode ? "transcode" : "copy",
|
|
107916
|
+
...source.transcode ? {
|
|
107917
|
+
sourceResolution: `${source.width}x${source.height}`,
|
|
107918
|
+
decodeHwAccel: decodeHwAccel?.hwaccel ?? "software"
|
|
107919
|
+
} : {},
|
|
107131
107920
|
measuredFps: fps,
|
|
107132
107921
|
advertisedFps: advertisedResolution?.[2] ?? null,
|
|
107133
107922
|
fragmentLengthMs,
|
|
@@ -107142,6 +107931,27 @@ async function buildHksvRecording(input) {
|
|
|
107142
107931
|
dispose: () => delegate.dispose()
|
|
107143
107932
|
};
|
|
107144
107933
|
}
|
|
107934
|
+
/**
|
|
107935
|
+
* The `-hwaccel` value for a transcoding prebuffer, and the flags that travel
|
|
107936
|
+
* with it.
|
|
107937
|
+
*
|
|
107938
|
+
* Software is a legitimate answer and is always NAMED: a camera that quietly
|
|
107939
|
+
* stopped using the GPU and one that never had it look identical in a CPU
|
|
107940
|
+
* graph, and on this branch the difference is most of a core, permanently.
|
|
107941
|
+
*/
|
|
107942
|
+
async function resolveDecodeHwAccel(bctx, log) {
|
|
107943
|
+
const decision = selectHwDecode({
|
|
107944
|
+
transcode: true,
|
|
107945
|
+
reading: await probeDecoderHwaccel({
|
|
107946
|
+
source: decoderInfoSourceFromContext(bctx.ctx),
|
|
107947
|
+
log,
|
|
107948
|
+
memo: bctx.options.decodeMemos.reading
|
|
107949
|
+
}),
|
|
107950
|
+
platform: process.platform
|
|
107951
|
+
});
|
|
107952
|
+
if (decision.kind === "software") log.warn("export-hap: HKSV will transcode in SOFTWARE — this costs most of a core, permanently", { meta: { reason: decision.reason } });
|
|
107953
|
+
return decision;
|
|
107954
|
+
}
|
|
107145
107955
|
/** `cameraStreams.getProfileRtspEntries`, or `null` when the cap is unreachable. */
|
|
107146
107956
|
async function readProfileEntries(bctx) {
|
|
107147
107957
|
try {
|
|
@@ -108137,13 +108947,12 @@ async function buildCameraAccessory(input) {
|
|
|
108137
108947
|
bctx,
|
|
108138
108948
|
streamingOptions: streams.streamingOptions
|
|
108139
108949
|
}));
|
|
108140
|
-
const recordingEnabled = options.hapDeviceSettings.hksvRecording === true;
|
|
108141
108950
|
let recordingAudioActive = true;
|
|
108142
|
-
const recording =
|
|
108951
|
+
const recording = await buildHksvRecording({
|
|
108143
108952
|
bctx,
|
|
108144
108953
|
fpsByProfile: advertisedVideo.fpsByProfile,
|
|
108145
108954
|
isAudioActive: () => recordingAudioActive
|
|
108146
|
-
})
|
|
108955
|
+
});
|
|
108147
108956
|
const controller = new (isDoorbell ? import_dist.DoorbellController : import_dist.CameraController)({
|
|
108148
108957
|
delegate: streams.delegate,
|
|
108149
108958
|
streamingOptions: streams.streamingOptions,
|
|
@@ -108392,38 +109201,7 @@ function syncStateToJson(map) {
|
|
|
108392
109201
|
* that matters about it: it must resolve to NOT recording, or "off by default"
|
|
108393
109202
|
* is true only for cameras exposed before the flip.
|
|
108394
109203
|
*/
|
|
108395
|
-
var DEFAULT_DEVICE_SETTINGS = {
|
|
108396
|
-
streamPreference: "auto",
|
|
108397
|
-
hksvRecording: false
|
|
108398
|
-
};
|
|
108399
|
-
/**
|
|
108400
|
-
* OFF unless explicitly switched on — operator decision 2026-09-21, reversing
|
|
108401
|
-
* the 2026-08-08 flip:
|
|
108402
|
-
*
|
|
108403
|
-
* > *"il recording deve essere off di default, non deve essere attivo quando
|
|
108404
|
-
* > si esporta una camera su HKSV"*
|
|
108405
|
-
*
|
|
108406
|
-
* What changed is not the cost the earlier record argued about — recording on
|
|
108407
|
-
* the copy branch really is 0.7 % of a core and ~30 MB (D84), and cheap it
|
|
108408
|
-
* remains. What changed is that on-by-default made the switch **say something
|
|
108409
|
-
* the system was not doing**. Measured on 2026-09-21: 592, 587, 618 and 640
|
|
108410
|
-
* all reported HomeKit recording ON while the advertisement was WITHHELD
|
|
108411
|
-
* (`no-enabled-stream` — no enabled RTSP profile), so HomeKit never recorded
|
|
108412
|
-
* them and the tee had nothing to keep. The operator was being told four
|
|
108413
|
-
* cameras were recording because nobody had turned them off.
|
|
108414
|
-
*
|
|
108415
|
-
* Exposing a camera to HomeKit is a decision about EXPOSURE. Recording is a
|
|
108416
|
-
* second decision and now has to be made.
|
|
108417
|
-
*
|
|
108418
|
-
* ABSENT resolves OFF — the load-bearing case, for the same reason it was
|
|
108419
|
-
* before and with the opposite answer: a camera whose settings predate the
|
|
108420
|
-
* field, or that was exposed before today, was never asked about. Every read
|
|
108421
|
-
* goes through this one resolver (`=== true`), never a scattered `!== false`,
|
|
108422
|
-
* because those two disagree about exactly that case.
|
|
108423
|
-
*/
|
|
108424
|
-
function resolveHksvRecording(settings) {
|
|
108425
|
-
return settings?.hksvRecording === true;
|
|
108426
|
-
}
|
|
109204
|
+
var DEFAULT_DEVICE_SETTINGS = { streamPreference: "auto" };
|
|
108427
109205
|
/**
|
|
108428
109206
|
* Whether this camera offers Apple's NEW camera service alongside the classic
|
|
108429
109207
|
* one — `camera-multi-tier-rtp-stream-management` (0x8031), where HEVC and 4K
|
|
@@ -108466,11 +109244,11 @@ var EXPORT_HAP_ADDON_ID = "export-hap";
|
|
|
108466
109244
|
* stays and says the copies are off, which is D62's other half: an off switch
|
|
108467
109245
|
* is REPORTED off, never made to look like a broken camera.
|
|
108468
109246
|
*/
|
|
108469
|
-
function describeHksvCamera(entry, lastBuild) {
|
|
109247
|
+
function describeHksvCamera(entry, lastBuild, homekitRecording) {
|
|
108470
109248
|
const isCamera = entry !== null && entry.mapperKind === "camera";
|
|
108471
109249
|
return {
|
|
108472
109250
|
exported: isCamera,
|
|
108473
|
-
|
|
109251
|
+
homekitRecording: isCamera ? homekitRecording : null,
|
|
108474
109252
|
keepingClips: isCamera && resolveKeepHomekitClips(entry.settings),
|
|
108475
109253
|
lastBuild
|
|
108476
109254
|
};
|
|
@@ -108714,7 +109492,7 @@ var ExportHapAddon = class extends BaseAddon {
|
|
|
108714
109492
|
const clipsProvider = createHksvVideoclipsProvider({
|
|
108715
109493
|
logger: this.ctx.logger.child("hksv-clips"),
|
|
108716
109494
|
addonId: EXPORT_HAP_ADDON_ID,
|
|
108717
|
-
describeCamera: (deviceId) => describeHksvCamera(this.findEntry(deviceId), this.hksvBuilds.lastFor(deviceId)),
|
|
109495
|
+
describeCamera: (deviceId) => describeHksvCamera(this.findEntry(deviceId), this.hksvBuilds.lastFor(deviceId), readHomekitRecordingActive(this.exposed.get(String(deviceId))?.accessories ?? [])),
|
|
108718
109496
|
readCatalog: async (deviceId) => await this.hksvClipStore?.listCatalog(deviceId) ?? { kind: "no-root" },
|
|
108719
109497
|
locationRefusal: () => this.hksvClipLocation?.lastRefusal ?? null,
|
|
108720
109498
|
mediaUrl: (deviceId, stem) => this.hksvClipUrl("media", deviceId, stem),
|
|
@@ -108870,7 +109648,6 @@ var ExportHapAddon = class extends BaseAddon {
|
|
|
108870
109648
|
},
|
|
108871
109649
|
hapDeviceSettings: {
|
|
108872
109650
|
streamPreference: entrySettings.streamPreference ?? "auto",
|
|
108873
|
-
hksvRecording: resolveHksvRecording(entrySettings),
|
|
108874
109651
|
keepHomekitClips: resolveKeepHomekitClips(entrySettings),
|
|
108875
109652
|
multiTierService: resolveMultiTierService(entrySettings),
|
|
108876
109653
|
allowTranscode: entrySettings.allowTranscode !== false
|
|
@@ -108951,15 +109728,40 @@ var ExportHapAddon = class extends BaseAddon {
|
|
|
108951
109728
|
features: device.features
|
|
108952
109729
|
});
|
|
108953
109730
|
const persisted = syncStateFromJson(this.config.exportSyncState).get(deviceId)?.fingerprint;
|
|
109731
|
+
const withToken = withRecordabilityToken({
|
|
109732
|
+
base: fresh,
|
|
109733
|
+
token: await this.readRecordabilityToken(deviceId, device.type),
|
|
109734
|
+
persisted
|
|
109735
|
+
});
|
|
108954
109736
|
return resolveExportFingerprint({
|
|
108955
109737
|
ready: device.probed ?? false,
|
|
108956
|
-
fresh,
|
|
109738
|
+
fresh: withToken,
|
|
108957
109739
|
persisted
|
|
108958
109740
|
});
|
|
108959
109741
|
} catch {
|
|
108960
109742
|
return null;
|
|
108961
109743
|
}
|
|
108962
109744
|
}
|
|
109745
|
+
/**
|
|
109746
|
+
* The slot HKSV would record this camera from, for the fingerprint.
|
|
109747
|
+
*
|
|
109748
|
+
* `null` — do not move the fingerprint — for anything that is not a camera
|
|
109749
|
+
* (a switch has no recording decision, and stamping a constant on it would
|
|
109750
|
+
* republish every non-camera accessory once for nothing) and for a camera
|
|
109751
|
+
* whose profiles could not be read right now.
|
|
109752
|
+
*/
|
|
109753
|
+
async readRecordabilityToken(deviceId, type) {
|
|
109754
|
+
if (pickMapperKind(type) !== "camera") return null;
|
|
109755
|
+
try {
|
|
109756
|
+
const entries = await (await this.ctx.fetchDevice(deviceId)).cameraStreams?.getProfileRtspEntries({});
|
|
109757
|
+
return recordabilityTokenFor({
|
|
109758
|
+
allowTranscode: this.findEntry(deviceId)?.settings?.allowTranscode !== false,
|
|
109759
|
+
entries: entries ?? null
|
|
109760
|
+
});
|
|
109761
|
+
} catch {
|
|
109762
|
+
return null;
|
|
109763
|
+
}
|
|
109764
|
+
}
|
|
108963
109765
|
/** Persist a device's current export fingerprint into `exportSyncState`
|
|
108964
109766
|
* (best-effort; called after a successful attach). */
|
|
108965
109767
|
async persistFingerprint(deviceId, fingerprint) {
|
|
@@ -109225,7 +110027,6 @@ var ExportHapAddon = class extends BaseAddon {
|
|
|
109225
110027
|
const enabled = entry !== null;
|
|
109226
110028
|
const enabledKey = `hap:${deviceId}:enabled`;
|
|
109227
110029
|
const streamPreferenceKey = `hap:${deviceId}:streamPreference`;
|
|
109228
|
-
const hksvKey = `hap:${deviceId}:hksvRecording`;
|
|
109229
110030
|
const multiTierKey = `hap:${deviceId}:multiTierService`;
|
|
109230
110031
|
const useBridgeKey = `hap:${deviceId}:useBridge`;
|
|
109231
110032
|
const allowTranscodeKey = `hap:${deviceId}:allowTranscode`;
|
|
@@ -109276,17 +110077,14 @@ var ExportHapAddon = class extends BaseAddon {
|
|
|
109276
110077
|
immediate: true
|
|
109277
110078
|
},
|
|
109278
110079
|
{
|
|
109279
|
-
type: "
|
|
109280
|
-
key:
|
|
110080
|
+
type: "info",
|
|
110081
|
+
key: `hap:${deviceId}:hksvRecordingStatus`,
|
|
109281
110082
|
label: "HomeKit recording (Secure Video)",
|
|
109282
|
-
|
|
109283
|
-
style: "switch",
|
|
109284
|
-
value: resolveHksvRecording(settings),
|
|
110083
|
+
content: describeHomekitRecording(readHomekitRecordingActive(this.exposed.get(String(deviceId))?.accessories ?? []), this.hksvBuilds.lastFor(deviceId)),
|
|
109285
110084
|
showWhen: {
|
|
109286
110085
|
field: enabledKey,
|
|
109287
110086
|
equals: true
|
|
109288
|
-
}
|
|
109289
|
-
immediate: true
|
|
110087
|
+
}
|
|
109290
110088
|
},
|
|
109291
110089
|
{
|
|
109292
110090
|
type: "boolean",
|
|
@@ -109309,7 +110107,7 @@ var ExportHapAddon = class extends BaseAddon {
|
|
|
109309
110107
|
style: "switch",
|
|
109310
110108
|
value: resolveKeepHomekitClips(settings),
|
|
109311
110109
|
showWhen: {
|
|
109312
|
-
field:
|
|
110110
|
+
field: enabledKey,
|
|
109313
110111
|
equals: true
|
|
109314
110112
|
},
|
|
109315
110113
|
immediate: true
|
|
@@ -109409,7 +110207,6 @@ var ExportHapAddon = class extends BaseAddon {
|
|
|
109409
110207
|
const wasEnabled = this.exposed.has(deviceIdStr);
|
|
109410
110208
|
const enabledKey = `hap:${deviceId}:enabled`;
|
|
109411
110209
|
const streamPreferenceKey = `hap:${deviceId}:streamPreference`;
|
|
109412
|
-
const hksvKey = `hap:${deviceId}:hksvRecording`;
|
|
109413
110210
|
const useBridgeKey = `hap:${deviceId}:useBridge`;
|
|
109414
110211
|
const allowTranscodeKey = `hap:${deviceId}:allowTranscode`;
|
|
109415
110212
|
const multiTierKey = `hap:${deviceId}:multiTierService`;
|
|
@@ -109418,7 +110215,6 @@ var ExportHapAddon = class extends BaseAddon {
|
|
|
109418
110215
|
const enabledValue = enabledKey in patch ? Boolean(patch[enabledKey]) : wasEnabled;
|
|
109419
110216
|
const streamPreferenceRaw = streamPreferenceKey in patch ? patch[streamPreferenceKey] : current?.settings?.streamPreference;
|
|
109420
110217
|
const streamPreference = typeof streamPreferenceRaw === "string" && streamPreferenceRaw.trim().length > 0 ? streamPreferenceRaw : "auto";
|
|
109421
|
-
const hksvRecording = hksvKey in patch ? Boolean(patch[hksvKey]) : resolveHksvRecording(current?.settings);
|
|
109422
110218
|
const useBridge = useBridgeKey in patch ? Boolean(patch[useBridgeKey]) : current?.settings?.useBridge !== false;
|
|
109423
110219
|
const allowTranscode = allowTranscodeKey in patch ? Boolean(patch[allowTranscodeKey]) : current?.settings?.allowTranscode !== false;
|
|
109424
110220
|
const multiTierService = multiTierKey in patch ? Boolean(patch[multiTierKey]) : resolveMultiTierService(current?.settings);
|
|
@@ -109430,7 +110226,6 @@ var ExportHapAddon = class extends BaseAddon {
|
|
|
109430
110226
|
const nextSettings = {
|
|
109431
110227
|
...current?.settings ?? DEFAULT_DEVICE_SETTINGS,
|
|
109432
110228
|
streamPreference,
|
|
109433
|
-
hksvRecording,
|
|
109434
110229
|
useBridge,
|
|
109435
110230
|
allowTranscode,
|
|
109436
110231
|
multiTierService,
|
|
@@ -109447,7 +110242,6 @@ var ExportHapAddon = class extends BaseAddon {
|
|
|
109447
110242
|
return { success: true };
|
|
109448
110243
|
}
|
|
109449
110244
|
const currentPref = current?.settings?.streamPreference ?? "auto";
|
|
109450
|
-
const currentHksv = resolveHksvRecording(current?.settings);
|
|
109451
110245
|
const currentKeepClips = resolveKeepHomekitClips(current?.settings);
|
|
109452
110246
|
const mapperKind = current?.mapperKind ?? "generic";
|
|
109453
110247
|
const wasBridged = shouldBridge({
|
|
@@ -109459,16 +110253,12 @@ var ExportHapAddon = class extends BaseAddon {
|
|
|
109459
110253
|
useBridge
|
|
109460
110254
|
});
|
|
109461
110255
|
await this.updateEntrySettings(deviceIdStr, nextSettings);
|
|
109462
|
-
if (currentPref !== streamPreference ||
|
|
110256
|
+
if (currentPref !== streamPreference || currentKeepClips !== keepClips || wasBridged !== willBridge) {
|
|
109463
110257
|
log.info("export-hap: per-camera export settings changed — refreshing accessory", { meta: {
|
|
109464
110258
|
streamPreference: {
|
|
109465
110259
|
from: currentPref,
|
|
109466
110260
|
to: streamPreference
|
|
109467
110261
|
},
|
|
109468
|
-
hksvRecording: {
|
|
109469
|
-
from: currentHksv,
|
|
109470
|
-
to: hksvRecording
|
|
109471
|
-
},
|
|
109472
110262
|
keepClips: {
|
|
109473
110263
|
from: currentKeepClips,
|
|
109474
110264
|
to: keepClips
|
|
@@ -109565,7 +110355,6 @@ exports.describeHksvCamera = describeHksvCamera;
|
|
|
109565
110355
|
exports.initHapStorage = initHapStorage;
|
|
109566
110356
|
exports.publishStandalone = publishStandalone;
|
|
109567
110357
|
exports.resolveClipRetentionDays = resolveClipRetentionDays;
|
|
109568
|
-
exports.resolveHksvRecording = resolveHksvRecording;
|
|
109569
110358
|
exports.resolveKeepHomekitClips = resolveKeepHomekitClips;
|
|
109570
110359
|
exports.resolveMultiTierService = resolveMultiTierService;
|
|
109571
110360
|
exports.unpublishAccessory = unpublishAccessory;
|