@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
|
@@ -25460,6 +25460,23 @@ var videoclipsCapability = {
|
|
|
25460
25460
|
deviceId: number(),
|
|
25461
25461
|
clipId: string().min(1),
|
|
25462
25462
|
/**
|
|
25463
|
+
* WHICH provider holds the bytes — the `addonId` a
|
|
25464
|
+
* {@link ClipSourceSchema} row carries. **Required**, for the reason
|
|
25465
|
+
* `listClips` states one method above and for a second one this method
|
|
25466
|
+
* learned the hard way.
|
|
25467
|
+
*
|
|
25468
|
+
* The caller is the stream broker, and the broker lives in
|
|
25469
|
+
* `addon-pipeline` — the same addon that registers the RECORDER's
|
|
25470
|
+
* videoclips provider. With no provider named, the in-process
|
|
25471
|
+
* resolution handed it its own sibling, which implements this method
|
|
25472
|
+
* solely to explain that an analytics visit has no file behind it. So
|
|
25473
|
+
* every onboard clip answered with that sentence, a flash of video and
|
|
25474
|
+
* nothing more, while the SAME call from outside the addon reached the
|
|
25475
|
+
* right provider and returned the bytes (measured on 3628,
|
|
25476
|
+
* 2026-09-21).
|
|
25477
|
+
*/
|
|
25478
|
+
provider: string().min(1),
|
|
25479
|
+
/**
|
|
25463
25480
|
* Which twin to fetch, on the mapping D549 15 already fixed:
|
|
25464
25481
|
* `low | mid` → the sub file, `high` → the main twin. `auto` is not
|
|
25465
25482
|
* accepted here for the same reason it is not accepted by
|
|
@@ -31223,7 +31240,7 @@ method(object({
|
|
|
31223
31240
|
auth: "admin"
|
|
31224
31241
|
}), method(object({ deviceId: number() }), RecordingConfigSchema, {
|
|
31225
31242
|
kind: "query",
|
|
31226
|
-
auth: "
|
|
31243
|
+
auth: "protected"
|
|
31227
31244
|
}), method(object({
|
|
31228
31245
|
deviceId: number(),
|
|
31229
31246
|
profile: string(),
|
|
@@ -33470,6 +33487,12 @@ DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeate
|
|
|
33470
33487
|
new Set(Object.values(DeviceType));
|
|
33471
33488
|
DeviceFeature.BatteryOperated;
|
|
33472
33489
|
Object.freeze({
|
|
33490
|
+
"accessories.getStatus": {
|
|
33491
|
+
capName: "accessories",
|
|
33492
|
+
capScope: "device",
|
|
33493
|
+
addonId: null,
|
|
33494
|
+
access: "view"
|
|
33495
|
+
},
|
|
33473
33496
|
"accessories.setChildHidden": {
|
|
33474
33497
|
capName: "accessories",
|
|
33475
33498
|
capScope: "device",
|
|
@@ -33752,6 +33775,12 @@ Object.freeze({
|
|
|
33752
33775
|
addonId: null,
|
|
33753
33776
|
access: "view"
|
|
33754
33777
|
},
|
|
33778
|
+
"airQualitySensor.getStatus": {
|
|
33779
|
+
capName: "air-quality-sensor",
|
|
33780
|
+
capScope: "device",
|
|
33781
|
+
addonId: null,
|
|
33782
|
+
access: "view"
|
|
33783
|
+
},
|
|
33755
33784
|
"alarmPanel.arm": {
|
|
33756
33785
|
capName: "alarm-panel",
|
|
33757
33786
|
capScope: "device",
|
|
@@ -33764,6 +33793,12 @@ Object.freeze({
|
|
|
33764
33793
|
addonId: null,
|
|
33765
33794
|
access: "create"
|
|
33766
33795
|
},
|
|
33796
|
+
"alarmPanel.getStatus": {
|
|
33797
|
+
capName: "alarm-panel",
|
|
33798
|
+
capScope: "device",
|
|
33799
|
+
addonId: null,
|
|
33800
|
+
access: "view"
|
|
33801
|
+
},
|
|
33767
33802
|
"alarmPanel.trigger": {
|
|
33768
33803
|
capName: "alarm-panel",
|
|
33769
33804
|
capScope: "device",
|
|
@@ -33812,6 +33847,30 @@ Object.freeze({
|
|
|
33812
33847
|
addonId: null,
|
|
33813
33848
|
access: "create"
|
|
33814
33849
|
},
|
|
33850
|
+
"ambientLightSensor.getStatus": {
|
|
33851
|
+
capName: "ambient-light-sensor",
|
|
33852
|
+
capScope: "device",
|
|
33853
|
+
addonId: null,
|
|
33854
|
+
access: "view"
|
|
33855
|
+
},
|
|
33856
|
+
"audioAnalysis.applyDeviceSettingsPatch": {
|
|
33857
|
+
capName: "audio-analysis",
|
|
33858
|
+
capScope: "device",
|
|
33859
|
+
addonId: null,
|
|
33860
|
+
access: "create"
|
|
33861
|
+
},
|
|
33862
|
+
"audioAnalysis.getDeviceLiveContribution": {
|
|
33863
|
+
capName: "audio-analysis",
|
|
33864
|
+
capScope: "device",
|
|
33865
|
+
addonId: null,
|
|
33866
|
+
access: "view"
|
|
33867
|
+
},
|
|
33868
|
+
"audioAnalysis.getDeviceSettingsContribution": {
|
|
33869
|
+
capName: "audio-analysis",
|
|
33870
|
+
capScope: "device",
|
|
33871
|
+
addonId: null,
|
|
33872
|
+
access: "view"
|
|
33873
|
+
},
|
|
33815
33874
|
"audioAnalysis.resolveDeviceSettings": {
|
|
33816
33875
|
capName: "audio-analysis",
|
|
33817
33876
|
capScope: "device",
|
|
@@ -33974,6 +34033,12 @@ Object.freeze({
|
|
|
33974
34033
|
addonId: null,
|
|
33975
34034
|
access: "create"
|
|
33976
34035
|
},
|
|
34036
|
+
"automationControl.getStatus": {
|
|
34037
|
+
capName: "automation-control",
|
|
34038
|
+
capScope: "device",
|
|
34039
|
+
addonId: null,
|
|
34040
|
+
access: "view"
|
|
34041
|
+
},
|
|
33977
34042
|
"automationControl.trigger": {
|
|
33978
34043
|
capName: "automation-control",
|
|
33979
34044
|
capScope: "device",
|
|
@@ -34070,12 +34135,30 @@ Object.freeze({
|
|
|
34070
34135
|
addonId: null,
|
|
34071
34136
|
access: "create"
|
|
34072
34137
|
},
|
|
34138
|
+
"battery.getStatus": {
|
|
34139
|
+
capName: "battery",
|
|
34140
|
+
capScope: "device",
|
|
34141
|
+
addonId: null,
|
|
34142
|
+
access: "view"
|
|
34143
|
+
},
|
|
34073
34144
|
"battery.wakeForStream": {
|
|
34074
34145
|
capName: "battery",
|
|
34075
34146
|
capScope: "device",
|
|
34076
34147
|
addonId: null,
|
|
34077
34148
|
access: "create"
|
|
34078
34149
|
},
|
|
34150
|
+
"binary.getStatus": {
|
|
34151
|
+
capName: "binary",
|
|
34152
|
+
capScope: "device",
|
|
34153
|
+
addonId: null,
|
|
34154
|
+
access: "view"
|
|
34155
|
+
},
|
|
34156
|
+
"brightness.getStatus": {
|
|
34157
|
+
capName: "brightness",
|
|
34158
|
+
capScope: "device",
|
|
34159
|
+
addonId: null,
|
|
34160
|
+
access: "view"
|
|
34161
|
+
},
|
|
34079
34162
|
"brightness.setBrightness": {
|
|
34080
34163
|
capName: "brightness",
|
|
34081
34164
|
capScope: "device",
|
|
@@ -34190,6 +34273,30 @@ Object.freeze({
|
|
|
34190
34273
|
addonId: null,
|
|
34191
34274
|
access: "view"
|
|
34192
34275
|
},
|
|
34276
|
+
"cameraCredentials.getStatus": {
|
|
34277
|
+
capName: "camera-credentials",
|
|
34278
|
+
capScope: "device",
|
|
34279
|
+
addonId: null,
|
|
34280
|
+
access: "view"
|
|
34281
|
+
},
|
|
34282
|
+
"cameraGridLayout.applyDeviceSettingsPatch": {
|
|
34283
|
+
capName: "camera-grid-layout",
|
|
34284
|
+
capScope: "device",
|
|
34285
|
+
addonId: null,
|
|
34286
|
+
access: "create"
|
|
34287
|
+
},
|
|
34288
|
+
"cameraGridLayout.getDeviceLiveContribution": {
|
|
34289
|
+
capName: "camera-grid-layout",
|
|
34290
|
+
capScope: "device",
|
|
34291
|
+
addonId: null,
|
|
34292
|
+
access: "view"
|
|
34293
|
+
},
|
|
34294
|
+
"cameraGridLayout.getDeviceSettingsContribution": {
|
|
34295
|
+
capName: "camera-grid-layout",
|
|
34296
|
+
capScope: "device",
|
|
34297
|
+
addonId: null,
|
|
34298
|
+
access: "view"
|
|
34299
|
+
},
|
|
34193
34300
|
"cameraGridLayout.getLayout": {
|
|
34194
34301
|
capName: "camera-grid-layout",
|
|
34195
34302
|
capScope: "device",
|
|
@@ -34202,6 +34309,24 @@ Object.freeze({
|
|
|
34202
34309
|
addonId: null,
|
|
34203
34310
|
access: "create"
|
|
34204
34311
|
},
|
|
34312
|
+
"cameraPipelineConfig.applyDeviceSettingsPatch": {
|
|
34313
|
+
capName: "camera-pipeline-config",
|
|
34314
|
+
capScope: "device",
|
|
34315
|
+
addonId: null,
|
|
34316
|
+
access: "create"
|
|
34317
|
+
},
|
|
34318
|
+
"cameraPipelineConfig.getDeviceLiveContribution": {
|
|
34319
|
+
capName: "camera-pipeline-config",
|
|
34320
|
+
capScope: "device",
|
|
34321
|
+
addonId: null,
|
|
34322
|
+
access: "view"
|
|
34323
|
+
},
|
|
34324
|
+
"cameraPipelineConfig.getDeviceSettingsContribution": {
|
|
34325
|
+
capName: "camera-pipeline-config",
|
|
34326
|
+
capScope: "device",
|
|
34327
|
+
addonId: null,
|
|
34328
|
+
access: "view"
|
|
34329
|
+
},
|
|
34205
34330
|
"cameraStreams.getBrokerStreams": {
|
|
34206
34331
|
capName: "camera-streams",
|
|
34207
34332
|
capScope: "device",
|
|
@@ -34232,6 +34357,18 @@ Object.freeze({
|
|
|
34232
34357
|
addonId: null,
|
|
34233
34358
|
access: "view"
|
|
34234
34359
|
},
|
|
34360
|
+
"carbonMonoxide.getStatus": {
|
|
34361
|
+
capName: "carbon-monoxide",
|
|
34362
|
+
capScope: "device",
|
|
34363
|
+
addonId: null,
|
|
34364
|
+
access: "view"
|
|
34365
|
+
},
|
|
34366
|
+
"climateControl.getStatus": {
|
|
34367
|
+
capName: "climate-control",
|
|
34368
|
+
capScope: "device",
|
|
34369
|
+
addonId: null,
|
|
34370
|
+
access: "view"
|
|
34371
|
+
},
|
|
34235
34372
|
"climateControl.setFanMode": {
|
|
34236
34373
|
capName: "climate-control",
|
|
34237
34374
|
capScope: "device",
|
|
@@ -34280,6 +34417,12 @@ Object.freeze({
|
|
|
34280
34417
|
addonId: null,
|
|
34281
34418
|
access: "create"
|
|
34282
34419
|
},
|
|
34420
|
+
"color.getStatus": {
|
|
34421
|
+
capName: "color",
|
|
34422
|
+
capScope: "device",
|
|
34423
|
+
addonId: null,
|
|
34424
|
+
access: "view"
|
|
34425
|
+
},
|
|
34283
34426
|
"color.setColor": {
|
|
34284
34427
|
capName: "color",
|
|
34285
34428
|
capScope: "device",
|
|
@@ -34298,12 +34441,36 @@ Object.freeze({
|
|
|
34298
34441
|
addonId: null,
|
|
34299
34442
|
access: "create"
|
|
34300
34443
|
},
|
|
34444
|
+
"connectivity.getStatus": {
|
|
34445
|
+
capName: "connectivity",
|
|
34446
|
+
capScope: "device",
|
|
34447
|
+
addonId: null,
|
|
34448
|
+
access: "view"
|
|
34449
|
+
},
|
|
34450
|
+
"consumables.getStatus": {
|
|
34451
|
+
capName: "consumables",
|
|
34452
|
+
capScope: "device",
|
|
34453
|
+
addonId: null,
|
|
34454
|
+
access: "view"
|
|
34455
|
+
},
|
|
34301
34456
|
"consumables.reset": {
|
|
34302
34457
|
capName: "consumables",
|
|
34303
34458
|
capScope: "device",
|
|
34304
34459
|
addonId: null,
|
|
34305
34460
|
access: "delete"
|
|
34306
34461
|
},
|
|
34462
|
+
"contact.getStatus": {
|
|
34463
|
+
capName: "contact",
|
|
34464
|
+
capScope: "device",
|
|
34465
|
+
addonId: null,
|
|
34466
|
+
access: "view"
|
|
34467
|
+
},
|
|
34468
|
+
"control.getStatus": {
|
|
34469
|
+
capName: "control",
|
|
34470
|
+
capScope: "device",
|
|
34471
|
+
addonId: null,
|
|
34472
|
+
access: "view"
|
|
34473
|
+
},
|
|
34307
34474
|
"control.setValue": {
|
|
34308
34475
|
capName: "control",
|
|
34309
34476
|
capScope: "device",
|
|
@@ -34370,6 +34537,12 @@ Object.freeze({
|
|
|
34370
34537
|
addonId: null,
|
|
34371
34538
|
access: "create"
|
|
34372
34539
|
},
|
|
34540
|
+
"cover.getStatus": {
|
|
34541
|
+
capName: "cover",
|
|
34542
|
+
capScope: "device",
|
|
34543
|
+
addonId: null,
|
|
34544
|
+
access: "view"
|
|
34545
|
+
},
|
|
34373
34546
|
"cover.open": {
|
|
34374
34547
|
capName: "cover",
|
|
34375
34548
|
capScope: "device",
|
|
@@ -34502,6 +34675,12 @@ Object.freeze({
|
|
|
34502
34675
|
addonId: null,
|
|
34503
34676
|
access: "view"
|
|
34504
34677
|
},
|
|
34678
|
+
"dayNight.getStatus": {
|
|
34679
|
+
capName: "day-night",
|
|
34680
|
+
capScope: "device",
|
|
34681
|
+
addonId: null,
|
|
34682
|
+
access: "view"
|
|
34683
|
+
},
|
|
34505
34684
|
"dayNight.setSettings": {
|
|
34506
34685
|
capName: "day-night",
|
|
34507
34686
|
capScope: "device",
|
|
@@ -34592,6 +34771,24 @@ Object.freeze({
|
|
|
34592
34771
|
addonId: null,
|
|
34593
34772
|
access: "view"
|
|
34594
34773
|
},
|
|
34774
|
+
"detectionPipeline.applyDeviceSettingsPatch": {
|
|
34775
|
+
capName: "detection-pipeline",
|
|
34776
|
+
capScope: "device",
|
|
34777
|
+
addonId: null,
|
|
34778
|
+
access: "create"
|
|
34779
|
+
},
|
|
34780
|
+
"detectionPipeline.getDeviceLiveContribution": {
|
|
34781
|
+
capName: "detection-pipeline",
|
|
34782
|
+
capScope: "device",
|
|
34783
|
+
addonId: null,
|
|
34784
|
+
access: "view"
|
|
34785
|
+
},
|
|
34786
|
+
"detectionPipeline.getDeviceSettingsContribution": {
|
|
34787
|
+
capName: "detection-pipeline",
|
|
34788
|
+
capScope: "device",
|
|
34789
|
+
addonId: null,
|
|
34790
|
+
access: "view"
|
|
34791
|
+
},
|
|
34595
34792
|
"deviceAdoption.adopt": {
|
|
34596
34793
|
capName: "device-adoption",
|
|
34597
34794
|
capScope: "system",
|
|
@@ -34604,6 +34801,12 @@ Object.freeze({
|
|
|
34604
34801
|
addonId: null,
|
|
34605
34802
|
access: "view"
|
|
34606
34803
|
},
|
|
34804
|
+
"deviceAdoption.getStatus": {
|
|
34805
|
+
capName: "device-adoption",
|
|
34806
|
+
capScope: "system",
|
|
34807
|
+
addonId: null,
|
|
34808
|
+
access: "view"
|
|
34809
|
+
},
|
|
34607
34810
|
"deviceAdoption.listCandidateFilters": {
|
|
34608
34811
|
capName: "device-adoption",
|
|
34609
34812
|
capScope: "system",
|
|
@@ -34640,6 +34843,12 @@ Object.freeze({
|
|
|
34640
34843
|
addonId: null,
|
|
34641
34844
|
access: "create"
|
|
34642
34845
|
},
|
|
34846
|
+
"deviceDiscovery.getStatus": {
|
|
34847
|
+
capName: "device-discovery",
|
|
34848
|
+
capScope: "device",
|
|
34849
|
+
addonId: null,
|
|
34850
|
+
access: "view"
|
|
34851
|
+
},
|
|
34643
34852
|
"deviceDiscovery.listDiscovered": {
|
|
34644
34853
|
capName: "device-discovery",
|
|
34645
34854
|
capScope: "device",
|
|
@@ -34658,12 +34867,30 @@ Object.freeze({
|
|
|
34658
34867
|
addonId: null,
|
|
34659
34868
|
access: "create"
|
|
34660
34869
|
},
|
|
34870
|
+
"deviceExport.applyDeviceSettingsPatch": {
|
|
34871
|
+
capName: "device-export",
|
|
34872
|
+
capScope: "system",
|
|
34873
|
+
addonId: null,
|
|
34874
|
+
access: "create"
|
|
34875
|
+
},
|
|
34661
34876
|
"deviceExport.exposeDevice": {
|
|
34662
34877
|
capName: "device-export",
|
|
34663
34878
|
capScope: "system",
|
|
34664
34879
|
addonId: null,
|
|
34665
34880
|
access: "create"
|
|
34666
34881
|
},
|
|
34882
|
+
"deviceExport.getDeviceLiveContribution": {
|
|
34883
|
+
capName: "device-export",
|
|
34884
|
+
capScope: "system",
|
|
34885
|
+
addonId: null,
|
|
34886
|
+
access: "view"
|
|
34887
|
+
},
|
|
34888
|
+
"deviceExport.getDeviceSettingsContribution": {
|
|
34889
|
+
capName: "device-export",
|
|
34890
|
+
capScope: "system",
|
|
34891
|
+
addonId: null,
|
|
34892
|
+
access: "view"
|
|
34893
|
+
},
|
|
34667
34894
|
"deviceExport.getStatus": {
|
|
34668
34895
|
capName: "device-export",
|
|
34669
34896
|
capScope: "system",
|
|
@@ -34760,6 +34987,12 @@ Object.freeze({
|
|
|
34760
34987
|
addonId: null,
|
|
34761
34988
|
access: "create"
|
|
34762
34989
|
},
|
|
34990
|
+
"deviceManager.applyDeviceSettingsPatch": {
|
|
34991
|
+
capName: "device-manager",
|
|
34992
|
+
capScope: "system",
|
|
34993
|
+
addonId: null,
|
|
34994
|
+
access: "create"
|
|
34995
|
+
},
|
|
34763
34996
|
"deviceManager.applyInitialMeta": {
|
|
34764
34997
|
capName: "device-manager",
|
|
34765
34998
|
capScope: "system",
|
|
@@ -34862,6 +35095,12 @@ Object.freeze({
|
|
|
34862
35095
|
addonId: null,
|
|
34863
35096
|
access: "view"
|
|
34864
35097
|
},
|
|
35098
|
+
"deviceManager.getDeviceLiveContribution": {
|
|
35099
|
+
capName: "device-manager",
|
|
35100
|
+
capScope: "system",
|
|
35101
|
+
addonId: null,
|
|
35102
|
+
access: "view"
|
|
35103
|
+
},
|
|
34865
35104
|
"deviceManager.getDeviceLiveInfoAggregate": {
|
|
34866
35105
|
capName: "device-manager",
|
|
34867
35106
|
capScope: "system",
|
|
@@ -34874,6 +35113,12 @@ Object.freeze({
|
|
|
34874
35113
|
addonId: null,
|
|
34875
35114
|
access: "view"
|
|
34876
35115
|
},
|
|
35116
|
+
"deviceManager.getDeviceSettingsContribution": {
|
|
35117
|
+
capName: "device-manager",
|
|
35118
|
+
capScope: "system",
|
|
35119
|
+
addonId: null,
|
|
35120
|
+
access: "view"
|
|
35121
|
+
},
|
|
34877
35122
|
"deviceManager.getDeviceStatusAggregate": {
|
|
34878
35123
|
capName: "device-manager",
|
|
34879
35124
|
capScope: "system",
|
|
@@ -35366,6 +35611,36 @@ Object.freeze({
|
|
|
35366
35611
|
addonId: null,
|
|
35367
35612
|
access: "create"
|
|
35368
35613
|
},
|
|
35614
|
+
"deviceStatus.getStatus": {
|
|
35615
|
+
capName: "device-status",
|
|
35616
|
+
capScope: "device",
|
|
35617
|
+
addonId: null,
|
|
35618
|
+
access: "view"
|
|
35619
|
+
},
|
|
35620
|
+
"doorbell.applyDeviceSettingsPatch": {
|
|
35621
|
+
capName: "doorbell",
|
|
35622
|
+
capScope: "device",
|
|
35623
|
+
addonId: null,
|
|
35624
|
+
access: "create"
|
|
35625
|
+
},
|
|
35626
|
+
"doorbell.getDeviceLiveContribution": {
|
|
35627
|
+
capName: "doorbell",
|
|
35628
|
+
capScope: "device",
|
|
35629
|
+
addonId: null,
|
|
35630
|
+
access: "view"
|
|
35631
|
+
},
|
|
35632
|
+
"doorbell.getDeviceSettingsContribution": {
|
|
35633
|
+
capName: "doorbell",
|
|
35634
|
+
capScope: "device",
|
|
35635
|
+
addonId: null,
|
|
35636
|
+
access: "view"
|
|
35637
|
+
},
|
|
35638
|
+
"doorbell.getStatus": {
|
|
35639
|
+
capName: "doorbell",
|
|
35640
|
+
capScope: "device",
|
|
35641
|
+
addonId: null,
|
|
35642
|
+
access: "view"
|
|
35643
|
+
},
|
|
35369
35644
|
"embeddingEncoder.encode": {
|
|
35370
35645
|
capName: "embedding-encoder",
|
|
35371
35646
|
capScope: "system",
|
|
@@ -35384,6 +35659,18 @@ Object.freeze({
|
|
|
35384
35659
|
addonId: null,
|
|
35385
35660
|
access: "view"
|
|
35386
35661
|
},
|
|
35662
|
+
"enumSensor.getStatus": {
|
|
35663
|
+
capName: "enum-sensor",
|
|
35664
|
+
capScope: "device",
|
|
35665
|
+
addonId: null,
|
|
35666
|
+
access: "view"
|
|
35667
|
+
},
|
|
35668
|
+
"eventEmitter.getStatus": {
|
|
35669
|
+
capName: "event-emitter",
|
|
35670
|
+
capScope: "device",
|
|
35671
|
+
addonId: null,
|
|
35672
|
+
access: "view"
|
|
35673
|
+
},
|
|
35387
35674
|
"events.getEventClipUrl": {
|
|
35388
35675
|
capName: "events",
|
|
35389
35676
|
capScope: "device",
|
|
@@ -35504,6 +35791,12 @@ Object.freeze({
|
|
|
35504
35791
|
addonId: null,
|
|
35505
35792
|
access: "view"
|
|
35506
35793
|
},
|
|
35794
|
+
"fanControl.getStatus": {
|
|
35795
|
+
capName: "fan-control",
|
|
35796
|
+
capScope: "device",
|
|
35797
|
+
addonId: null,
|
|
35798
|
+
access: "view"
|
|
35799
|
+
},
|
|
35507
35800
|
"fanControl.setDirection": {
|
|
35508
35801
|
capName: "fan-control",
|
|
35509
35802
|
capScope: "device",
|
|
@@ -35528,6 +35821,12 @@ Object.freeze({
|
|
|
35528
35821
|
addonId: null,
|
|
35529
35822
|
access: "create"
|
|
35530
35823
|
},
|
|
35824
|
+
"featureProbe.getStatus": {
|
|
35825
|
+
capName: "feature-probe",
|
|
35826
|
+
capScope: "device",
|
|
35827
|
+
addonId: null,
|
|
35828
|
+
access: "view"
|
|
35829
|
+
},
|
|
35531
35830
|
"filesystemBrowse.browse": {
|
|
35532
35831
|
capName: "filesystem-browse",
|
|
35533
35832
|
capScope: "system",
|
|
@@ -35546,6 +35845,24 @@ Object.freeze({
|
|
|
35546
35845
|
addonId: null,
|
|
35547
35846
|
access: "view"
|
|
35548
35847
|
},
|
|
35848
|
+
"flood.getStatus": {
|
|
35849
|
+
capName: "flood",
|
|
35850
|
+
capScope: "device",
|
|
35851
|
+
addonId: null,
|
|
35852
|
+
access: "view"
|
|
35853
|
+
},
|
|
35854
|
+
"gas.getStatus": {
|
|
35855
|
+
capName: "gas",
|
|
35856
|
+
capScope: "device",
|
|
35857
|
+
addonId: null,
|
|
35858
|
+
access: "view"
|
|
35859
|
+
},
|
|
35860
|
+
"humidifier.getStatus": {
|
|
35861
|
+
capName: "humidifier",
|
|
35862
|
+
capScope: "device",
|
|
35863
|
+
addonId: null,
|
|
35864
|
+
access: "view"
|
|
35865
|
+
},
|
|
35549
35866
|
"humidifier.setMode": {
|
|
35550
35867
|
capName: "humidifier",
|
|
35551
35868
|
capScope: "device",
|
|
@@ -35564,12 +35881,30 @@ Object.freeze({
|
|
|
35564
35881
|
addonId: null,
|
|
35565
35882
|
access: "create"
|
|
35566
35883
|
},
|
|
35884
|
+
"humiditySensor.getStatus": {
|
|
35885
|
+
capName: "humidity-sensor",
|
|
35886
|
+
capScope: "device",
|
|
35887
|
+
addonId: null,
|
|
35888
|
+
access: "view"
|
|
35889
|
+
},
|
|
35890
|
+
"image.getStatus": {
|
|
35891
|
+
capName: "image",
|
|
35892
|
+
capScope: "device",
|
|
35893
|
+
addonId: null,
|
|
35894
|
+
access: "view"
|
|
35895
|
+
},
|
|
35567
35896
|
"imageSettings.getOptions": {
|
|
35568
35897
|
capName: "image-settings",
|
|
35569
35898
|
capScope: "device",
|
|
35570
35899
|
addonId: null,
|
|
35571
35900
|
access: "view"
|
|
35572
35901
|
},
|
|
35902
|
+
"imageSettings.getStatus": {
|
|
35903
|
+
capName: "image-settings",
|
|
35904
|
+
capScope: "device",
|
|
35905
|
+
addonId: null,
|
|
35906
|
+
access: "view"
|
|
35907
|
+
},
|
|
35573
35908
|
"imageSettings.setSettings": {
|
|
35574
35909
|
capName: "image-settings",
|
|
35575
35910
|
capScope: "device",
|
|
@@ -35642,6 +35977,12 @@ Object.freeze({
|
|
|
35642
35977
|
addonId: null,
|
|
35643
35978
|
access: "create"
|
|
35644
35979
|
},
|
|
35980
|
+
"intercom.getStatus": {
|
|
35981
|
+
capName: "intercom",
|
|
35982
|
+
capScope: "device",
|
|
35983
|
+
addonId: null,
|
|
35984
|
+
access: "view"
|
|
35985
|
+
},
|
|
35645
35986
|
"intercom.handleAnswer": {
|
|
35646
35987
|
capName: "intercom",
|
|
35647
35988
|
capScope: "device",
|
|
@@ -35678,6 +36019,12 @@ Object.freeze({
|
|
|
35678
36019
|
addonId: null,
|
|
35679
36020
|
access: "create"
|
|
35680
36021
|
},
|
|
36022
|
+
"lawnMowerControl.getStatus": {
|
|
36023
|
+
capName: "lawn-mower-control",
|
|
36024
|
+
capScope: "device",
|
|
36025
|
+
addonId: null,
|
|
36026
|
+
access: "view"
|
|
36027
|
+
},
|
|
35681
36028
|
"lawnMowerControl.pause": {
|
|
35682
36029
|
capName: "lawn-mower-control",
|
|
35683
36030
|
capScope: "device",
|
|
@@ -35960,6 +36307,12 @@ Object.freeze({
|
|
|
35960
36307
|
addonId: null,
|
|
35961
36308
|
access: "create"
|
|
35962
36309
|
},
|
|
36310
|
+
"lockControl.getStatus": {
|
|
36311
|
+
capName: "lock-control",
|
|
36312
|
+
capScope: "device",
|
|
36313
|
+
addonId: null,
|
|
36314
|
+
access: "view"
|
|
36315
|
+
},
|
|
35963
36316
|
"lockControl.lock": {
|
|
35964
36317
|
capName: "lock-control",
|
|
35965
36318
|
capScope: "device",
|
|
@@ -36008,6 +36361,12 @@ Object.freeze({
|
|
|
36008
36361
|
addonId: null,
|
|
36009
36362
|
access: "view"
|
|
36010
36363
|
},
|
|
36364
|
+
"mediaPlayer.getStatus": {
|
|
36365
|
+
capName: "media-player",
|
|
36366
|
+
capScope: "device",
|
|
36367
|
+
addonId: null,
|
|
36368
|
+
access: "view"
|
|
36369
|
+
},
|
|
36011
36370
|
"mediaPlayer.next": {
|
|
36012
36371
|
capName: "media-player",
|
|
36013
36372
|
capScope: "device",
|
|
@@ -36200,6 +36559,12 @@ Object.freeze({
|
|
|
36200
36559
|
addonId: null,
|
|
36201
36560
|
access: "create"
|
|
36202
36561
|
},
|
|
36562
|
+
"motion.getStatus": {
|
|
36563
|
+
capName: "motion",
|
|
36564
|
+
capScope: "device",
|
|
36565
|
+
addonId: null,
|
|
36566
|
+
access: "view"
|
|
36567
|
+
},
|
|
36203
36568
|
"motion.isDetected": {
|
|
36204
36569
|
capName: "motion",
|
|
36205
36570
|
capScope: "device",
|
|
@@ -36212,6 +36577,24 @@ Object.freeze({
|
|
|
36212
36577
|
addonId: null,
|
|
36213
36578
|
access: "create"
|
|
36214
36579
|
},
|
|
36580
|
+
"motionDetection.applyDeviceSettingsPatch": {
|
|
36581
|
+
capName: "motion-detection",
|
|
36582
|
+
capScope: "device",
|
|
36583
|
+
addonId: null,
|
|
36584
|
+
access: "create"
|
|
36585
|
+
},
|
|
36586
|
+
"motionDetection.getDeviceLiveContribution": {
|
|
36587
|
+
capName: "motion-detection",
|
|
36588
|
+
capScope: "device",
|
|
36589
|
+
addonId: null,
|
|
36590
|
+
access: "view"
|
|
36591
|
+
},
|
|
36592
|
+
"motionDetection.getDeviceSettingsContribution": {
|
|
36593
|
+
capName: "motion-detection",
|
|
36594
|
+
capScope: "device",
|
|
36595
|
+
addonId: null,
|
|
36596
|
+
access: "view"
|
|
36597
|
+
},
|
|
36215
36598
|
"motionDetection.removeCamera": {
|
|
36216
36599
|
capName: "motion-detection",
|
|
36217
36600
|
capScope: "device",
|
|
@@ -36224,6 +36607,12 @@ Object.freeze({
|
|
|
36224
36607
|
addonId: null,
|
|
36225
36608
|
access: "delete"
|
|
36226
36609
|
},
|
|
36610
|
+
"motionTrigger.getStatus": {
|
|
36611
|
+
capName: "motion-trigger",
|
|
36612
|
+
capScope: "device",
|
|
36613
|
+
addonId: null,
|
|
36614
|
+
access: "view"
|
|
36615
|
+
},
|
|
36227
36616
|
"motionTrigger.setMotionTrigger": {
|
|
36228
36617
|
capName: "motion-trigger",
|
|
36229
36618
|
capScope: "device",
|
|
@@ -36236,6 +36625,12 @@ Object.freeze({
|
|
|
36236
36625
|
addonId: null,
|
|
36237
36626
|
access: "view"
|
|
36238
36627
|
},
|
|
36628
|
+
"motionZones.getStatus": {
|
|
36629
|
+
capName: "motion-zones",
|
|
36630
|
+
capScope: "device",
|
|
36631
|
+
addonId: null,
|
|
36632
|
+
access: "view"
|
|
36633
|
+
},
|
|
36239
36634
|
"motionZones.setZone": {
|
|
36240
36635
|
capName: "motion-zones",
|
|
36241
36636
|
capScope: "device",
|
|
@@ -36296,6 +36691,12 @@ Object.freeze({
|
|
|
36296
36691
|
addonId: null,
|
|
36297
36692
|
access: "view"
|
|
36298
36693
|
},
|
|
36694
|
+
"nativeObjectDetection.getStatus": {
|
|
36695
|
+
capName: "native-object-detection",
|
|
36696
|
+
capScope: "device",
|
|
36697
|
+
addonId: null,
|
|
36698
|
+
access: "view"
|
|
36699
|
+
},
|
|
36299
36700
|
"nativeObjectDetection.setEnabled": {
|
|
36300
36701
|
capName: "native-object-detection",
|
|
36301
36702
|
capScope: "device",
|
|
@@ -36314,6 +36715,12 @@ Object.freeze({
|
|
|
36314
36715
|
addonId: null,
|
|
36315
36716
|
access: "view"
|
|
36316
36717
|
},
|
|
36718
|
+
"navigation.getStatus": {
|
|
36719
|
+
capName: "navigation",
|
|
36720
|
+
capScope: "device",
|
|
36721
|
+
addonId: null,
|
|
36722
|
+
access: "view"
|
|
36723
|
+
},
|
|
36317
36724
|
"navigation.goToPoint": {
|
|
36318
36725
|
capName: "navigation",
|
|
36319
36726
|
capScope: "device",
|
|
@@ -36398,6 +36805,12 @@ Object.freeze({
|
|
|
36398
36805
|
addonId: null,
|
|
36399
36806
|
access: "create"
|
|
36400
36807
|
},
|
|
36808
|
+
"networkLink.getStatus": {
|
|
36809
|
+
capName: "network-link",
|
|
36810
|
+
capScope: "device",
|
|
36811
|
+
addonId: null,
|
|
36812
|
+
access: "view"
|
|
36813
|
+
},
|
|
36401
36814
|
"networkQuality.getAllStats": {
|
|
36402
36815
|
capName: "network-quality",
|
|
36403
36816
|
capScope: "system",
|
|
@@ -36656,18 +37069,36 @@ Object.freeze({
|
|
|
36656
37069
|
addonId: null,
|
|
36657
37070
|
access: "create"
|
|
36658
37071
|
},
|
|
37072
|
+
"notifier.getStatus": {
|
|
37073
|
+
capName: "notifier",
|
|
37074
|
+
capScope: "device",
|
|
37075
|
+
addonId: null,
|
|
37076
|
+
access: "view"
|
|
37077
|
+
},
|
|
36659
37078
|
"notifier.send": {
|
|
36660
37079
|
capName: "notifier",
|
|
36661
37080
|
capScope: "device",
|
|
36662
37081
|
addonId: null,
|
|
36663
37082
|
access: "create"
|
|
36664
37083
|
},
|
|
37084
|
+
"numericSensor.getStatus": {
|
|
37085
|
+
capName: "numeric-sensor",
|
|
37086
|
+
capScope: "device",
|
|
37087
|
+
addonId: null,
|
|
37088
|
+
access: "view"
|
|
37089
|
+
},
|
|
36665
37090
|
"oauthIntegration.getDescriptor": {
|
|
36666
37091
|
capName: "oauth-integration",
|
|
36667
37092
|
capScope: "system",
|
|
36668
37093
|
addonId: null,
|
|
36669
37094
|
access: "view"
|
|
36670
37095
|
},
|
|
37096
|
+
"osd.getStatus": {
|
|
37097
|
+
capName: "osd",
|
|
37098
|
+
capScope: "device",
|
|
37099
|
+
addonId: null,
|
|
37100
|
+
access: "view"
|
|
37101
|
+
},
|
|
36671
37102
|
"osd.setOverlay": {
|
|
36672
37103
|
capName: "osd",
|
|
36673
37104
|
capScope: "device",
|
|
@@ -36740,6 +37171,12 @@ Object.freeze({
|
|
|
36740
37171
|
addonId: null,
|
|
36741
37172
|
access: "create"
|
|
36742
37173
|
},
|
|
37174
|
+
"petFeeder.getStatus": {
|
|
37175
|
+
capName: "pet-feeder",
|
|
37176
|
+
capScope: "device",
|
|
37177
|
+
addonId: null,
|
|
37178
|
+
access: "view"
|
|
37179
|
+
},
|
|
36743
37180
|
"petFeeder.markFoodReplenished": {
|
|
36744
37181
|
capName: "pet-feeder",
|
|
36745
37182
|
capScope: "device",
|
|
@@ -36782,6 +37219,12 @@ Object.freeze({
|
|
|
36782
37219
|
addonId: null,
|
|
36783
37220
|
access: "create"
|
|
36784
37221
|
},
|
|
37222
|
+
"pipelineAnalytics.applyDeviceSettingsPatch": {
|
|
37223
|
+
capName: "pipeline-analytics",
|
|
37224
|
+
capScope: "device",
|
|
37225
|
+
addonId: null,
|
|
37226
|
+
access: "create"
|
|
37227
|
+
},
|
|
36785
37228
|
"pipelineAnalytics.cancelRelocateMedia": {
|
|
36786
37229
|
capName: "pipeline-analytics",
|
|
36787
37230
|
capScope: "device",
|
|
@@ -36848,6 +37291,18 @@ Object.freeze({
|
|
|
36848
37291
|
addonId: null,
|
|
36849
37292
|
access: "view"
|
|
36850
37293
|
},
|
|
37294
|
+
"pipelineAnalytics.getDeviceLiveContribution": {
|
|
37295
|
+
capName: "pipeline-analytics",
|
|
37296
|
+
capScope: "device",
|
|
37297
|
+
addonId: null,
|
|
37298
|
+
access: "view"
|
|
37299
|
+
},
|
|
37300
|
+
"pipelineAnalytics.getDeviceSettingsContribution": {
|
|
37301
|
+
capName: "pipeline-analytics",
|
|
37302
|
+
capScope: "device",
|
|
37303
|
+
addonId: null,
|
|
37304
|
+
access: "view"
|
|
37305
|
+
},
|
|
36851
37306
|
"pipelineAnalytics.getEventDensity": {
|
|
36852
37307
|
capName: "pipeline-analytics",
|
|
36853
37308
|
capScope: "device",
|
|
@@ -37418,6 +37873,12 @@ Object.freeze({
|
|
|
37418
37873
|
addonId: null,
|
|
37419
37874
|
access: "view"
|
|
37420
37875
|
},
|
|
37876
|
+
"pipelineOrchestrator.applyDeviceSettingsPatch": {
|
|
37877
|
+
capName: "pipeline-orchestrator",
|
|
37878
|
+
capScope: "system",
|
|
37879
|
+
addonId: null,
|
|
37880
|
+
access: "create"
|
|
37881
|
+
},
|
|
37421
37882
|
"pipelineOrchestrator.assignAudio": {
|
|
37422
37883
|
capName: "pipeline-orchestrator",
|
|
37423
37884
|
capScope: "system",
|
|
@@ -37508,6 +37969,18 @@ Object.freeze({
|
|
|
37508
37969
|
addonId: null,
|
|
37509
37970
|
access: "view"
|
|
37510
37971
|
},
|
|
37972
|
+
"pipelineOrchestrator.getDeviceLiveContribution": {
|
|
37973
|
+
capName: "pipeline-orchestrator",
|
|
37974
|
+
capScope: "system",
|
|
37975
|
+
addonId: null,
|
|
37976
|
+
access: "view"
|
|
37977
|
+
},
|
|
37978
|
+
"pipelineOrchestrator.getDeviceSettingsContribution": {
|
|
37979
|
+
capName: "pipeline-orchestrator",
|
|
37980
|
+
capScope: "system",
|
|
37981
|
+
addonId: null,
|
|
37982
|
+
access: "view"
|
|
37983
|
+
},
|
|
37511
37984
|
"pipelineOrchestrator.getGlobalMetrics": {
|
|
37512
37985
|
capName: "pipeline-orchestrator",
|
|
37513
37986
|
capScope: "system",
|
|
@@ -37916,12 +38389,36 @@ Object.freeze({
|
|
|
37916
38389
|
addonId: null,
|
|
37917
38390
|
access: "view"
|
|
37918
38391
|
},
|
|
38392
|
+
"powerMeter.getStatus": {
|
|
38393
|
+
capName: "power-meter",
|
|
38394
|
+
capScope: "device",
|
|
38395
|
+
addonId: null,
|
|
38396
|
+
access: "view"
|
|
38397
|
+
},
|
|
38398
|
+
"presence.getStatus": {
|
|
38399
|
+
capName: "presence",
|
|
38400
|
+
capScope: "device",
|
|
38401
|
+
addonId: null,
|
|
38402
|
+
access: "view"
|
|
38403
|
+
},
|
|
38404
|
+
"pressureSensor.getStatus": {
|
|
38405
|
+
capName: "pressure-sensor",
|
|
38406
|
+
capScope: "device",
|
|
38407
|
+
addonId: null,
|
|
38408
|
+
access: "view"
|
|
38409
|
+
},
|
|
37919
38410
|
"privacyMask.getOptions": {
|
|
37920
38411
|
capName: "privacy-mask",
|
|
37921
38412
|
capScope: "device",
|
|
37922
38413
|
addonId: null,
|
|
37923
38414
|
access: "view"
|
|
37924
38415
|
},
|
|
38416
|
+
"privacyMask.getStatus": {
|
|
38417
|
+
capName: "privacy-mask",
|
|
38418
|
+
capScope: "device",
|
|
38419
|
+
addonId: null,
|
|
38420
|
+
access: "view"
|
|
38421
|
+
},
|
|
37925
38422
|
"privacyMask.setAudioEnabled": {
|
|
37926
38423
|
capName: "privacy-mask",
|
|
37927
38424
|
capScope: "device",
|
|
@@ -37982,6 +38479,12 @@ Object.freeze({
|
|
|
37982
38479
|
addonId: null,
|
|
37983
38480
|
access: "view"
|
|
37984
38481
|
},
|
|
38482
|
+
"ptz.getStatus": {
|
|
38483
|
+
capName: "ptz",
|
|
38484
|
+
capScope: "device",
|
|
38485
|
+
addonId: null,
|
|
38486
|
+
access: "view"
|
|
38487
|
+
},
|
|
37985
38488
|
"ptz.goHome": {
|
|
37986
38489
|
capName: "ptz",
|
|
37987
38490
|
capScope: "device",
|
|
@@ -38060,6 +38563,12 @@ Object.freeze({
|
|
|
38060
38563
|
addonId: null,
|
|
38061
38564
|
access: "create"
|
|
38062
38565
|
},
|
|
38566
|
+
"recording.applyDeviceSettingsPatch": {
|
|
38567
|
+
capName: "recording",
|
|
38568
|
+
capScope: "system",
|
|
38569
|
+
addonId: null,
|
|
38570
|
+
access: "create"
|
|
38571
|
+
},
|
|
38063
38572
|
"recording.cancelRelocateJob": {
|
|
38064
38573
|
capName: "recording",
|
|
38065
38574
|
capScope: "system",
|
|
@@ -38108,6 +38617,18 @@ Object.freeze({
|
|
|
38108
38617
|
addonId: null,
|
|
38109
38618
|
access: "view"
|
|
38110
38619
|
},
|
|
38620
|
+
"recording.getDeviceLiveContribution": {
|
|
38621
|
+
capName: "recording",
|
|
38622
|
+
capScope: "system",
|
|
38623
|
+
addonId: null,
|
|
38624
|
+
access: "view"
|
|
38625
|
+
},
|
|
38626
|
+
"recording.getDeviceSettingsContribution": {
|
|
38627
|
+
capName: "recording",
|
|
38628
|
+
capScope: "system",
|
|
38629
|
+
addonId: null,
|
|
38630
|
+
access: "view"
|
|
38631
|
+
},
|
|
38111
38632
|
"recording.getPlacement": {
|
|
38112
38633
|
capName: "recording",
|
|
38113
38634
|
capScope: "system",
|
|
@@ -38126,6 +38647,12 @@ Object.freeze({
|
|
|
38126
38647
|
addonId: null,
|
|
38127
38648
|
access: "view"
|
|
38128
38649
|
},
|
|
38650
|
+
"recording.getStatus": {
|
|
38651
|
+
capName: "recording",
|
|
38652
|
+
capScope: "system",
|
|
38653
|
+
addonId: null,
|
|
38654
|
+
access: "view"
|
|
38655
|
+
},
|
|
38129
38656
|
"recording.getStorageMigrationMoveStatus": {
|
|
38130
38657
|
capName: "recording",
|
|
38131
38658
|
capScope: "system",
|
|
@@ -38330,6 +38857,12 @@ Object.freeze({
|
|
|
38330
38857
|
addonId: null,
|
|
38331
38858
|
access: "delete"
|
|
38332
38859
|
},
|
|
38860
|
+
"sceneMonitor.getStatus": {
|
|
38861
|
+
capName: "scene-monitor",
|
|
38862
|
+
capScope: "device",
|
|
38863
|
+
addonId: null,
|
|
38864
|
+
access: "view"
|
|
38865
|
+
},
|
|
38333
38866
|
"sceneMonitor.listScenes": {
|
|
38334
38867
|
capName: "scene-monitor",
|
|
38335
38868
|
capScope: "device",
|
|
@@ -38360,6 +38893,12 @@ Object.freeze({
|
|
|
38360
38893
|
addonId: null,
|
|
38361
38894
|
access: "create"
|
|
38362
38895
|
},
|
|
38896
|
+
"scriptRunner.getStatus": {
|
|
38897
|
+
capName: "script-runner",
|
|
38898
|
+
capScope: "device",
|
|
38899
|
+
addonId: null,
|
|
38900
|
+
access: "view"
|
|
38901
|
+
},
|
|
38363
38902
|
"scriptRunner.run": {
|
|
38364
38903
|
capName: "script-runner",
|
|
38365
38904
|
capScope: "device",
|
|
@@ -38492,6 +39031,12 @@ Object.freeze({
|
|
|
38492
39031
|
addonId: null,
|
|
38493
39032
|
access: "create"
|
|
38494
39033
|
},
|
|
39034
|
+
"smoke.getStatus": {
|
|
39035
|
+
capName: "smoke",
|
|
39036
|
+
capScope: "device",
|
|
39037
|
+
addonId: null,
|
|
39038
|
+
access: "view"
|
|
39039
|
+
},
|
|
38495
39040
|
"smtpProvider.getStatus": {
|
|
38496
39041
|
capName: "smtp-provider",
|
|
38497
39042
|
capScope: "system",
|
|
@@ -38510,12 +39055,30 @@ Object.freeze({
|
|
|
38510
39055
|
addonId: null,
|
|
38511
39056
|
access: "view"
|
|
38512
39057
|
},
|
|
39058
|
+
"snapshot.applyDeviceSettingsPatch": {
|
|
39059
|
+
capName: "snapshot",
|
|
39060
|
+
capScope: "device",
|
|
39061
|
+
addonId: null,
|
|
39062
|
+
access: "create"
|
|
39063
|
+
},
|
|
38513
39064
|
"snapshot.getDebugState": {
|
|
38514
39065
|
capName: "snapshot",
|
|
38515
39066
|
capScope: "device",
|
|
38516
39067
|
addonId: null,
|
|
38517
39068
|
access: "view"
|
|
38518
39069
|
},
|
|
39070
|
+
"snapshot.getDeviceLiveContribution": {
|
|
39071
|
+
capName: "snapshot",
|
|
39072
|
+
capScope: "device",
|
|
39073
|
+
addonId: null,
|
|
39074
|
+
access: "view"
|
|
39075
|
+
},
|
|
39076
|
+
"snapshot.getDeviceSettingsContribution": {
|
|
39077
|
+
capName: "snapshot",
|
|
39078
|
+
capScope: "device",
|
|
39079
|
+
addonId: null,
|
|
39080
|
+
access: "view"
|
|
39081
|
+
},
|
|
38519
39082
|
"snapshot.getSnapshot": {
|
|
38520
39083
|
capName: "snapshot",
|
|
38521
39084
|
capScope: "device",
|
|
@@ -38534,6 +39097,12 @@ Object.freeze({
|
|
|
38534
39097
|
addonId: null,
|
|
38535
39098
|
access: "view"
|
|
38536
39099
|
},
|
|
39100
|
+
"snapshot.getStatus": {
|
|
39101
|
+
capName: "snapshot",
|
|
39102
|
+
capScope: "device",
|
|
39103
|
+
addonId: null,
|
|
39104
|
+
access: "view"
|
|
39105
|
+
},
|
|
38537
39106
|
"snapshot.invalidateCache": {
|
|
38538
39107
|
capName: "snapshot",
|
|
38539
39108
|
capScope: "device",
|
|
@@ -38870,6 +39439,12 @@ Object.freeze({
|
|
|
38870
39439
|
addonId: null,
|
|
38871
39440
|
access: "create"
|
|
38872
39441
|
},
|
|
39442
|
+
"streamBroker.applyDeviceSettingsPatch": {
|
|
39443
|
+
capName: "stream-broker",
|
|
39444
|
+
capScope: "system",
|
|
39445
|
+
addonId: null,
|
|
39446
|
+
access: "create"
|
|
39447
|
+
},
|
|
38873
39448
|
"streamBroker.assignProfile": {
|
|
38874
39449
|
capName: "stream-broker",
|
|
38875
39450
|
capScope: "system",
|
|
@@ -38906,6 +39481,18 @@ Object.freeze({
|
|
|
38906
39481
|
addonId: null,
|
|
38907
39482
|
access: "view"
|
|
38908
39483
|
},
|
|
39484
|
+
"streamBroker.getDeviceLiveContribution": {
|
|
39485
|
+
capName: "stream-broker",
|
|
39486
|
+
capScope: "system",
|
|
39487
|
+
addonId: null,
|
|
39488
|
+
access: "view"
|
|
39489
|
+
},
|
|
39490
|
+
"streamBroker.getDeviceSettingsContribution": {
|
|
39491
|
+
capName: "stream-broker",
|
|
39492
|
+
capScope: "system",
|
|
39493
|
+
addonId: null,
|
|
39494
|
+
access: "view"
|
|
39495
|
+
},
|
|
38909
39496
|
"streamBroker.getPreBufferInfo": {
|
|
38910
39497
|
capName: "stream-broker",
|
|
38911
39498
|
capScope: "system",
|
|
@@ -39104,6 +39691,12 @@ Object.freeze({
|
|
|
39104
39691
|
addonId: null,
|
|
39105
39692
|
access: "view"
|
|
39106
39693
|
},
|
|
39694
|
+
"streamParams.getStatus": {
|
|
39695
|
+
capName: "stream-params",
|
|
39696
|
+
capScope: "device",
|
|
39697
|
+
addonId: null,
|
|
39698
|
+
access: "view"
|
|
39699
|
+
},
|
|
39107
39700
|
"streamParams.setProfile": {
|
|
39108
39701
|
capName: "stream-params",
|
|
39109
39702
|
capScope: "device",
|
|
@@ -39116,6 +39709,12 @@ Object.freeze({
|
|
|
39116
39709
|
addonId: null,
|
|
39117
39710
|
access: "view"
|
|
39118
39711
|
},
|
|
39712
|
+
"switch.getStatus": {
|
|
39713
|
+
capName: "switch",
|
|
39714
|
+
capScope: "device",
|
|
39715
|
+
addonId: null,
|
|
39716
|
+
access: "view"
|
|
39717
|
+
},
|
|
39119
39718
|
"switch.setState": {
|
|
39120
39719
|
capName: "switch",
|
|
39121
39720
|
capScope: "device",
|
|
@@ -39212,6 +39811,18 @@ Object.freeze({
|
|
|
39212
39811
|
addonId: null,
|
|
39213
39812
|
access: "create"
|
|
39214
39813
|
},
|
|
39814
|
+
"tamper.getStatus": {
|
|
39815
|
+
capName: "tamper",
|
|
39816
|
+
capScope: "device",
|
|
39817
|
+
addonId: null,
|
|
39818
|
+
access: "view"
|
|
39819
|
+
},
|
|
39820
|
+
"temperatureSensor.getStatus": {
|
|
39821
|
+
capName: "temperature-sensor",
|
|
39822
|
+
capScope: "device",
|
|
39823
|
+
addonId: null,
|
|
39824
|
+
access: "view"
|
|
39825
|
+
},
|
|
39215
39826
|
"terminalSession.adoptLegacyMonitor": {
|
|
39216
39827
|
capName: "terminal-session",
|
|
39217
39828
|
capScope: "system",
|
|
@@ -39308,6 +39919,12 @@ Object.freeze({
|
|
|
39308
39919
|
addonId: null,
|
|
39309
39920
|
access: "view"
|
|
39310
39921
|
},
|
|
39922
|
+
"update.getStatus": {
|
|
39923
|
+
capName: "update",
|
|
39924
|
+
capScope: "device",
|
|
39925
|
+
addonId: null,
|
|
39926
|
+
access: "view"
|
|
39927
|
+
},
|
|
39311
39928
|
"update.installUpdate": {
|
|
39312
39929
|
capName: "update",
|
|
39313
39930
|
capScope: "device",
|
|
@@ -39530,6 +40147,12 @@ Object.freeze({
|
|
|
39530
40147
|
addonId: null,
|
|
39531
40148
|
access: "create"
|
|
39532
40149
|
},
|
|
40150
|
+
"vacuumControl.getStatus": {
|
|
40151
|
+
capName: "vacuum-control",
|
|
40152
|
+
capScope: "device",
|
|
40153
|
+
addonId: null,
|
|
40154
|
+
access: "view"
|
|
40155
|
+
},
|
|
39533
40156
|
"vacuumControl.locate": {
|
|
39534
40157
|
capName: "vacuum-control",
|
|
39535
40158
|
capScope: "device",
|
|
@@ -39572,6 +40195,12 @@ Object.freeze({
|
|
|
39572
40195
|
addonId: null,
|
|
39573
40196
|
access: "create"
|
|
39574
40197
|
},
|
|
40198
|
+
"valve.getStatus": {
|
|
40199
|
+
capName: "valve",
|
|
40200
|
+
capScope: "device",
|
|
40201
|
+
addonId: null,
|
|
40202
|
+
access: "view"
|
|
40203
|
+
},
|
|
39575
40204
|
"valve.open": {
|
|
39576
40205
|
capName: "valve",
|
|
39577
40206
|
capScope: "device",
|
|
@@ -39644,6 +40273,12 @@ Object.freeze({
|
|
|
39644
40273
|
addonId: null,
|
|
39645
40274
|
access: "create"
|
|
39646
40275
|
},
|
|
40276
|
+
"vibration.getStatus": {
|
|
40277
|
+
capName: "vibration",
|
|
40278
|
+
capScope: "device",
|
|
40279
|
+
addonId: null,
|
|
40280
|
+
access: "view"
|
|
40281
|
+
},
|
|
39647
40282
|
"videoclips.getClipPlayback": {
|
|
39648
40283
|
capName: "videoclips",
|
|
39649
40284
|
capScope: "device",
|
|
@@ -39680,6 +40315,12 @@ Object.freeze({
|
|
|
39680
40315
|
addonId: null,
|
|
39681
40316
|
access: "view"
|
|
39682
40317
|
},
|
|
40318
|
+
"waterHeater.getStatus": {
|
|
40319
|
+
capName: "water-heater",
|
|
40320
|
+
capScope: "device",
|
|
40321
|
+
addonId: null,
|
|
40322
|
+
access: "view"
|
|
40323
|
+
},
|
|
39683
40324
|
"waterHeater.setAway": {
|
|
39684
40325
|
capName: "water-heater",
|
|
39685
40326
|
capScope: "device",
|
|
@@ -39698,6 +40339,12 @@ Object.freeze({
|
|
|
39698
40339
|
addonId: null,
|
|
39699
40340
|
access: "create"
|
|
39700
40341
|
},
|
|
40342
|
+
"weather.getStatus": {
|
|
40343
|
+
capName: "weather",
|
|
40344
|
+
capScope: "device",
|
|
40345
|
+
addonId: null,
|
|
40346
|
+
access: "view"
|
|
40347
|
+
},
|
|
39701
40348
|
"webrtcSession.addIceCandidate": {
|
|
39702
40349
|
capName: "webrtc-session",
|
|
39703
40350
|
capScope: "device",
|
|
@@ -90660,6 +91307,153 @@ function createClipThumbnailMinter(input) {
|
|
|
90660
91307
|
};
|
|
90661
91308
|
}
|
|
90662
91309
|
//#endregion
|
|
91310
|
+
//#region src/hksv/recording-active.ts
|
|
91311
|
+
/**
|
|
91312
|
+
* `true`/`false` as HomeKit holds it, or `null` when this accessory does not
|
|
91313
|
+
* offer recording at all.
|
|
91314
|
+
*/
|
|
91315
|
+
function readHomekitRecordingActive(accessories) {
|
|
91316
|
+
for (const accessory of accessories) {
|
|
91317
|
+
const service = accessory.getService(import_dist.Service.CameraRecordingManagement);
|
|
91318
|
+
if (service === void 0) continue;
|
|
91319
|
+
const value = service.getCharacteristic(import_dist.Characteristic.Active).value;
|
|
91320
|
+
if (typeof value === "number") return value === 1;
|
|
91321
|
+
if (typeof value === "boolean") return value;
|
|
91322
|
+
return null;
|
|
91323
|
+
}
|
|
91324
|
+
return null;
|
|
91325
|
+
}
|
|
91326
|
+
/**
|
|
91327
|
+
* One sentence for the settings page: what HomeKit says, or why it was never
|
|
91328
|
+
* asked.
|
|
91329
|
+
*
|
|
91330
|
+
* The cost stays in the text even though the switch is gone. It is still the
|
|
91331
|
+
* operator's to understand — a camera recording here runs a permanent ffmpeg —
|
|
91332
|
+
* and a status line that reported only the state would have quietly dropped
|
|
91333
|
+
* the one number that decides whether to turn it on.
|
|
91334
|
+
*/
|
|
91335
|
+
function describeHomekitRecording(active, lastBuild) {
|
|
91336
|
+
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).";
|
|
91337
|
+
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.";
|
|
91338
|
+
if (lastBuild !== null && !lastBuild.advertised) return `Recording is not offered for this camera: ${lastBuild.detail ?? "the accessory could not advertise it"}.`;
|
|
91339
|
+
return "Not known yet — this camera’s accessory has not published its recording service in this process. It appears once the accessory is built.";
|
|
91340
|
+
}
|
|
91341
|
+
//#endregion
|
|
91342
|
+
//#region src/hksv/recording-source.ts
|
|
91343
|
+
/** The tallest frame the recording path will hold in its prebuffer. */
|
|
91344
|
+
var MAX_RECORDING_HEIGHT = 1080;
|
|
91345
|
+
/** HKSV takes H.264 only — AAC audio and H.264 video, no negotiation. */
|
|
91346
|
+
var RECORDABLE_CODEC = "h264";
|
|
91347
|
+
/**
|
|
91348
|
+
* Pick the slot the recording child pulls.
|
|
91349
|
+
*
|
|
91350
|
+
* Deliberately NOT `pickPreferredRtspEntry`: that picker resolves the operator's
|
|
91351
|
+
* LIVE preference and, on `auto`, steers by the resolution iOS negotiated for a
|
|
91352
|
+
* live session — neither is a fact about recording, and on 615 it selects `mid`,
|
|
91353
|
+
* a 10 fps slot. Recording has one criterion, applied here and nowhere else:
|
|
91354
|
+
* the largest copyable frame that does not exceed {@link MAX_RECORDING_HEIGHT}.
|
|
91355
|
+
*/
|
|
91356
|
+
function pickRecordingSource(entries, options = {}) {
|
|
91357
|
+
const enabled = entries.filter((e) => e.enabled);
|
|
91358
|
+
if (enabled.length === 0) return {
|
|
91359
|
+
ok: false,
|
|
91360
|
+
refusal: "no-enabled-stream"
|
|
91361
|
+
};
|
|
91362
|
+
const h264 = enabled.filter((e) => normaliseCodec(e.codec) === RECORDABLE_CODEC);
|
|
91363
|
+
const pool = h264.length > 0 ? h264 : options.allowTranscode === true ? enabled : [];
|
|
91364
|
+
if (pool.length === 0) return {
|
|
91365
|
+
ok: false,
|
|
91366
|
+
refusal: "no-h264-stream"
|
|
91367
|
+
};
|
|
91368
|
+
const transcode = h264.length === 0;
|
|
91369
|
+
const sized = pool.filter(hasUsableResolution);
|
|
91370
|
+
if (sized.length === 0) return {
|
|
91371
|
+
ok: false,
|
|
91372
|
+
refusal: "no-resolution"
|
|
91373
|
+
};
|
|
91374
|
+
const withinCeiling = sized.filter((e) => height(e) <= MAX_RECORDING_HEIGHT);
|
|
91375
|
+
const within = withinCeiling.length > 0;
|
|
91376
|
+
const best = [...within ? withinCeiling : sized].sort((a, b) => within ? height(b) - height(a) : height(a) - height(b))[0];
|
|
91377
|
+
if (best === void 0 || best.resolution === void 0) return {
|
|
91378
|
+
ok: false,
|
|
91379
|
+
refusal: "no-resolution"
|
|
91380
|
+
};
|
|
91381
|
+
return {
|
|
91382
|
+
ok: true,
|
|
91383
|
+
source: {
|
|
91384
|
+
brokerId: best.brokerId,
|
|
91385
|
+
profile: best.profile ?? best.brokerId,
|
|
91386
|
+
transcode,
|
|
91387
|
+
url: best.url,
|
|
91388
|
+
mutedUrl: best.mutedUrl,
|
|
91389
|
+
width: best.resolution.width,
|
|
91390
|
+
height: best.resolution.height
|
|
91391
|
+
}
|
|
91392
|
+
};
|
|
91393
|
+
}
|
|
91394
|
+
/** A one-line reason for the log — silence about a withdrawn service reads as a bug. */
|
|
91395
|
+
function refusalReason(refusal) {
|
|
91396
|
+
switch (refusal) {
|
|
91397
|
+
case "no-enabled-stream": return "the camera has no enabled RTSP profile";
|
|
91398
|
+
case "no-h264-stream": return "every enabled profile is H.265 — HKSV takes H.264 only, and a permanent transcode costs 128x a copy";
|
|
91399
|
+
case "no-resolution": return "no enabled profile declares a resolution, so nothing honest could be advertised";
|
|
91400
|
+
}
|
|
91401
|
+
}
|
|
91402
|
+
function height(entry) {
|
|
91403
|
+
return entry.resolution?.height ?? 0;
|
|
91404
|
+
}
|
|
91405
|
+
function hasUsableResolution(entry) {
|
|
91406
|
+
const r = entry.resolution;
|
|
91407
|
+
return r !== void 0 && r.width > 0 && r.height > 0;
|
|
91408
|
+
}
|
|
91409
|
+
/** Publishers spell H.265 four ways; the same normalisation the broker uses. */
|
|
91410
|
+
function normaliseCodec(codec) {
|
|
91411
|
+
return (codec ?? "").toLowerCase().replace(/[.\s-]/g, "");
|
|
91412
|
+
}
|
|
91413
|
+
//#endregion
|
|
91414
|
+
//#region src/hksv/recordability-token.ts
|
|
91415
|
+
/** No slot is recordable. A real answer, and a fingerprint-moving one. */
|
|
91416
|
+
var RECORDABILITY_NONE = "rec:none";
|
|
91417
|
+
/**
|
|
91418
|
+
* The slot HKSV would record from, as a fingerprint token.
|
|
91419
|
+
*
|
|
91420
|
+
* `null` when `entries` is null — the profiles could not be read, which is not
|
|
91421
|
+
* a claim about the camera.
|
|
91422
|
+
*/
|
|
91423
|
+
function recordabilityToken(entries, options = {}) {
|
|
91424
|
+
if (entries === null) return null;
|
|
91425
|
+
const choice = pickRecordingSource(entries, options);
|
|
91426
|
+
return choice.ok ? `rec:${choice.source.profile}${choice.source.transcode ? "+x" : ""}` : RECORDABILITY_NONE;
|
|
91427
|
+
}
|
|
91428
|
+
var TOKEN_SUFFIX = /\|(rec:[^|]*)$/;
|
|
91429
|
+
/**
|
|
91430
|
+
* Attach the recording token to a device-shape fingerprint.
|
|
91431
|
+
*
|
|
91432
|
+
* On an unreadable read the persisted token is carried forward — but only onto
|
|
91433
|
+
* the base it was persisted against. If the device's SHAPE also changed, that
|
|
91434
|
+
* change is a rebuild in its own right and the token has nothing to say about
|
|
91435
|
+
* it; inventing one there would advertise a recording slot nobody read.
|
|
91436
|
+
*/
|
|
91437
|
+
function withRecordabilityToken(input) {
|
|
91438
|
+
if (input.token !== null) return `${input.base}|${input.token}`;
|
|
91439
|
+
const carried = input.persisted?.match(TOKEN_SUFFIX);
|
|
91440
|
+
if (carried === null || carried === void 0) return input.base;
|
|
91441
|
+
return carried.input?.slice(0, carried.index) === input.base ? `${input.base}|${carried[1]}` : input.base;
|
|
91442
|
+
}
|
|
91443
|
+
/**
|
|
91444
|
+
* What this camera could record, as one fingerprint token.
|
|
91445
|
+
*
|
|
91446
|
+
* There used to be an `rec:off` here, for a per-camera switch of ours. That
|
|
91447
|
+
* switch is gone (D589): whether HomeKit RECORDS is HomeKit's own persisted
|
|
91448
|
+
* characteristic, it does not change the accessory's shape, and a rebuild is
|
|
91449
|
+
* about shape. What still belongs here is the CAPABILITY — which slot, and
|
|
91450
|
+
* whether serving it means running an encoder — because those are two
|
|
91451
|
+
* different accessories to build.
|
|
91452
|
+
*/
|
|
91453
|
+
function recordabilityTokenFor(input) {
|
|
91454
|
+
return recordabilityToken(input.entries, { allowTranscode: input.allowTranscode !== false });
|
|
91455
|
+
}
|
|
91456
|
+
//#endregion
|
|
90663
91457
|
//#region src/hksv/videoclips-plane.ts
|
|
90664
91458
|
/**
|
|
90665
91459
|
* The two data-plane routes behind the HomeKit clip source.
|
|
@@ -90922,8 +91716,9 @@ function createHksvClipPlanes(deps) {
|
|
|
90922
91716
|
*
|
|
90923
91717
|
* ## The source EXISTS because of HomeKit, and is not a switch
|
|
90924
91718
|
*
|
|
90925
|
-
* A camera has this source because it is exported to HomeKit
|
|
90926
|
-
*
|
|
91719
|
+
* A camera has this source because it is exported to HomeKit and HomeKit has
|
|
91720
|
+
* not said no to recording it; un-export it, or switch recording off in the
|
|
91721
|
+
* Home app, and the row is gone (D550, D569 § 5, D589).
|
|
90927
91722
|
* There is deliberately no enable control of its own — a knob over somebody
|
|
90928
91723
|
* else's decision is D62's defect. `keepClips` is NOT that gate either: it
|
|
90929
91724
|
* governs the TEE, and the clips already kept remain the truth about this
|
|
@@ -90970,7 +91765,7 @@ function createHksvVideoclipsProvider(deps) {
|
|
|
90970
91765
|
*/
|
|
90971
91766
|
async function measure(deviceId) {
|
|
90972
91767
|
const facts = deps.describeCamera(deviceId);
|
|
90973
|
-
if (!facts.exported ||
|
|
91768
|
+
if (!facts.exported || facts.homekitRecording === false) return null;
|
|
90974
91769
|
const catalog = await deps.readCatalog(deviceId);
|
|
90975
91770
|
return {
|
|
90976
91771
|
availability: availabilityFor(facts, catalog),
|
|
@@ -106325,6 +107120,72 @@ function buildRecordingOptions(input) {
|
|
|
106325
107120
|
};
|
|
106326
107121
|
}
|
|
106327
107122
|
//#endregion
|
|
107123
|
+
//#region src/hksv/recording-invocation.ts
|
|
107124
|
+
/**
|
|
107125
|
+
* The resolution the accessory may advertise, which is the one it can deliver.
|
|
107126
|
+
*
|
|
107127
|
+
* A copy is advertised at its source size whatever that is — there is no
|
|
107128
|
+
* encoder to resize with, and advertising a size we cannot produce is the
|
|
107129
|
+
* "stream that does not match its own advertisement" defect in miniature.
|
|
107130
|
+
* A transcode above the ceiling is fitted down, because with an encoder in the
|
|
107131
|
+
* pipeline the 6.35 MB 4K fragment is a choice rather than a fact, and iOS
|
|
107132
|
+
* renders HKSV clips at 1080p regardless.
|
|
107133
|
+
*/
|
|
107134
|
+
function recordingOutput(source) {
|
|
107135
|
+
if (!source.transcode || source.height <= 1080) return {
|
|
107136
|
+
width: source.width,
|
|
107137
|
+
height: source.height,
|
|
107138
|
+
scaled: false
|
|
107139
|
+
};
|
|
107140
|
+
return {
|
|
107141
|
+
width: Math.max(2, Math.round(source.width * MAX_RECORDING_HEIGHT / source.height / 2) * 2),
|
|
107142
|
+
height: MAX_RECORDING_HEIGHT,
|
|
107143
|
+
scaled: true
|
|
107144
|
+
};
|
|
107145
|
+
}
|
|
107146
|
+
/** The invocation, minus the sink and sidecar the child owns. */
|
|
107147
|
+
function buildRecordingInvocation(input) {
|
|
107148
|
+
const { source } = input;
|
|
107149
|
+
const audio = input.audioActive ? {
|
|
107150
|
+
kind: "encode",
|
|
107151
|
+
codec: "aac",
|
|
107152
|
+
bitrateKbps: 32,
|
|
107153
|
+
sampleRateHz: HKSV_AUDIO_SAMPLE_RATE_HZ,
|
|
107154
|
+
channels: 1
|
|
107155
|
+
} : { kind: "none" };
|
|
107156
|
+
const out = recordingOutput(source);
|
|
107157
|
+
const video = source.transcode ? {
|
|
107158
|
+
kind: "encode",
|
|
107159
|
+
encoder: "libx264",
|
|
107160
|
+
preset: "veryfast",
|
|
107161
|
+
profile: "main",
|
|
107162
|
+
level: "4.0",
|
|
107163
|
+
pixelFormat: "yuv420p",
|
|
107164
|
+
forceKeyFramesSeconds: Math.max(1, Math.round(input.fragmentMs / 1e3)),
|
|
107165
|
+
bf: 0,
|
|
107166
|
+
...out.scaled ? { scale: {
|
|
107167
|
+
mode: "fit",
|
|
107168
|
+
width: out.width,
|
|
107169
|
+
height: out.height
|
|
107170
|
+
} } : {}
|
|
107171
|
+
} : { kind: "copy" };
|
|
107172
|
+
return {
|
|
107173
|
+
logLevel: "error",
|
|
107174
|
+
decodeHwAccel: source.transcode ? input.decodeHwAccel : null,
|
|
107175
|
+
input: {
|
|
107176
|
+
url: input.audioActive ? source.url : source.mutedUrl,
|
|
107177
|
+
rtspTransport: "tcp",
|
|
107178
|
+
...source.transcode && input.decodeInputArgs !== void 0 && input.decodeInputArgs.length > 0 ? { extraArgs: input.decodeInputArgs } : {},
|
|
107179
|
+
analyzeDurationUs: 1e6,
|
|
107180
|
+
probeSizeBytes: 1e6
|
|
107181
|
+
},
|
|
107182
|
+
video,
|
|
107183
|
+
audio,
|
|
107184
|
+
threadCount: 0,
|
|
107185
|
+
outputArgs: []
|
|
107186
|
+
};
|
|
107187
|
+
}
|
|
107188
|
+
//#endregion
|
|
106328
107189
|
//#region src/hksv/fragment-source.ts
|
|
106329
107190
|
/**
|
|
106330
107191
|
* How far back the prebuffer ring reaches.
|
|
@@ -106492,6 +107353,7 @@ var HksvFragmentSource = class {
|
|
|
106492
107353
|
meta: {
|
|
106493
107354
|
brokerId: this.input.source.brokerId,
|
|
106494
107355
|
resolution: `${this.input.source.width}x${this.input.source.height}`,
|
|
107356
|
+
branch: this.input.source.transcode ? "transcode" : "copy",
|
|
106495
107357
|
fragmentMs: this.input.fragmentMs,
|
|
106496
107358
|
audioActive: this.audioActive,
|
|
106497
107359
|
windowMs: PREBUFFER_WINDOW_MS
|
|
@@ -106556,27 +107418,13 @@ var HksvFragmentSource = class {
|
|
|
106556
107418
|
* takes AAC only — which the same measurement priced at 0.4 % of a core.
|
|
106557
107419
|
*/
|
|
106558
107420
|
buildInvocation() {
|
|
106559
|
-
|
|
106560
|
-
|
|
106561
|
-
|
|
106562
|
-
|
|
106563
|
-
|
|
106564
|
-
|
|
106565
|
-
}
|
|
106566
|
-
return {
|
|
106567
|
-
logLevel: "error",
|
|
106568
|
-
decodeHwAccel: null,
|
|
106569
|
-
input: {
|
|
106570
|
-
url: this.audioActive ? this.input.source.url : this.input.source.mutedUrl,
|
|
106571
|
-
rtspTransport: "tcp",
|
|
106572
|
-
analyzeDurationUs: 1e6,
|
|
106573
|
-
probeSizeBytes: 1e6
|
|
106574
|
-
},
|
|
106575
|
-
video: { kind: "copy" },
|
|
106576
|
-
audio,
|
|
106577
|
-
threadCount: 0,
|
|
106578
|
-
outputArgs: []
|
|
106579
|
-
};
|
|
107421
|
+
return buildRecordingInvocation({
|
|
107422
|
+
source: this.input.source,
|
|
107423
|
+
audioActive: this.audioActive,
|
|
107424
|
+
fragmentMs: this.input.fragmentMs,
|
|
107425
|
+
decodeHwAccel: this.input.decodeHwAccel ?? null,
|
|
107426
|
+
...this.input.decodeInputArgs === void 0 ? {} : { decodeInputArgs: this.input.decodeInputArgs }
|
|
107427
|
+
});
|
|
106580
107428
|
}
|
|
106581
107429
|
};
|
|
106582
107430
|
//#endregion
|
|
@@ -106936,74 +107784,6 @@ var HksvRecordingDelegate = class {
|
|
|
106936
107784
|
}
|
|
106937
107785
|
};
|
|
106938
107786
|
//#endregion
|
|
106939
|
-
//#region src/hksv/recording-source.ts
|
|
106940
|
-
/** The tallest frame the recording path will hold in its prebuffer. */
|
|
106941
|
-
var MAX_RECORDING_HEIGHT = 1080;
|
|
106942
|
-
/** HKSV takes H.264 only — AAC audio and H.264 video, no negotiation. */
|
|
106943
|
-
var RECORDABLE_CODEC = "h264";
|
|
106944
|
-
/**
|
|
106945
|
-
* Pick the slot the recording child pulls.
|
|
106946
|
-
*
|
|
106947
|
-
* Deliberately NOT `pickPreferredRtspEntry`: that picker resolves the operator's
|
|
106948
|
-
* LIVE preference and, on `auto`, steers by the resolution iOS negotiated for a
|
|
106949
|
-
* live session — neither is a fact about recording, and on 615 it selects `mid`,
|
|
106950
|
-
* a 10 fps slot. Recording has one criterion, applied here and nowhere else:
|
|
106951
|
-
* the largest copyable frame that does not exceed {@link MAX_RECORDING_HEIGHT}.
|
|
106952
|
-
*/
|
|
106953
|
-
function pickRecordingSource(entries) {
|
|
106954
|
-
const enabled = entries.filter((e) => e.enabled);
|
|
106955
|
-
if (enabled.length === 0) return {
|
|
106956
|
-
ok: false,
|
|
106957
|
-
refusal: "no-enabled-stream"
|
|
106958
|
-
};
|
|
106959
|
-
const h264 = enabled.filter((e) => normaliseCodec(e.codec) === RECORDABLE_CODEC);
|
|
106960
|
-
if (h264.length === 0) return {
|
|
106961
|
-
ok: false,
|
|
106962
|
-
refusal: "no-h264-stream"
|
|
106963
|
-
};
|
|
106964
|
-
const sized = h264.filter(hasUsableResolution);
|
|
106965
|
-
if (sized.length === 0) return {
|
|
106966
|
-
ok: false,
|
|
106967
|
-
refusal: "no-resolution"
|
|
106968
|
-
};
|
|
106969
|
-
const withinCeiling = sized.filter((e) => height(e) <= MAX_RECORDING_HEIGHT);
|
|
106970
|
-
const best = [...withinCeiling.length > 0 ? withinCeiling : sized].sort((a, b) => withinCeiling.length > 0 ? height(b) - height(a) : height(a) - height(b))[0];
|
|
106971
|
-
if (best === void 0 || best.resolution === void 0) return {
|
|
106972
|
-
ok: false,
|
|
106973
|
-
refusal: "no-resolution"
|
|
106974
|
-
};
|
|
106975
|
-
return {
|
|
106976
|
-
ok: true,
|
|
106977
|
-
source: {
|
|
106978
|
-
brokerId: best.brokerId,
|
|
106979
|
-
profile: best.profile ?? best.brokerId,
|
|
106980
|
-
url: best.url,
|
|
106981
|
-
mutedUrl: best.mutedUrl,
|
|
106982
|
-
width: best.resolution.width,
|
|
106983
|
-
height: best.resolution.height
|
|
106984
|
-
}
|
|
106985
|
-
};
|
|
106986
|
-
}
|
|
106987
|
-
/** A one-line reason for the log — silence about a withdrawn service reads as a bug. */
|
|
106988
|
-
function refusalReason(refusal) {
|
|
106989
|
-
switch (refusal) {
|
|
106990
|
-
case "no-enabled-stream": return "the camera has no enabled RTSP profile";
|
|
106991
|
-
case "no-h264-stream": return "every enabled profile is H.265 — HKSV takes H.264 only, and a permanent transcode costs 128x a copy";
|
|
106992
|
-
case "no-resolution": return "no enabled profile declares a resolution, so nothing honest could be advertised";
|
|
106993
|
-
}
|
|
106994
|
-
}
|
|
106995
|
-
function height(entry) {
|
|
106996
|
-
return entry.resolution?.height ?? 0;
|
|
106997
|
-
}
|
|
106998
|
-
function hasUsableResolution(entry) {
|
|
106999
|
-
const r = entry.resolution;
|
|
107000
|
-
return r !== void 0 && r.width > 0 && r.height > 0;
|
|
107001
|
-
}
|
|
107002
|
-
/** Publishers spell H.265 four ways; the same normalisation the broker uses. */
|
|
107003
|
-
function normaliseCodec(codec) {
|
|
107004
|
-
return (codec ?? "").toLowerCase().replace(/[.\s-]/g, "");
|
|
107005
|
-
}
|
|
107006
|
-
//#endregion
|
|
107007
107787
|
//#region src/hksv/build-recording.ts
|
|
107008
107788
|
/**
|
|
107009
107789
|
* Assemble HomeKit Secure Video for one camera — the ADVERTISEMENT and the
|
|
@@ -107055,7 +107835,7 @@ async function buildHksvRecording(input) {
|
|
|
107055
107835
|
note("profiles-unreadable", "cameraStreams.getProfileRtspEntries could not be read");
|
|
107056
107836
|
return null;
|
|
107057
107837
|
}
|
|
107058
|
-
const choice = pickRecordingSource(entries);
|
|
107838
|
+
const choice = pickRecordingSource(entries, { allowTranscode: bctx.options.hapDeviceSettings?.allowTranscode !== false });
|
|
107059
107839
|
if (!choice.ok) {
|
|
107060
107840
|
log.info("export-hap: HKSV withheld — no recordable stream", { meta: {
|
|
107061
107841
|
refusal: choice.refusal,
|
|
@@ -107065,9 +107845,10 @@ async function buildHksvRecording(input) {
|
|
|
107065
107845
|
return null;
|
|
107066
107846
|
}
|
|
107067
107847
|
const source = choice.source;
|
|
107848
|
+
const decodeHwAccel = source.transcode ? await resolveDecodeHwAccel(bctx, log) : null;
|
|
107068
107849
|
const gopMs = await readSourceGopMs(bctx, source.width, source.height);
|
|
107069
|
-
const fragmentLengthMs = deriveFragmentLengthMs(gopMs);
|
|
107070
|
-
if (fragmentLengthMs === null) {
|
|
107850
|
+
const fragmentLengthMs = source.transcode ? HKSV_FRAGMENT_LENGTHS_MS[0] : deriveFragmentLengthMs(gopMs);
|
|
107851
|
+
if (fragmentLengthMs === void 0 || fragmentLengthMs === null) {
|
|
107071
107852
|
log.warn("export-hap: HKSV withheld — the camera key-frame interval is longer than any fragment length we advertise", { meta: {
|
|
107072
107853
|
gopMs,
|
|
107073
107854
|
brokerId: source.brokerId
|
|
@@ -107078,9 +107859,10 @@ async function buildHksvRecording(input) {
|
|
|
107078
107859
|
const parsedProfile = CamProfileSchema.safeParse(source.profile);
|
|
107079
107860
|
const recordedProfile = parsedProfile.success ? parsedProfile.data : null;
|
|
107080
107861
|
const fps = resolveFps(input.fpsByProfile, source.profile);
|
|
107862
|
+
const out = recordingOutput(source);
|
|
107081
107863
|
const options = buildRecordingOptions({
|
|
107082
|
-
width:
|
|
107083
|
-
height:
|
|
107864
|
+
width: out.width,
|
|
107865
|
+
height: out.height,
|
|
107084
107866
|
fps,
|
|
107085
107867
|
fragmentLengthMs
|
|
107086
107868
|
});
|
|
@@ -107090,8 +107872,8 @@ async function buildHksvRecording(input) {
|
|
|
107090
107872
|
logger: log,
|
|
107091
107873
|
deviceId: numericDeviceId,
|
|
107092
107874
|
store: clipStore,
|
|
107093
|
-
width:
|
|
107094
|
-
height:
|
|
107875
|
+
width: out.width,
|
|
107876
|
+
height: out.height,
|
|
107095
107877
|
fragmentMs: fragmentLengthMs,
|
|
107096
107878
|
...recordedProfile === null ? {} : { profile: recordedProfile }
|
|
107097
107879
|
});
|
|
@@ -107110,14 +107892,21 @@ async function buildHksvRecording(input) {
|
|
|
107110
107892
|
spawnFn: spawn,
|
|
107111
107893
|
source,
|
|
107112
107894
|
fragmentMs,
|
|
107113
|
-
audioActive
|
|
107895
|
+
audioActive,
|
|
107896
|
+
decodeHwAccel: decodeHwAccel?.hwaccel ?? null,
|
|
107897
|
+
...decodeHwAccel === null || decodeHwAccel.extraInputArgs.length === 0 ? {} : { decodeInputArgs: decodeHwAccel.extraInputArgs }
|
|
107114
107898
|
})
|
|
107115
107899
|
});
|
|
107116
107900
|
const advertisedResolution = options.video.resolutions[0];
|
|
107117
107901
|
log.info("export-hap: HKSV ADVERTISED — recording is offered for this camera", { meta: {
|
|
107118
107902
|
brokerId: source.brokerId,
|
|
107119
107903
|
profile: source.profile,
|
|
107120
|
-
resolution: `${
|
|
107904
|
+
resolution: `${out.width}x${out.height}`,
|
|
107905
|
+
branch: source.transcode ? "transcode" : "copy",
|
|
107906
|
+
...source.transcode ? {
|
|
107907
|
+
sourceResolution: `${source.width}x${source.height}`,
|
|
107908
|
+
decodeHwAccel: decodeHwAccel?.hwaccel ?? "software"
|
|
107909
|
+
} : {},
|
|
107121
107910
|
measuredFps: fps,
|
|
107122
107911
|
advertisedFps: advertisedResolution?.[2] ?? null,
|
|
107123
107912
|
fragmentLengthMs,
|
|
@@ -107132,6 +107921,27 @@ async function buildHksvRecording(input) {
|
|
|
107132
107921
|
dispose: () => delegate.dispose()
|
|
107133
107922
|
};
|
|
107134
107923
|
}
|
|
107924
|
+
/**
|
|
107925
|
+
* The `-hwaccel` value for a transcoding prebuffer, and the flags that travel
|
|
107926
|
+
* with it.
|
|
107927
|
+
*
|
|
107928
|
+
* Software is a legitimate answer and is always NAMED: a camera that quietly
|
|
107929
|
+
* stopped using the GPU and one that never had it look identical in a CPU
|
|
107930
|
+
* graph, and on this branch the difference is most of a core, permanently.
|
|
107931
|
+
*/
|
|
107932
|
+
async function resolveDecodeHwAccel(bctx, log) {
|
|
107933
|
+
const decision = selectHwDecode({
|
|
107934
|
+
transcode: true,
|
|
107935
|
+
reading: await probeDecoderHwaccel({
|
|
107936
|
+
source: decoderInfoSourceFromContext(bctx.ctx),
|
|
107937
|
+
log,
|
|
107938
|
+
memo: bctx.options.decodeMemos.reading
|
|
107939
|
+
}),
|
|
107940
|
+
platform: process.platform
|
|
107941
|
+
});
|
|
107942
|
+
if (decision.kind === "software") log.warn("export-hap: HKSV will transcode in SOFTWARE — this costs most of a core, permanently", { meta: { reason: decision.reason } });
|
|
107943
|
+
return decision;
|
|
107944
|
+
}
|
|
107135
107945
|
/** `cameraStreams.getProfileRtspEntries`, or `null` when the cap is unreachable. */
|
|
107136
107946
|
async function readProfileEntries(bctx) {
|
|
107137
107947
|
try {
|
|
@@ -108127,13 +108937,12 @@ async function buildCameraAccessory(input) {
|
|
|
108127
108937
|
bctx,
|
|
108128
108938
|
streamingOptions: streams.streamingOptions
|
|
108129
108939
|
}));
|
|
108130
|
-
const recordingEnabled = options.hapDeviceSettings.hksvRecording === true;
|
|
108131
108940
|
let recordingAudioActive = true;
|
|
108132
|
-
const recording =
|
|
108941
|
+
const recording = await buildHksvRecording({
|
|
108133
108942
|
bctx,
|
|
108134
108943
|
fpsByProfile: advertisedVideo.fpsByProfile,
|
|
108135
108944
|
isAudioActive: () => recordingAudioActive
|
|
108136
|
-
})
|
|
108945
|
+
});
|
|
108137
108946
|
const controller = new (isDoorbell ? import_dist.DoorbellController : import_dist.CameraController)({
|
|
108138
108947
|
delegate: streams.delegate,
|
|
108139
108948
|
streamingOptions: streams.streamingOptions,
|
|
@@ -108382,38 +109191,7 @@ function syncStateToJson(map) {
|
|
|
108382
109191
|
* that matters about it: it must resolve to NOT recording, or "off by default"
|
|
108383
109192
|
* is true only for cameras exposed before the flip.
|
|
108384
109193
|
*/
|
|
108385
|
-
var DEFAULT_DEVICE_SETTINGS = {
|
|
108386
|
-
streamPreference: "auto",
|
|
108387
|
-
hksvRecording: false
|
|
108388
|
-
};
|
|
108389
|
-
/**
|
|
108390
|
-
* OFF unless explicitly switched on — operator decision 2026-09-21, reversing
|
|
108391
|
-
* the 2026-08-08 flip:
|
|
108392
|
-
*
|
|
108393
|
-
* > *"il recording deve essere off di default, non deve essere attivo quando
|
|
108394
|
-
* > si esporta una camera su HKSV"*
|
|
108395
|
-
*
|
|
108396
|
-
* What changed is not the cost the earlier record argued about — recording on
|
|
108397
|
-
* the copy branch really is 0.7 % of a core and ~30 MB (D84), and cheap it
|
|
108398
|
-
* remains. What changed is that on-by-default made the switch **say something
|
|
108399
|
-
* the system was not doing**. Measured on 2026-09-21: 592, 587, 618 and 640
|
|
108400
|
-
* all reported HomeKit recording ON while the advertisement was WITHHELD
|
|
108401
|
-
* (`no-enabled-stream` — no enabled RTSP profile), so HomeKit never recorded
|
|
108402
|
-
* them and the tee had nothing to keep. The operator was being told four
|
|
108403
|
-
* cameras were recording because nobody had turned them off.
|
|
108404
|
-
*
|
|
108405
|
-
* Exposing a camera to HomeKit is a decision about EXPOSURE. Recording is a
|
|
108406
|
-
* second decision and now has to be made.
|
|
108407
|
-
*
|
|
108408
|
-
* ABSENT resolves OFF — the load-bearing case, for the same reason it was
|
|
108409
|
-
* before and with the opposite answer: a camera whose settings predate the
|
|
108410
|
-
* field, or that was exposed before today, was never asked about. Every read
|
|
108411
|
-
* goes through this one resolver (`=== true`), never a scattered `!== false`,
|
|
108412
|
-
* because those two disagree about exactly that case.
|
|
108413
|
-
*/
|
|
108414
|
-
function resolveHksvRecording(settings) {
|
|
108415
|
-
return settings?.hksvRecording === true;
|
|
108416
|
-
}
|
|
109194
|
+
var DEFAULT_DEVICE_SETTINGS = { streamPreference: "auto" };
|
|
108417
109195
|
/**
|
|
108418
109196
|
* Whether this camera offers Apple's NEW camera service alongside the classic
|
|
108419
109197
|
* one — `camera-multi-tier-rtp-stream-management` (0x8031), where HEVC and 4K
|
|
@@ -108456,11 +109234,11 @@ var EXPORT_HAP_ADDON_ID = "export-hap";
|
|
|
108456
109234
|
* stays and says the copies are off, which is D62's other half: an off switch
|
|
108457
109235
|
* is REPORTED off, never made to look like a broken camera.
|
|
108458
109236
|
*/
|
|
108459
|
-
function describeHksvCamera(entry, lastBuild) {
|
|
109237
|
+
function describeHksvCamera(entry, lastBuild, homekitRecording) {
|
|
108460
109238
|
const isCamera = entry !== null && entry.mapperKind === "camera";
|
|
108461
109239
|
return {
|
|
108462
109240
|
exported: isCamera,
|
|
108463
|
-
|
|
109241
|
+
homekitRecording: isCamera ? homekitRecording : null,
|
|
108464
109242
|
keepingClips: isCamera && resolveKeepHomekitClips(entry.settings),
|
|
108465
109243
|
lastBuild
|
|
108466
109244
|
};
|
|
@@ -108704,7 +109482,7 @@ var ExportHapAddon = class extends BaseAddon {
|
|
|
108704
109482
|
const clipsProvider = createHksvVideoclipsProvider({
|
|
108705
109483
|
logger: this.ctx.logger.child("hksv-clips"),
|
|
108706
109484
|
addonId: EXPORT_HAP_ADDON_ID,
|
|
108707
|
-
describeCamera: (deviceId) => describeHksvCamera(this.findEntry(deviceId), this.hksvBuilds.lastFor(deviceId)),
|
|
109485
|
+
describeCamera: (deviceId) => describeHksvCamera(this.findEntry(deviceId), this.hksvBuilds.lastFor(deviceId), readHomekitRecordingActive(this.exposed.get(String(deviceId))?.accessories ?? [])),
|
|
108708
109486
|
readCatalog: async (deviceId) => await this.hksvClipStore?.listCatalog(deviceId) ?? { kind: "no-root" },
|
|
108709
109487
|
locationRefusal: () => this.hksvClipLocation?.lastRefusal ?? null,
|
|
108710
109488
|
mediaUrl: (deviceId, stem) => this.hksvClipUrl("media", deviceId, stem),
|
|
@@ -108860,7 +109638,6 @@ var ExportHapAddon = class extends BaseAddon {
|
|
|
108860
109638
|
},
|
|
108861
109639
|
hapDeviceSettings: {
|
|
108862
109640
|
streamPreference: entrySettings.streamPreference ?? "auto",
|
|
108863
|
-
hksvRecording: resolveHksvRecording(entrySettings),
|
|
108864
109641
|
keepHomekitClips: resolveKeepHomekitClips(entrySettings),
|
|
108865
109642
|
multiTierService: resolveMultiTierService(entrySettings),
|
|
108866
109643
|
allowTranscode: entrySettings.allowTranscode !== false
|
|
@@ -108941,15 +109718,40 @@ var ExportHapAddon = class extends BaseAddon {
|
|
|
108941
109718
|
features: device.features
|
|
108942
109719
|
});
|
|
108943
109720
|
const persisted = syncStateFromJson(this.config.exportSyncState).get(deviceId)?.fingerprint;
|
|
109721
|
+
const withToken = withRecordabilityToken({
|
|
109722
|
+
base: fresh,
|
|
109723
|
+
token: await this.readRecordabilityToken(deviceId, device.type),
|
|
109724
|
+
persisted
|
|
109725
|
+
});
|
|
108944
109726
|
return resolveExportFingerprint({
|
|
108945
109727
|
ready: device.probed ?? false,
|
|
108946
|
-
fresh,
|
|
109728
|
+
fresh: withToken,
|
|
108947
109729
|
persisted
|
|
108948
109730
|
});
|
|
108949
109731
|
} catch {
|
|
108950
109732
|
return null;
|
|
108951
109733
|
}
|
|
108952
109734
|
}
|
|
109735
|
+
/**
|
|
109736
|
+
* The slot HKSV would record this camera from, for the fingerprint.
|
|
109737
|
+
*
|
|
109738
|
+
* `null` — do not move the fingerprint — for anything that is not a camera
|
|
109739
|
+
* (a switch has no recording decision, and stamping a constant on it would
|
|
109740
|
+
* republish every non-camera accessory once for nothing) and for a camera
|
|
109741
|
+
* whose profiles could not be read right now.
|
|
109742
|
+
*/
|
|
109743
|
+
async readRecordabilityToken(deviceId, type) {
|
|
109744
|
+
if (pickMapperKind(type) !== "camera") return null;
|
|
109745
|
+
try {
|
|
109746
|
+
const entries = await (await this.ctx.fetchDevice(deviceId)).cameraStreams?.getProfileRtspEntries({});
|
|
109747
|
+
return recordabilityTokenFor({
|
|
109748
|
+
allowTranscode: this.findEntry(deviceId)?.settings?.allowTranscode !== false,
|
|
109749
|
+
entries: entries ?? null
|
|
109750
|
+
});
|
|
109751
|
+
} catch {
|
|
109752
|
+
return null;
|
|
109753
|
+
}
|
|
109754
|
+
}
|
|
108953
109755
|
/** Persist a device's current export fingerprint into `exportSyncState`
|
|
108954
109756
|
* (best-effort; called after a successful attach). */
|
|
108955
109757
|
async persistFingerprint(deviceId, fingerprint) {
|
|
@@ -109215,7 +110017,6 @@ var ExportHapAddon = class extends BaseAddon {
|
|
|
109215
110017
|
const enabled = entry !== null;
|
|
109216
110018
|
const enabledKey = `hap:${deviceId}:enabled`;
|
|
109217
110019
|
const streamPreferenceKey = `hap:${deviceId}:streamPreference`;
|
|
109218
|
-
const hksvKey = `hap:${deviceId}:hksvRecording`;
|
|
109219
110020
|
const multiTierKey = `hap:${deviceId}:multiTierService`;
|
|
109220
110021
|
const useBridgeKey = `hap:${deviceId}:useBridge`;
|
|
109221
110022
|
const allowTranscodeKey = `hap:${deviceId}:allowTranscode`;
|
|
@@ -109266,17 +110067,14 @@ var ExportHapAddon = class extends BaseAddon {
|
|
|
109266
110067
|
immediate: true
|
|
109267
110068
|
},
|
|
109268
110069
|
{
|
|
109269
|
-
type: "
|
|
109270
|
-
key:
|
|
110070
|
+
type: "info",
|
|
110071
|
+
key: `hap:${deviceId}:hksvRecordingStatus`,
|
|
109271
110072
|
label: "HomeKit recording (Secure Video)",
|
|
109272
|
-
|
|
109273
|
-
style: "switch",
|
|
109274
|
-
value: resolveHksvRecording(settings),
|
|
110073
|
+
content: describeHomekitRecording(readHomekitRecordingActive(this.exposed.get(String(deviceId))?.accessories ?? []), this.hksvBuilds.lastFor(deviceId)),
|
|
109275
110074
|
showWhen: {
|
|
109276
110075
|
field: enabledKey,
|
|
109277
110076
|
equals: true
|
|
109278
|
-
}
|
|
109279
|
-
immediate: true
|
|
110077
|
+
}
|
|
109280
110078
|
},
|
|
109281
110079
|
{
|
|
109282
110080
|
type: "boolean",
|
|
@@ -109299,7 +110097,7 @@ var ExportHapAddon = class extends BaseAddon {
|
|
|
109299
110097
|
style: "switch",
|
|
109300
110098
|
value: resolveKeepHomekitClips(settings),
|
|
109301
110099
|
showWhen: {
|
|
109302
|
-
field:
|
|
110100
|
+
field: enabledKey,
|
|
109303
110101
|
equals: true
|
|
109304
110102
|
},
|
|
109305
110103
|
immediate: true
|
|
@@ -109399,7 +110197,6 @@ var ExportHapAddon = class extends BaseAddon {
|
|
|
109399
110197
|
const wasEnabled = this.exposed.has(deviceIdStr);
|
|
109400
110198
|
const enabledKey = `hap:${deviceId}:enabled`;
|
|
109401
110199
|
const streamPreferenceKey = `hap:${deviceId}:streamPreference`;
|
|
109402
|
-
const hksvKey = `hap:${deviceId}:hksvRecording`;
|
|
109403
110200
|
const useBridgeKey = `hap:${deviceId}:useBridge`;
|
|
109404
110201
|
const allowTranscodeKey = `hap:${deviceId}:allowTranscode`;
|
|
109405
110202
|
const multiTierKey = `hap:${deviceId}:multiTierService`;
|
|
@@ -109408,7 +110205,6 @@ var ExportHapAddon = class extends BaseAddon {
|
|
|
109408
110205
|
const enabledValue = enabledKey in patch ? Boolean(patch[enabledKey]) : wasEnabled;
|
|
109409
110206
|
const streamPreferenceRaw = streamPreferenceKey in patch ? patch[streamPreferenceKey] : current?.settings?.streamPreference;
|
|
109410
110207
|
const streamPreference = typeof streamPreferenceRaw === "string" && streamPreferenceRaw.trim().length > 0 ? streamPreferenceRaw : "auto";
|
|
109411
|
-
const hksvRecording = hksvKey in patch ? Boolean(patch[hksvKey]) : resolveHksvRecording(current?.settings);
|
|
109412
110208
|
const useBridge = useBridgeKey in patch ? Boolean(patch[useBridgeKey]) : current?.settings?.useBridge !== false;
|
|
109413
110209
|
const allowTranscode = allowTranscodeKey in patch ? Boolean(patch[allowTranscodeKey]) : current?.settings?.allowTranscode !== false;
|
|
109414
110210
|
const multiTierService = multiTierKey in patch ? Boolean(patch[multiTierKey]) : resolveMultiTierService(current?.settings);
|
|
@@ -109420,7 +110216,6 @@ var ExportHapAddon = class extends BaseAddon {
|
|
|
109420
110216
|
const nextSettings = {
|
|
109421
110217
|
...current?.settings ?? DEFAULT_DEVICE_SETTINGS,
|
|
109422
110218
|
streamPreference,
|
|
109423
|
-
hksvRecording,
|
|
109424
110219
|
useBridge,
|
|
109425
110220
|
allowTranscode,
|
|
109426
110221
|
multiTierService,
|
|
@@ -109437,7 +110232,6 @@ var ExportHapAddon = class extends BaseAddon {
|
|
|
109437
110232
|
return { success: true };
|
|
109438
110233
|
}
|
|
109439
110234
|
const currentPref = current?.settings?.streamPreference ?? "auto";
|
|
109440
|
-
const currentHksv = resolveHksvRecording(current?.settings);
|
|
109441
110235
|
const currentKeepClips = resolveKeepHomekitClips(current?.settings);
|
|
109442
110236
|
const mapperKind = current?.mapperKind ?? "generic";
|
|
109443
110237
|
const wasBridged = shouldBridge({
|
|
@@ -109449,16 +110243,12 @@ var ExportHapAddon = class extends BaseAddon {
|
|
|
109449
110243
|
useBridge
|
|
109450
110244
|
});
|
|
109451
110245
|
await this.updateEntrySettings(deviceIdStr, nextSettings);
|
|
109452
|
-
if (currentPref !== streamPreference ||
|
|
110246
|
+
if (currentPref !== streamPreference || currentKeepClips !== keepClips || wasBridged !== willBridge) {
|
|
109453
110247
|
log.info("export-hap: per-camera export settings changed — refreshing accessory", { meta: {
|
|
109454
110248
|
streamPreference: {
|
|
109455
110249
|
from: currentPref,
|
|
109456
110250
|
to: streamPreference
|
|
109457
110251
|
},
|
|
109458
|
-
hksvRecording: {
|
|
109459
|
-
from: currentHksv,
|
|
109460
|
-
to: hksvRecording
|
|
109461
|
-
},
|
|
109462
110252
|
keepClips: {
|
|
109463
110253
|
from: currentKeepClips,
|
|
109464
110254
|
to: keepClips
|
|
@@ -109544,4 +110334,4 @@ function errMsg(err) {
|
|
|
109544
110334
|
return err instanceof Error ? err.message : String(err);
|
|
109545
110335
|
}
|
|
109546
110336
|
//#endregion
|
|
109547
|
-
export { DEFAULT_CLIP_RETENTION_DAYS, DEFAULT_DEVICE_SETTINGS, EXPORT_HAP_ADDON_ID, ExportHapAddon, ExportHapAddon as default, describeHksvCamera, unpublishAccessory as i, initHapStorage as n, publishStandalone as r, resolveClipRetentionDays,
|
|
110337
|
+
export { DEFAULT_CLIP_RETENTION_DAYS, DEFAULT_DEVICE_SETTINGS, EXPORT_HAP_ADDON_ID, ExportHapAddon, ExportHapAddon as default, describeHksvCamera, unpublishAccessory as i, initHapStorage as n, publishStandalone as r, resolveClipRetentionDays, resolveKeepHomekitClips, resolveMultiTierService, deriveUsername as t };
|