@camstack/addon-provider-dreame 0.2.153 → 0.2.154
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/addon.js +442 -64
- package/dist/addon.mjs +442 -64
- package/package.json +1 -1
package/dist/addon.js
CHANGED
|
@@ -8874,7 +8874,7 @@ function errMsg(err) {
|
|
|
8874
8874
|
return String(err);
|
|
8875
8875
|
}
|
|
8876
8876
|
//#endregion
|
|
8877
|
-
//#region ../types/dist/composition-
|
|
8877
|
+
//#region ../types/dist/composition-BJ8iAZb3.mjs
|
|
8878
8878
|
/**
|
|
8879
8879
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
8880
8880
|
*
|
|
@@ -8934,7 +8934,7 @@ portable("linux64"), portable("linuxarm64"), portable("macarm64"), portable("mac
|
|
|
8934
8934
|
* ONE table for everyone who asks "is this device HIGH?": the
|
|
8935
8935
|
* recorder's `RecordingTriggers.sensorDeviceIds` trigger, the post-analysis
|
|
8936
8936
|
* sensor markers, the orchestrator's camera-sensors bridge and
|
|
8937
|
-
* the sources of a
|
|
8937
|
+
* the sources of a pulse (`compilePulseOverride`, D936).
|
|
8938
8938
|
* A second copy would diverge at the first cap added, and the symptom — "the
|
|
8939
8939
|
* sensor rings the doorbell but does not record" — is exactly D62.
|
|
8940
8940
|
*
|
|
@@ -54401,20 +54401,68 @@ var BatteryStatusSchema = object({
|
|
|
54401
54401
|
*/
|
|
54402
54402
|
binary: boolean().optional()
|
|
54403
54403
|
});
|
|
54404
|
+
var BATTERY_DEVICE_TYPES = [
|
|
54405
|
+
DeviceType.Camera,
|
|
54406
|
+
DeviceType.Sensor,
|
|
54407
|
+
DeviceType.Button,
|
|
54408
|
+
DeviceType.Switch,
|
|
54409
|
+
DeviceType.PetFeeder,
|
|
54410
|
+
DeviceType.Container,
|
|
54411
|
+
DeviceType.Thermostat
|
|
54412
|
+
];
|
|
54413
|
+
/** Generic Customize target for the percentage reading (D936). */
|
|
54414
|
+
var batteryCustomize = {
|
|
54415
|
+
version: 1,
|
|
54416
|
+
targets: [{
|
|
54417
|
+
id: "percentage",
|
|
54418
|
+
cardinality: "scalar",
|
|
54419
|
+
vocabulary: {
|
|
54420
|
+
cap: "battery",
|
|
54421
|
+
stateField: "percentage"
|
|
54422
|
+
},
|
|
54423
|
+
deviceTypes: BATTERY_DEVICE_TYPES,
|
|
54424
|
+
apply: "add-or-replace",
|
|
54425
|
+
path: "percentage",
|
|
54426
|
+
sources: [{
|
|
54427
|
+
kind: "field",
|
|
54428
|
+
valueKinds: ["number", "string"],
|
|
54429
|
+
transforms: [{ kind: "identity" }, {
|
|
54430
|
+
kind: "linear",
|
|
54431
|
+
defaultScale: 1,
|
|
54432
|
+
defaultOffset: 0,
|
|
54433
|
+
clampMin: 0,
|
|
54434
|
+
clampMax: 100
|
|
54435
|
+
}]
|
|
54436
|
+
}],
|
|
54437
|
+
companions: [
|
|
54438
|
+
{
|
|
54439
|
+
kind: "constant",
|
|
54440
|
+
path: "charging",
|
|
54441
|
+
value: "unknown",
|
|
54442
|
+
when: "add"
|
|
54443
|
+
},
|
|
54444
|
+
{
|
|
54445
|
+
kind: "constant",
|
|
54446
|
+
path: "sleeping",
|
|
54447
|
+
value: false,
|
|
54448
|
+
when: "add"
|
|
54449
|
+
},
|
|
54450
|
+
{
|
|
54451
|
+
kind: "clock",
|
|
54452
|
+
path: "lastUpdated",
|
|
54453
|
+
when: "add"
|
|
54454
|
+
}
|
|
54455
|
+
],
|
|
54456
|
+
sourceReport: { status: "assignment-status" },
|
|
54457
|
+
advancedExpression: true
|
|
54458
|
+
}]
|
|
54459
|
+
};
|
|
54404
54460
|
var batteryCapability = {
|
|
54405
54461
|
name: "battery",
|
|
54406
54462
|
scope: "device",
|
|
54407
54463
|
deviceNative: true,
|
|
54408
54464
|
mode: "singleton",
|
|
54409
|
-
deviceTypes:
|
|
54410
|
-
DeviceType.Camera,
|
|
54411
|
-
DeviceType.Sensor,
|
|
54412
|
-
DeviceType.Button,
|
|
54413
|
-
DeviceType.Switch,
|
|
54414
|
-
DeviceType.PetFeeder,
|
|
54415
|
-
DeviceType.Container,
|
|
54416
|
-
DeviceType.Thermostat
|
|
54417
|
-
],
|
|
54465
|
+
deviceTypes: BATTERY_DEVICE_TYPES,
|
|
54418
54466
|
methods: {
|
|
54419
54467
|
/**
|
|
54420
54468
|
* Explicitly wake the camera from low-power sleep ahead of a
|
|
@@ -54498,6 +54546,7 @@ onStatusChanged: { data: object({
|
|
|
54498
54546
|
kind: "gauge",
|
|
54499
54547
|
unit: "%"
|
|
54500
54548
|
} } },
|
|
54549
|
+
customize: batteryCustomize,
|
|
54501
54550
|
/** Clock fields: written, but excluded from the compare that decides
|
|
54502
54551
|
* whether persisting is worth a SQLite commit. */
|
|
54503
54552
|
volatileStateFields: ["lastUpdated"]
|
|
@@ -55487,6 +55536,106 @@ var ConsumablesStatusSchema = object({
|
|
|
55487
55536
|
items: array(ConsumableItemSchema),
|
|
55488
55537
|
lastChangedAt: number()
|
|
55489
55538
|
});
|
|
55539
|
+
/** Synthesize seed for a link-built status (no native provider).
|
|
55540
|
+
*
|
|
55541
|
+
* ⚠ NO LIVE CALLER since 2026-08-08 (device-links deleted; see
|
|
55542
|
+
* `CapabilityStatusSchema.empty`). The wiring guidance below was written for
|
|
55543
|
+
* exactly the case the operator is asking about again — a Dreame's HA
|
|
55544
|
+
* consumable-life sensors — so it is kept for that conversation, not because
|
|
55545
|
+
* anything reads it today. */
|
|
55546
|
+
var EMPTY_STATUS = {
|
|
55547
|
+
items: [],
|
|
55548
|
+
lastChangedAt: 0
|
|
55549
|
+
};
|
|
55550
|
+
/** Seed for a NEW link-built consumable item. `key`/`label` are overwritten
|
|
55551
|
+
* with the link's `itemKey` (see `status.itemArray`), so the placeholder
|
|
55552
|
+
* empty strings never survive into a validated item. Link-built items are
|
|
55553
|
+
* not resettable — there is no native provider to receive `reset()`.
|
|
55554
|
+
*
|
|
55555
|
+
* Wiring guidance (HA vacuum consumable-life sensors):
|
|
55556
|
+
* - a percent-remaining source (`numeric-sensor`, unit '%') → `level` via
|
|
55557
|
+
* `identity` (or `linear` scale 1 offset 0 clamp [0,100] to be safe);
|
|
55558
|
+
* - an hours-remaining source (e.g. Dreame 'Main Brush Time Left', unit 'h')
|
|
55559
|
+
* → `level` via `linear` with scale = 100 / max-hours for that item
|
|
55560
|
+
* (e.g. main brush 300 h → scale 0.3333) + clamp [0,100];
|
|
55561
|
+
* - a discrete source (`enum-sensor`, e.g. mop pad 'installed') → `status`
|
|
55562
|
+
* via `enum-map` (e.g. { installed: 'ok', missing: 'replace' }).
|
|
55563
|
+
* A numeric→'replace' THRESHOLD (level < 10 → 'replace') is NOT expressible
|
|
55564
|
+
* with the current transform kinds — leave `status` null (valid) until the
|
|
55565
|
+
* expression transform lands. */
|
|
55566
|
+
/** Generic Customize target for one consumable item (D936). Native rows stay read-only. */
|
|
55567
|
+
var consumablesCustomize = {
|
|
55568
|
+
version: 1,
|
|
55569
|
+
targets: [{
|
|
55570
|
+
id: "items",
|
|
55571
|
+
cardinality: "keyedArray",
|
|
55572
|
+
vocabulary: { cap: "consumables" },
|
|
55573
|
+
deviceTypes: Object.values(DeviceType),
|
|
55574
|
+
apply: "add",
|
|
55575
|
+
path: "items",
|
|
55576
|
+
keyField: "key",
|
|
55577
|
+
labelField: "label",
|
|
55578
|
+
itemSchema: ConsumableItemSchema,
|
|
55579
|
+
nativeItems: "read-only",
|
|
55580
|
+
sourceReport: { status: "assignment-status" },
|
|
55581
|
+
fields: [
|
|
55582
|
+
{
|
|
55583
|
+
path: "level",
|
|
55584
|
+
sources: [{
|
|
55585
|
+
kind: "numeric",
|
|
55586
|
+
transforms: [{ kind: "identity" }, {
|
|
55587
|
+
kind: "linear",
|
|
55588
|
+
defaultScale: 1,
|
|
55589
|
+
defaultOffset: 0,
|
|
55590
|
+
clampMin: 0,
|
|
55591
|
+
clampMax: 100
|
|
55592
|
+
}]
|
|
55593
|
+
}]
|
|
55594
|
+
},
|
|
55595
|
+
{
|
|
55596
|
+
path: "remaining.value",
|
|
55597
|
+
sources: [{
|
|
55598
|
+
kind: "numeric",
|
|
55599
|
+
transforms: [{ kind: "identity" }]
|
|
55600
|
+
}],
|
|
55601
|
+
literals: [{
|
|
55602
|
+
path: "remaining.unit",
|
|
55603
|
+
values: [...ConsumableRemainingUnitSchema.options]
|
|
55604
|
+
}]
|
|
55605
|
+
},
|
|
55606
|
+
{
|
|
55607
|
+
path: "status",
|
|
55608
|
+
sources: [{
|
|
55609
|
+
kind: "enum",
|
|
55610
|
+
transforms: [{
|
|
55611
|
+
kind: "enum-map",
|
|
55612
|
+
outputValues: [...ConsumableStatusSchema.options],
|
|
55613
|
+
unmapped: null
|
|
55614
|
+
}]
|
|
55615
|
+
}]
|
|
55616
|
+
}
|
|
55617
|
+
],
|
|
55618
|
+
traits: [{
|
|
55619
|
+
path: "kind",
|
|
55620
|
+
values: [...ConsumableKindSchema.options],
|
|
55621
|
+
defaultValue: "wear"
|
|
55622
|
+
}, {
|
|
55623
|
+
path: "form",
|
|
55624
|
+
values: [...ConsumableFormSchema.options],
|
|
55625
|
+
defaultValue: "part"
|
|
55626
|
+
}],
|
|
55627
|
+
companions: [{
|
|
55628
|
+
kind: "clock",
|
|
55629
|
+
path: "lastChangedAt",
|
|
55630
|
+
when: "add"
|
|
55631
|
+
}, {
|
|
55632
|
+
kind: "clock",
|
|
55633
|
+
path: "lastFetchedAt",
|
|
55634
|
+
when: "add"
|
|
55635
|
+
}],
|
|
55636
|
+
advancedExpression: true
|
|
55637
|
+
}]
|
|
55638
|
+
};
|
|
55490
55639
|
var consumablesCapability = {
|
|
55491
55640
|
name: "consumables",
|
|
55492
55641
|
scope: "device",
|
|
@@ -55524,10 +55673,7 @@ reset: method(object({
|
|
|
55524
55673
|
status: {
|
|
55525
55674
|
schema: ConsumablesStatusSchema,
|
|
55526
55675
|
kind: "push",
|
|
55527
|
-
empty:
|
|
55528
|
-
items: [],
|
|
55529
|
-
lastChangedAt: 0
|
|
55530
|
-
},
|
|
55676
|
+
empty: EMPTY_STATUS,
|
|
55531
55677
|
itemArray: {
|
|
55532
55678
|
path: "items",
|
|
55533
55679
|
keyField: "key",
|
|
@@ -55563,6 +55709,7 @@ reset: method(object({
|
|
|
55563
55709
|
* brush's remaining life and a dishwasher's salt are each recorded the moment
|
|
55564
55710
|
* their provider reports them; an item that appears later gets its series.
|
|
55565
55711
|
*/
|
|
55712
|
+
customize: consumablesCustomize,
|
|
55566
55713
|
history: {
|
|
55567
55714
|
fields: {},
|
|
55568
55715
|
items: {
|
|
@@ -56305,6 +56452,36 @@ var dishwasherCapability = {
|
|
|
56305
56452
|
powerOn: { kind: "boolean" }
|
|
56306
56453
|
} }
|
|
56307
56454
|
};
|
|
56455
|
+
/** Pulse override: a rising edge advances `lastPressedAt` and the press count. */
|
|
56456
|
+
var doorbellCustomize = {
|
|
56457
|
+
version: 1,
|
|
56458
|
+
targets: [{
|
|
56459
|
+
id: "pressed",
|
|
56460
|
+
cardinality: "event",
|
|
56461
|
+
shape: "pulse",
|
|
56462
|
+
vocabulary: {
|
|
56463
|
+
cap: "doorbell",
|
|
56464
|
+
eventName: "onPressed"
|
|
56465
|
+
},
|
|
56466
|
+
deviceTypes: [DeviceType.Camera],
|
|
56467
|
+
apply: "add",
|
|
56468
|
+
applyAuthority: { kind: "composition-claim" },
|
|
56469
|
+
eventName: "onPressed",
|
|
56470
|
+
edges: ["rising"],
|
|
56471
|
+
timestampPath: "lastPressedAt",
|
|
56472
|
+
counterPath: "pressCountSinceStart",
|
|
56473
|
+
highWater: "composer-advance",
|
|
56474
|
+
combine: "any",
|
|
56475
|
+
debounce: {
|
|
56476
|
+
kind: "rising-edge",
|
|
56477
|
+
defaultDebounceMs: 2e3,
|
|
56478
|
+
changedAtRequired: true
|
|
56479
|
+
},
|
|
56480
|
+
sources: [{ kind: "binary" }, { kind: "switch" }],
|
|
56481
|
+
sourceReport: { status: "assignment-status" },
|
|
56482
|
+
advancedExpression: true
|
|
56483
|
+
}]
|
|
56484
|
+
};
|
|
56308
56485
|
var DoorbellStatusSchema = object({
|
|
56309
56486
|
/** Ms epoch of the last press. null = never observed since this provider started. */
|
|
56310
56487
|
lastPressedAt: number().nullable(),
|
|
@@ -56371,7 +56548,8 @@ onPressed: {
|
|
|
56371
56548
|
/**
|
|
56372
56549
|
* History (D850): none — `pressCountSinceStart` resets with the addon, so it is not a monotonic meter; presses live in the events ledger.
|
|
56373
56550
|
*/
|
|
56374
|
-
history: "none"
|
|
56551
|
+
history: "none",
|
|
56552
|
+
customize: doorbellCustomize
|
|
56375
56553
|
};
|
|
56376
56554
|
/**
|
|
56377
56555
|
* Enum-state sensor — a string value picked from a finite option set.
|
|
@@ -58767,6 +58945,38 @@ authKey: string().optional() }), object({
|
|
|
58767
58945
|
/** Human-readable error when `ok: false`. */
|
|
58768
58946
|
error: string().optional()
|
|
58769
58947
|
}), { kind: "mutation" });
|
|
58948
|
+
/** Span override: start on a rising edge, end on a fall or this timeout. */
|
|
58949
|
+
var motionCustomize = {
|
|
58950
|
+
version: 1,
|
|
58951
|
+
targets: [{
|
|
58952
|
+
id: "detected",
|
|
58953
|
+
cardinality: "event",
|
|
58954
|
+
shape: "span",
|
|
58955
|
+
vocabulary: {
|
|
58956
|
+
cap: "motion",
|
|
58957
|
+
eventName: "onMotionChanged"
|
|
58958
|
+
},
|
|
58959
|
+
deviceTypes: [DeviceType.Camera],
|
|
58960
|
+
apply: "replace",
|
|
58961
|
+
applyAuthority: {
|
|
58962
|
+
kind: "camera-sensors",
|
|
58963
|
+
timeoutField: "motionCooldownMs"
|
|
58964
|
+
},
|
|
58965
|
+
eventName: "onMotionChanged",
|
|
58966
|
+
start: "rising-edge",
|
|
58967
|
+
end: "falling-edge-or-timeout",
|
|
58968
|
+
timeoutMs: 3e4,
|
|
58969
|
+
combine: "any",
|
|
58970
|
+
sourceModes: [
|
|
58971
|
+
"in-addition",
|
|
58972
|
+
"confirm",
|
|
58973
|
+
"replace"
|
|
58974
|
+
],
|
|
58975
|
+
sources: [{ kind: "binary" }, { kind: "switch" }],
|
|
58976
|
+
sourceReport: { status: "assignment-status" },
|
|
58977
|
+
advancedExpression: false
|
|
58978
|
+
}]
|
|
58979
|
+
};
|
|
58770
58980
|
var MotionStatusSchema = object({
|
|
58771
58981
|
detected: boolean(),
|
|
58772
58982
|
/** Ms epoch of the last detected-true observation. Null if never detected. */
|
|
@@ -58906,7 +59116,8 @@ onMotionChanged: { data: MotionOnMotionChangedDataSchema } },
|
|
|
58906
59116
|
history: { fields: { detected: {
|
|
58907
59117
|
kind: "boolean",
|
|
58908
59118
|
excludeDeviceTypes: [DeviceType.Camera]
|
|
58909
|
-
} } }
|
|
59119
|
+
} } },
|
|
59120
|
+
customize: motionCustomize
|
|
58910
59121
|
};
|
|
58911
59122
|
/**
|
|
58912
59123
|
* Motion-trigger toggle for accessory devices.
|
|
@@ -61780,6 +61991,16 @@ var ptzAutotrackCapability = {
|
|
|
61780
61991
|
*/
|
|
61781
61992
|
history: "none"
|
|
61782
61993
|
};
|
|
61994
|
+
var RUNNING_POWER_START_DELAY_MS = 3e4;
|
|
61995
|
+
var RUNNING_POWER_STOP_DELAY_MS = 18e4;
|
|
61996
|
+
/** Before any provider reading — all fields unknown (D933). */
|
|
61997
|
+
var RUNNING_STATE_COLD = {
|
|
61998
|
+
running: null,
|
|
61999
|
+
since: null,
|
|
62000
|
+
source: "native",
|
|
62001
|
+
phase: null,
|
|
62002
|
+
lastFetchedAt: null
|
|
62003
|
+
};
|
|
61783
62004
|
var RunningStateSourceSchema = _enum(["native", "assigned"]);
|
|
61784
62005
|
var RunningStateStatusSchema = object({
|
|
61785
62006
|
/** null = unknown — never coerced to false (D393). */
|
|
@@ -61788,19 +62009,100 @@ var RunningStateStatusSchema = object({
|
|
|
61788
62009
|
since: number().nullable(),
|
|
61789
62010
|
source: RunningStateSourceSchema,
|
|
61790
62011
|
phase: string().nullable(),
|
|
61791
|
-
|
|
62012
|
+
/** null until a reading has been published (D393). */
|
|
62013
|
+
lastFetchedAt: number().nullable()
|
|
61792
62014
|
});
|
|
61793
62015
|
var RunningFlipEventDataSchema = object({
|
|
61794
62016
|
deviceId: number(),
|
|
61795
62017
|
since: number().nullable(),
|
|
61796
62018
|
phase: string().nullable()
|
|
61797
62019
|
});
|
|
62020
|
+
var RUNNING_DEVICE_TYPES = Object.values(DeviceType);
|
|
62021
|
+
/** Generic Customize target for the running boolean (D936). */
|
|
62022
|
+
var runningCustomize = {
|
|
62023
|
+
version: 1,
|
|
62024
|
+
targets: [{
|
|
62025
|
+
id: "running",
|
|
62026
|
+
cardinality: "scalar",
|
|
62027
|
+
vocabulary: {
|
|
62028
|
+
cap: "running-state",
|
|
62029
|
+
stateField: "running"
|
|
62030
|
+
},
|
|
62031
|
+
deviceTypes: [
|
|
62032
|
+
DeviceType.Dishwasher,
|
|
62033
|
+
DeviceType.Vacuum,
|
|
62034
|
+
DeviceType.LawnMower,
|
|
62035
|
+
DeviceType.MediaPlayer,
|
|
62036
|
+
DeviceType.WaterHeater,
|
|
62037
|
+
DeviceType.Humidifier,
|
|
62038
|
+
DeviceType.Fan,
|
|
62039
|
+
DeviceType.Climate,
|
|
62040
|
+
DeviceType.Thermostat,
|
|
62041
|
+
DeviceType.PetFeeder
|
|
62042
|
+
],
|
|
62043
|
+
apply: "add-or-replace",
|
|
62044
|
+
path: "running",
|
|
62045
|
+
sources: [
|
|
62046
|
+
{
|
|
62047
|
+
kind: "switch",
|
|
62048
|
+
transforms: [{ kind: "identity" }]
|
|
62049
|
+
},
|
|
62050
|
+
{
|
|
62051
|
+
kind: "binary",
|
|
62052
|
+
transforms: [{ kind: "identity" }, { kind: "invert" }]
|
|
62053
|
+
},
|
|
62054
|
+
{
|
|
62055
|
+
kind: "numeric",
|
|
62056
|
+
requiredUnit: "W",
|
|
62057
|
+
transforms: [{
|
|
62058
|
+
kind: "threshold",
|
|
62059
|
+
comparison: "gte",
|
|
62060
|
+
defaultThreshold: 5,
|
|
62061
|
+
defaultStartDwellMs: RUNNING_POWER_START_DELAY_MS,
|
|
62062
|
+
defaultStopDwellMs: RUNNING_POWER_STOP_DELAY_MS,
|
|
62063
|
+
thresholdUnit: "W"
|
|
62064
|
+
}]
|
|
62065
|
+
}
|
|
62066
|
+
],
|
|
62067
|
+
companions: [
|
|
62068
|
+
{
|
|
62069
|
+
kind: "constant",
|
|
62070
|
+
path: "source",
|
|
62071
|
+
value: "assigned",
|
|
62072
|
+
when: "always"
|
|
62073
|
+
},
|
|
62074
|
+
{
|
|
62075
|
+
kind: "constant",
|
|
62076
|
+
path: "phase",
|
|
62077
|
+
value: null,
|
|
62078
|
+
when: "always"
|
|
62079
|
+
},
|
|
62080
|
+
{
|
|
62081
|
+
kind: "clock",
|
|
62082
|
+
path: "lastFetchedAt",
|
|
62083
|
+
when: "always"
|
|
62084
|
+
},
|
|
62085
|
+
{
|
|
62086
|
+
kind: "transition-time",
|
|
62087
|
+
path: "since",
|
|
62088
|
+
sourceChangedAt: "prefer"
|
|
62089
|
+
}
|
|
62090
|
+
],
|
|
62091
|
+
sourceReport: {
|
|
62092
|
+
status: "assignment-status",
|
|
62093
|
+
runtimeField: "source",
|
|
62094
|
+
nativeValue: "native",
|
|
62095
|
+
assignedValue: "assigned"
|
|
62096
|
+
},
|
|
62097
|
+
advancedExpression: true
|
|
62098
|
+
}]
|
|
62099
|
+
};
|
|
61798
62100
|
var runningStateCapability = {
|
|
61799
62101
|
name: "running-state",
|
|
61800
62102
|
scope: "device",
|
|
61801
62103
|
deviceNative: true,
|
|
61802
62104
|
mode: "singleton",
|
|
61803
|
-
deviceTypes:
|
|
62105
|
+
deviceTypes: RUNNING_DEVICE_TYPES,
|
|
61804
62106
|
methods: {},
|
|
61805
62107
|
events: {
|
|
61806
62108
|
onStarted: { data: RunningFlipEventDataSchema },
|
|
@@ -61813,7 +62115,8 @@ var runningStateCapability = {
|
|
|
61813
62115
|
runtimeState: RunningStateStatusSchema,
|
|
61814
62116
|
durability: "restored",
|
|
61815
62117
|
history: { fields: { running: { kind: "boolean" } } },
|
|
61816
|
-
volatileStateFields: ["lastFetchedAt"]
|
|
62118
|
+
volatileStateFields: ["lastFetchedAt"],
|
|
62119
|
+
customize: runningCustomize
|
|
61817
62120
|
};
|
|
61818
62121
|
DeviceType.Camera, DeviceType.Sensor, DeviceType.Switch, method(object({ deviceId: number().int().nonnegative() }), object({ success: literal(true) }), {
|
|
61819
62122
|
kind: "mutation",
|
|
@@ -66445,31 +66748,35 @@ method(object({}), array(TrainingBaseModelSchema).readonly(), { auth: "admin" })
|
|
|
66445
66748
|
kind: "mutation",
|
|
66446
66749
|
auth: "admin"
|
|
66447
66750
|
});
|
|
66448
|
-
function resolveSince(running, previous,
|
|
66751
|
+
function resolveSince(running, previous, transitionAtMs, bootstrapSinceMs) {
|
|
66449
66752
|
if (running === null) return null;
|
|
66450
|
-
|
|
66451
|
-
|
|
66753
|
+
const prevRunning = previous?.running ?? null;
|
|
66754
|
+
if (prevRunning === null) return bootstrapSinceMs;
|
|
66755
|
+
if (prevRunning !== running) return transitionAtMs;
|
|
66756
|
+
return previous?.since ?? null;
|
|
66452
66757
|
}
|
|
66453
|
-
function nativeSlice(running, phase, previous,
|
|
66758
|
+
function nativeSlice(running, phase, previous, transitionAtMs, fetchedAt, bootstrapSinceMs) {
|
|
66454
66759
|
return {
|
|
66455
66760
|
running,
|
|
66456
|
-
since: resolveSince(running, previous,
|
|
66761
|
+
since: resolveSince(running, previous, transitionAtMs, bootstrapSinceMs),
|
|
66457
66762
|
source: "native",
|
|
66458
66763
|
phase: running === null ? null : phase,
|
|
66459
|
-
lastFetchedAt:
|
|
66764
|
+
lastFetchedAt: fetchedAt
|
|
66460
66765
|
};
|
|
66461
66766
|
}
|
|
66462
|
-
function runningFromVacuumState(state, previous,
|
|
66463
|
-
|
|
66464
|
-
if (state ===
|
|
66465
|
-
if (state === "
|
|
66466
|
-
return nativeSlice(false,
|
|
66767
|
+
function runningFromVacuumState(state, previous, fetchedAt, transitionAt) {
|
|
66768
|
+
const transitionAtMs = transitionAt ?? fetchedAt;
|
|
66769
|
+
if (state === null) return nativeSlice(null, null, previous, transitionAtMs, fetchedAt, null);
|
|
66770
|
+
if (state === "cleaning" || state === "returning" || state === "drying") return nativeSlice(true, state, previous, transitionAtMs, fetchedAt, null);
|
|
66771
|
+
if (state === "paused") return nativeSlice(false, "paused", previous, transitionAtMs, fetchedAt, null);
|
|
66772
|
+
return nativeSlice(false, state, previous, transitionAtMs, fetchedAt, null);
|
|
66467
66773
|
}
|
|
66468
|
-
function runningFromLawnMower(activity, previous,
|
|
66469
|
-
|
|
66470
|
-
if (activity ===
|
|
66471
|
-
if (activity === "
|
|
66472
|
-
return nativeSlice(false,
|
|
66774
|
+
function runningFromLawnMower(activity, previous, fetchedAt, transitionAt) {
|
|
66775
|
+
const transitionAtMs = transitionAt ?? fetchedAt;
|
|
66776
|
+
if (activity === null) return nativeSlice(null, null, previous, transitionAtMs, fetchedAt, null);
|
|
66777
|
+
if (activity === "mowing") return nativeSlice(true, activity, previous, transitionAtMs, fetchedAt, null);
|
|
66778
|
+
if (activity === "paused") return nativeSlice(false, "paused", previous, transitionAtMs, fetchedAt, null);
|
|
66779
|
+
return nativeSlice(false, activity, previous, transitionAtMs, fetchedAt, null);
|
|
66473
66780
|
}
|
|
66474
66781
|
SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
|
|
66475
66782
|
Object.freeze({
|
|
@@ -84371,6 +84678,96 @@ Object.freeze({
|
|
|
84371
84678
|
"smtp-provider": "email"
|
|
84372
84679
|
});
|
|
84373
84680
|
DeviceType.Camera;
|
|
84681
|
+
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat, DeviceType.Camera, DeviceType.Hub, DeviceType.Light, DeviceType.Siren, DeviceType.Switch, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Fan, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.Dishwasher, DeviceType.Camera, DeviceType.Camera, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
|
|
84682
|
+
/**
|
|
84683
|
+
* A saved Customize assignment (D936). The schema is the type: callers use
|
|
84684
|
+
* `z.infer`, they do not restate the shape.
|
|
84685
|
+
*/
|
|
84686
|
+
var OverrideSourceSchema = object({
|
|
84687
|
+
addonId: string().min(1),
|
|
84688
|
+
stableId: string().min(1),
|
|
84689
|
+
cap: string().min(1),
|
|
84690
|
+
fieldPath: string().min(1)
|
|
84691
|
+
});
|
|
84692
|
+
var CustomizeTransformDraftSchema = discriminatedUnion("kind", [
|
|
84693
|
+
object({ kind: literal("identity") }),
|
|
84694
|
+
object({ kind: literal("invert") }),
|
|
84695
|
+
object({
|
|
84696
|
+
kind: literal("threshold"),
|
|
84697
|
+
comparison: _enum(["gte", "lte"]),
|
|
84698
|
+
threshold: number(),
|
|
84699
|
+
startDwellMs: number().nonnegative(),
|
|
84700
|
+
stopDwellMs: number().nonnegative()
|
|
84701
|
+
}),
|
|
84702
|
+
object({
|
|
84703
|
+
kind: literal("linear"),
|
|
84704
|
+
scale: number(),
|
|
84705
|
+
offset: number(),
|
|
84706
|
+
clampMin: number().optional(),
|
|
84707
|
+
clampMax: number().optional()
|
|
84708
|
+
}),
|
|
84709
|
+
object({
|
|
84710
|
+
kind: literal("enum-map"),
|
|
84711
|
+
mapping: record(string(), string().nullable())
|
|
84712
|
+
}),
|
|
84713
|
+
object({ kind: literal("number") })
|
|
84714
|
+
]);
|
|
84715
|
+
var ScalarOverrideDraftSchema = object({
|
|
84716
|
+
kind: literal("scalar"),
|
|
84717
|
+
cap: string().min(1),
|
|
84718
|
+
targetId: string().min(1),
|
|
84719
|
+
source: OverrideSourceSchema,
|
|
84720
|
+
transform: CustomizeTransformDraftSchema
|
|
84721
|
+
});
|
|
84722
|
+
var KeyedArrayOverrideDraftSchema = object({
|
|
84723
|
+
kind: literal("keyedArray"),
|
|
84724
|
+
cap: string().min(1),
|
|
84725
|
+
targetId: string().min(1),
|
|
84726
|
+
key: string().min(1),
|
|
84727
|
+
label: string().min(1),
|
|
84728
|
+
fieldPath: string().min(1),
|
|
84729
|
+
source: OverrideSourceSchema,
|
|
84730
|
+
transform: CustomizeTransformDraftSchema
|
|
84731
|
+
});
|
|
84732
|
+
var PulseOverrideDraftSchema = object({
|
|
84733
|
+
kind: literal("pulse"),
|
|
84734
|
+
cap: string().min(1),
|
|
84735
|
+
targetId: string().min(1),
|
|
84736
|
+
enabled: boolean(),
|
|
84737
|
+
debounceMs: number().nonnegative(),
|
|
84738
|
+
sources: array(OverrideSourceSchema).min(1)
|
|
84739
|
+
});
|
|
84740
|
+
var SpanSourceDraftSchema = OverrideSourceSchema.extend({ mode: _enum([
|
|
84741
|
+
"in-addition",
|
|
84742
|
+
"confirm",
|
|
84743
|
+
"replace"
|
|
84744
|
+
]).optional() });
|
|
84745
|
+
discriminatedUnion("kind", [
|
|
84746
|
+
ScalarOverrideDraftSchema,
|
|
84747
|
+
KeyedArrayOverrideDraftSchema,
|
|
84748
|
+
PulseOverrideDraftSchema,
|
|
84749
|
+
object({
|
|
84750
|
+
kind: literal("span"),
|
|
84751
|
+
cap: string().min(1),
|
|
84752
|
+
targetId: string().min(1),
|
|
84753
|
+
timeoutMs: number().nonnegative(),
|
|
84754
|
+
cooldownMs: number().nonnegative().optional(),
|
|
84755
|
+
sources: array(SpanSourceDraftSchema)
|
|
84756
|
+
})
|
|
84757
|
+
]);
|
|
84758
|
+
object({
|
|
84759
|
+
targetId: string().min(1),
|
|
84760
|
+
configured: boolean(),
|
|
84761
|
+
source: _enum(["native", "assigned"]),
|
|
84762
|
+
state: _enum([
|
|
84763
|
+
"active",
|
|
84764
|
+
"stale",
|
|
84765
|
+
"released",
|
|
84766
|
+
"unavailable"
|
|
84767
|
+
]),
|
|
84768
|
+
reason: string().nullable()
|
|
84769
|
+
});
|
|
84770
|
+
String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
|
|
84374
84771
|
var G711_SCALE_CORRECTION_DB = {
|
|
84375
84772
|
PCMU: 20 * Math.log10(4),
|
|
84376
84773
|
PCMA: 20 * Math.log10(8)
|
|
@@ -188494,13 +188891,6 @@ var MowerChargingEdge = class {
|
|
|
188494
188891
|
//#region src/devices/dreame-mower-device.ts
|
|
188495
188892
|
var CAP_NAME$9 = "lawn-mower-control";
|
|
188496
188893
|
var RUNNING_CAP$1 = "running-state";
|
|
188497
|
-
var RUNNING_COLD$1 = {
|
|
188498
|
-
running: null,
|
|
188499
|
-
since: null,
|
|
188500
|
-
source: "native",
|
|
188501
|
-
phase: null,
|
|
188502
|
-
lastFetchedAt: 0
|
|
188503
|
-
};
|
|
188504
188894
|
/**
|
|
188505
188895
|
* The CMS consumable custom-action only answers while the mower is momentarily
|
|
188506
188896
|
* awake and ACTIVELY charging — which it is the instant it docks with a depleted
|
|
@@ -188585,12 +188975,9 @@ var DreameMowerDevice = class extends DreameChildDevice {
|
|
|
188585
188975
|
await this.requireMower().dock();
|
|
188586
188976
|
}
|
|
188587
188977
|
});
|
|
188588
|
-
this.ctx.registerNativeCap(runningStateCapability, { getStatus: async () => this.runtimeState.getCapState(RUNNING_CAP$1) ??
|
|
188978
|
+
this.ctx.registerNativeCap(runningStateCapability, { getStatus: async () => this.runtimeState.getCapState(RUNNING_CAP$1) ?? RUNNING_STATE_COLD });
|
|
188589
188979
|
this.runtimeState.setCapState(CAP_NAME$9, COLD_START);
|
|
188590
|
-
this.runtimeState.setCapState(RUNNING_CAP$1,
|
|
188591
|
-
...RUNNING_COLD$1,
|
|
188592
|
-
lastFetchedAt: Date.now()
|
|
188593
|
-
});
|
|
188980
|
+
this.runtimeState.setCapState(RUNNING_CAP$1, RUNNING_STATE_COLD);
|
|
188594
188981
|
this.ctx.registerNativeCap(consumablesCapability, {
|
|
188595
188982
|
getStatus: async () => this.runtimeState.getCapState("consumables") ?? CONSUMABLES_COLD_START,
|
|
188596
188983
|
reset: async ({ key }) => {
|
|
@@ -188653,9 +189040,10 @@ var DreameMowerDevice = class extends DreameChildDevice {
|
|
|
188653
189040
|
lastChangedAt: Date.now()
|
|
188654
189041
|
};
|
|
188655
189042
|
this.runtimeState.setCapState(CAP_NAME$9, slice);
|
|
189043
|
+
const fetchedAt = Date.now();
|
|
188656
189044
|
const previous = this.runtimeState.getCapState(RUNNING_CAP$1);
|
|
188657
189045
|
const activityForRunning = status === null ? null : mapMowerStatusToActivity(status);
|
|
188658
|
-
this.runtimeState.setCapState(RUNNING_CAP$1, runningFromLawnMower(activityForRunning, previous, slice.lastChangedAt));
|
|
189046
|
+
this.runtimeState.setCapState(RUNNING_CAP$1, runningFromLawnMower(activityForRunning, previous, fetchedAt, slice.lastChangedAt));
|
|
188659
189047
|
if (this.#chargingEdge.observe(status, mower.charging)) this.#consumables.refresh("charging");
|
|
188660
189048
|
}
|
|
188661
189049
|
/** The live typed mower handle, or throw a clear error when disconnected. */
|
|
@@ -189403,13 +189791,6 @@ function resetMeta(result) {
|
|
|
189403
189791
|
//#region src/devices/dreame-vacuum-device.ts
|
|
189404
189792
|
var CAP_NAME$1 = "vacuum-control";
|
|
189405
189793
|
var RUNNING_CAP = "running-state";
|
|
189406
|
-
var RUNNING_COLD = {
|
|
189407
|
-
running: null,
|
|
189408
|
-
since: null,
|
|
189409
|
-
source: "native",
|
|
189410
|
-
phase: null,
|
|
189411
|
-
lastFetchedAt: 0
|
|
189412
|
-
};
|
|
189413
189794
|
var CONTROL_COLD_START = {
|
|
189414
189795
|
state: "idle",
|
|
189415
189796
|
batteryLevel: null,
|
|
@@ -189540,10 +189921,7 @@ var DreameVacuumDevice = class extends DreameChildDevice {
|
|
|
189540
189921
|
});
|
|
189541
189922
|
this.registerRunningCap();
|
|
189542
189923
|
this.runtimeState.setCapState(CAP_NAME$1, CONTROL_COLD_START);
|
|
189543
|
-
this.runtimeState.setCapState(RUNNING_CAP,
|
|
189544
|
-
...RUNNING_COLD,
|
|
189545
|
-
lastFetchedAt: Date.now()
|
|
189546
|
-
});
|
|
189924
|
+
this.runtimeState.setCapState(RUNNING_CAP, RUNNING_STATE_COLD);
|
|
189547
189925
|
this.registerConsumablesCap();
|
|
189548
189926
|
}
|
|
189549
189927
|
/**
|
|
@@ -189579,7 +189957,7 @@ var DreameVacuumDevice = class extends DreameChildDevice {
|
|
|
189579
189957
|
};
|
|
189580
189958
|
const toWrite = nextVacuumControlSlice(this.runtimeState.getCapState(CAP_NAME$1), controlSlice);
|
|
189581
189959
|
if (toWrite !== null) this.runtimeState.setCapState(CAP_NAME$1, toWrite);
|
|
189582
|
-
this.publishRunningSlice(miotStatus, controlSlice.lastChangedAt);
|
|
189960
|
+
this.publishRunningSlice(miotStatus, Date.now(), controlSlice.lastChangedAt);
|
|
189583
189961
|
this.consumables.onPush(controlSlice.state, tanks);
|
|
189584
189962
|
}
|
|
189585
189963
|
/**
|
|
@@ -189604,11 +189982,11 @@ var DreameVacuumDevice = class extends DreameChildDevice {
|
|
|
189604
189982
|
};
|
|
189605
189983
|
}
|
|
189606
189984
|
registerRunningCap() {
|
|
189607
|
-
this.ctx.registerNativeCap(runningStateCapability, { getStatus: async () => this.runtimeState.getCapState(RUNNING_CAP) ??
|
|
189985
|
+
this.ctx.registerNativeCap(runningStateCapability, { getStatus: async () => this.runtimeState.getCapState(RUNNING_CAP) ?? RUNNING_STATE_COLD });
|
|
189608
189986
|
}
|
|
189609
|
-
publishRunningSlice(miotStatus,
|
|
189987
|
+
publishRunningSlice(miotStatus, fetchedAt, transitionAt) {
|
|
189610
189988
|
const previous = this.runtimeState.getCapState(RUNNING_CAP);
|
|
189611
|
-
const next = runningFromVacuumState(miotStatus === null ? null : mapMiotStateToVacuumState(miotStatus), previous,
|
|
189989
|
+
const next = runningFromVacuumState(miotStatus === null ? null : mapMiotStateToVacuumState(miotStatus), previous, fetchedAt, transitionAt);
|
|
189612
189990
|
this.runtimeState.setCapState(RUNNING_CAP, next);
|
|
189613
189991
|
}
|
|
189614
189992
|
/** The live typed vacuum handle, or throw a clear error when disconnected. */
|
package/dist/addon.mjs
CHANGED
|
@@ -8871,7 +8871,7 @@ function errMsg(err) {
|
|
|
8871
8871
|
return String(err);
|
|
8872
8872
|
}
|
|
8873
8873
|
//#endregion
|
|
8874
|
-
//#region ../types/dist/composition-
|
|
8874
|
+
//#region ../types/dist/composition-BJ8iAZb3.mjs
|
|
8875
8875
|
/**
|
|
8876
8876
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
8877
8877
|
*
|
|
@@ -8931,7 +8931,7 @@ portable("linux64"), portable("linuxarm64"), portable("macarm64"), portable("mac
|
|
|
8931
8931
|
* ONE table for everyone who asks "is this device HIGH?": the
|
|
8932
8932
|
* recorder's `RecordingTriggers.sensorDeviceIds` trigger, the post-analysis
|
|
8933
8933
|
* sensor markers, the orchestrator's camera-sensors bridge and
|
|
8934
|
-
* the sources of a
|
|
8934
|
+
* the sources of a pulse (`compilePulseOverride`, D936).
|
|
8935
8935
|
* A second copy would diverge at the first cap added, and the symptom — "the
|
|
8936
8936
|
* sensor rings the doorbell but does not record" — is exactly D62.
|
|
8937
8937
|
*
|
|
@@ -54398,20 +54398,68 @@ var BatteryStatusSchema = object({
|
|
|
54398
54398
|
*/
|
|
54399
54399
|
binary: boolean().optional()
|
|
54400
54400
|
});
|
|
54401
|
+
var BATTERY_DEVICE_TYPES = [
|
|
54402
|
+
DeviceType.Camera,
|
|
54403
|
+
DeviceType.Sensor,
|
|
54404
|
+
DeviceType.Button,
|
|
54405
|
+
DeviceType.Switch,
|
|
54406
|
+
DeviceType.PetFeeder,
|
|
54407
|
+
DeviceType.Container,
|
|
54408
|
+
DeviceType.Thermostat
|
|
54409
|
+
];
|
|
54410
|
+
/** Generic Customize target for the percentage reading (D936). */
|
|
54411
|
+
var batteryCustomize = {
|
|
54412
|
+
version: 1,
|
|
54413
|
+
targets: [{
|
|
54414
|
+
id: "percentage",
|
|
54415
|
+
cardinality: "scalar",
|
|
54416
|
+
vocabulary: {
|
|
54417
|
+
cap: "battery",
|
|
54418
|
+
stateField: "percentage"
|
|
54419
|
+
},
|
|
54420
|
+
deviceTypes: BATTERY_DEVICE_TYPES,
|
|
54421
|
+
apply: "add-or-replace",
|
|
54422
|
+
path: "percentage",
|
|
54423
|
+
sources: [{
|
|
54424
|
+
kind: "field",
|
|
54425
|
+
valueKinds: ["number", "string"],
|
|
54426
|
+
transforms: [{ kind: "identity" }, {
|
|
54427
|
+
kind: "linear",
|
|
54428
|
+
defaultScale: 1,
|
|
54429
|
+
defaultOffset: 0,
|
|
54430
|
+
clampMin: 0,
|
|
54431
|
+
clampMax: 100
|
|
54432
|
+
}]
|
|
54433
|
+
}],
|
|
54434
|
+
companions: [
|
|
54435
|
+
{
|
|
54436
|
+
kind: "constant",
|
|
54437
|
+
path: "charging",
|
|
54438
|
+
value: "unknown",
|
|
54439
|
+
when: "add"
|
|
54440
|
+
},
|
|
54441
|
+
{
|
|
54442
|
+
kind: "constant",
|
|
54443
|
+
path: "sleeping",
|
|
54444
|
+
value: false,
|
|
54445
|
+
when: "add"
|
|
54446
|
+
},
|
|
54447
|
+
{
|
|
54448
|
+
kind: "clock",
|
|
54449
|
+
path: "lastUpdated",
|
|
54450
|
+
when: "add"
|
|
54451
|
+
}
|
|
54452
|
+
],
|
|
54453
|
+
sourceReport: { status: "assignment-status" },
|
|
54454
|
+
advancedExpression: true
|
|
54455
|
+
}]
|
|
54456
|
+
};
|
|
54401
54457
|
var batteryCapability = {
|
|
54402
54458
|
name: "battery",
|
|
54403
54459
|
scope: "device",
|
|
54404
54460
|
deviceNative: true,
|
|
54405
54461
|
mode: "singleton",
|
|
54406
|
-
deviceTypes:
|
|
54407
|
-
DeviceType.Camera,
|
|
54408
|
-
DeviceType.Sensor,
|
|
54409
|
-
DeviceType.Button,
|
|
54410
|
-
DeviceType.Switch,
|
|
54411
|
-
DeviceType.PetFeeder,
|
|
54412
|
-
DeviceType.Container,
|
|
54413
|
-
DeviceType.Thermostat
|
|
54414
|
-
],
|
|
54462
|
+
deviceTypes: BATTERY_DEVICE_TYPES,
|
|
54415
54463
|
methods: {
|
|
54416
54464
|
/**
|
|
54417
54465
|
* Explicitly wake the camera from low-power sleep ahead of a
|
|
@@ -54495,6 +54543,7 @@ onStatusChanged: { data: object({
|
|
|
54495
54543
|
kind: "gauge",
|
|
54496
54544
|
unit: "%"
|
|
54497
54545
|
} } },
|
|
54546
|
+
customize: batteryCustomize,
|
|
54498
54547
|
/** Clock fields: written, but excluded from the compare that decides
|
|
54499
54548
|
* whether persisting is worth a SQLite commit. */
|
|
54500
54549
|
volatileStateFields: ["lastUpdated"]
|
|
@@ -55484,6 +55533,106 @@ var ConsumablesStatusSchema = object({
|
|
|
55484
55533
|
items: array(ConsumableItemSchema),
|
|
55485
55534
|
lastChangedAt: number()
|
|
55486
55535
|
});
|
|
55536
|
+
/** Synthesize seed for a link-built status (no native provider).
|
|
55537
|
+
*
|
|
55538
|
+
* ⚠ NO LIVE CALLER since 2026-08-08 (device-links deleted; see
|
|
55539
|
+
* `CapabilityStatusSchema.empty`). The wiring guidance below was written for
|
|
55540
|
+
* exactly the case the operator is asking about again — a Dreame's HA
|
|
55541
|
+
* consumable-life sensors — so it is kept for that conversation, not because
|
|
55542
|
+
* anything reads it today. */
|
|
55543
|
+
var EMPTY_STATUS = {
|
|
55544
|
+
items: [],
|
|
55545
|
+
lastChangedAt: 0
|
|
55546
|
+
};
|
|
55547
|
+
/** Seed for a NEW link-built consumable item. `key`/`label` are overwritten
|
|
55548
|
+
* with the link's `itemKey` (see `status.itemArray`), so the placeholder
|
|
55549
|
+
* empty strings never survive into a validated item. Link-built items are
|
|
55550
|
+
* not resettable — there is no native provider to receive `reset()`.
|
|
55551
|
+
*
|
|
55552
|
+
* Wiring guidance (HA vacuum consumable-life sensors):
|
|
55553
|
+
* - a percent-remaining source (`numeric-sensor`, unit '%') → `level` via
|
|
55554
|
+
* `identity` (or `linear` scale 1 offset 0 clamp [0,100] to be safe);
|
|
55555
|
+
* - an hours-remaining source (e.g. Dreame 'Main Brush Time Left', unit 'h')
|
|
55556
|
+
* → `level` via `linear` with scale = 100 / max-hours for that item
|
|
55557
|
+
* (e.g. main brush 300 h → scale 0.3333) + clamp [0,100];
|
|
55558
|
+
* - a discrete source (`enum-sensor`, e.g. mop pad 'installed') → `status`
|
|
55559
|
+
* via `enum-map` (e.g. { installed: 'ok', missing: 'replace' }).
|
|
55560
|
+
* A numeric→'replace' THRESHOLD (level < 10 → 'replace') is NOT expressible
|
|
55561
|
+
* with the current transform kinds — leave `status` null (valid) until the
|
|
55562
|
+
* expression transform lands. */
|
|
55563
|
+
/** Generic Customize target for one consumable item (D936). Native rows stay read-only. */
|
|
55564
|
+
var consumablesCustomize = {
|
|
55565
|
+
version: 1,
|
|
55566
|
+
targets: [{
|
|
55567
|
+
id: "items",
|
|
55568
|
+
cardinality: "keyedArray",
|
|
55569
|
+
vocabulary: { cap: "consumables" },
|
|
55570
|
+
deviceTypes: Object.values(DeviceType),
|
|
55571
|
+
apply: "add",
|
|
55572
|
+
path: "items",
|
|
55573
|
+
keyField: "key",
|
|
55574
|
+
labelField: "label",
|
|
55575
|
+
itemSchema: ConsumableItemSchema,
|
|
55576
|
+
nativeItems: "read-only",
|
|
55577
|
+
sourceReport: { status: "assignment-status" },
|
|
55578
|
+
fields: [
|
|
55579
|
+
{
|
|
55580
|
+
path: "level",
|
|
55581
|
+
sources: [{
|
|
55582
|
+
kind: "numeric",
|
|
55583
|
+
transforms: [{ kind: "identity" }, {
|
|
55584
|
+
kind: "linear",
|
|
55585
|
+
defaultScale: 1,
|
|
55586
|
+
defaultOffset: 0,
|
|
55587
|
+
clampMin: 0,
|
|
55588
|
+
clampMax: 100
|
|
55589
|
+
}]
|
|
55590
|
+
}]
|
|
55591
|
+
},
|
|
55592
|
+
{
|
|
55593
|
+
path: "remaining.value",
|
|
55594
|
+
sources: [{
|
|
55595
|
+
kind: "numeric",
|
|
55596
|
+
transforms: [{ kind: "identity" }]
|
|
55597
|
+
}],
|
|
55598
|
+
literals: [{
|
|
55599
|
+
path: "remaining.unit",
|
|
55600
|
+
values: [...ConsumableRemainingUnitSchema.options]
|
|
55601
|
+
}]
|
|
55602
|
+
},
|
|
55603
|
+
{
|
|
55604
|
+
path: "status",
|
|
55605
|
+
sources: [{
|
|
55606
|
+
kind: "enum",
|
|
55607
|
+
transforms: [{
|
|
55608
|
+
kind: "enum-map",
|
|
55609
|
+
outputValues: [...ConsumableStatusSchema.options],
|
|
55610
|
+
unmapped: null
|
|
55611
|
+
}]
|
|
55612
|
+
}]
|
|
55613
|
+
}
|
|
55614
|
+
],
|
|
55615
|
+
traits: [{
|
|
55616
|
+
path: "kind",
|
|
55617
|
+
values: [...ConsumableKindSchema.options],
|
|
55618
|
+
defaultValue: "wear"
|
|
55619
|
+
}, {
|
|
55620
|
+
path: "form",
|
|
55621
|
+
values: [...ConsumableFormSchema.options],
|
|
55622
|
+
defaultValue: "part"
|
|
55623
|
+
}],
|
|
55624
|
+
companions: [{
|
|
55625
|
+
kind: "clock",
|
|
55626
|
+
path: "lastChangedAt",
|
|
55627
|
+
when: "add"
|
|
55628
|
+
}, {
|
|
55629
|
+
kind: "clock",
|
|
55630
|
+
path: "lastFetchedAt",
|
|
55631
|
+
when: "add"
|
|
55632
|
+
}],
|
|
55633
|
+
advancedExpression: true
|
|
55634
|
+
}]
|
|
55635
|
+
};
|
|
55487
55636
|
var consumablesCapability = {
|
|
55488
55637
|
name: "consumables",
|
|
55489
55638
|
scope: "device",
|
|
@@ -55521,10 +55670,7 @@ reset: method(object({
|
|
|
55521
55670
|
status: {
|
|
55522
55671
|
schema: ConsumablesStatusSchema,
|
|
55523
55672
|
kind: "push",
|
|
55524
|
-
empty:
|
|
55525
|
-
items: [],
|
|
55526
|
-
lastChangedAt: 0
|
|
55527
|
-
},
|
|
55673
|
+
empty: EMPTY_STATUS,
|
|
55528
55674
|
itemArray: {
|
|
55529
55675
|
path: "items",
|
|
55530
55676
|
keyField: "key",
|
|
@@ -55560,6 +55706,7 @@ reset: method(object({
|
|
|
55560
55706
|
* brush's remaining life and a dishwasher's salt are each recorded the moment
|
|
55561
55707
|
* their provider reports them; an item that appears later gets its series.
|
|
55562
55708
|
*/
|
|
55709
|
+
customize: consumablesCustomize,
|
|
55563
55710
|
history: {
|
|
55564
55711
|
fields: {},
|
|
55565
55712
|
items: {
|
|
@@ -56302,6 +56449,36 @@ var dishwasherCapability = {
|
|
|
56302
56449
|
powerOn: { kind: "boolean" }
|
|
56303
56450
|
} }
|
|
56304
56451
|
};
|
|
56452
|
+
/** Pulse override: a rising edge advances `lastPressedAt` and the press count. */
|
|
56453
|
+
var doorbellCustomize = {
|
|
56454
|
+
version: 1,
|
|
56455
|
+
targets: [{
|
|
56456
|
+
id: "pressed",
|
|
56457
|
+
cardinality: "event",
|
|
56458
|
+
shape: "pulse",
|
|
56459
|
+
vocabulary: {
|
|
56460
|
+
cap: "doorbell",
|
|
56461
|
+
eventName: "onPressed"
|
|
56462
|
+
},
|
|
56463
|
+
deviceTypes: [DeviceType.Camera],
|
|
56464
|
+
apply: "add",
|
|
56465
|
+
applyAuthority: { kind: "composition-claim" },
|
|
56466
|
+
eventName: "onPressed",
|
|
56467
|
+
edges: ["rising"],
|
|
56468
|
+
timestampPath: "lastPressedAt",
|
|
56469
|
+
counterPath: "pressCountSinceStart",
|
|
56470
|
+
highWater: "composer-advance",
|
|
56471
|
+
combine: "any",
|
|
56472
|
+
debounce: {
|
|
56473
|
+
kind: "rising-edge",
|
|
56474
|
+
defaultDebounceMs: 2e3,
|
|
56475
|
+
changedAtRequired: true
|
|
56476
|
+
},
|
|
56477
|
+
sources: [{ kind: "binary" }, { kind: "switch" }],
|
|
56478
|
+
sourceReport: { status: "assignment-status" },
|
|
56479
|
+
advancedExpression: true
|
|
56480
|
+
}]
|
|
56481
|
+
};
|
|
56305
56482
|
var DoorbellStatusSchema = object({
|
|
56306
56483
|
/** Ms epoch of the last press. null = never observed since this provider started. */
|
|
56307
56484
|
lastPressedAt: number().nullable(),
|
|
@@ -56368,7 +56545,8 @@ onPressed: {
|
|
|
56368
56545
|
/**
|
|
56369
56546
|
* History (D850): none — `pressCountSinceStart` resets with the addon, so it is not a monotonic meter; presses live in the events ledger.
|
|
56370
56547
|
*/
|
|
56371
|
-
history: "none"
|
|
56548
|
+
history: "none",
|
|
56549
|
+
customize: doorbellCustomize
|
|
56372
56550
|
};
|
|
56373
56551
|
/**
|
|
56374
56552
|
* Enum-state sensor — a string value picked from a finite option set.
|
|
@@ -58764,6 +58942,38 @@ authKey: string().optional() }), object({
|
|
|
58764
58942
|
/** Human-readable error when `ok: false`. */
|
|
58765
58943
|
error: string().optional()
|
|
58766
58944
|
}), { kind: "mutation" });
|
|
58945
|
+
/** Span override: start on a rising edge, end on a fall or this timeout. */
|
|
58946
|
+
var motionCustomize = {
|
|
58947
|
+
version: 1,
|
|
58948
|
+
targets: [{
|
|
58949
|
+
id: "detected",
|
|
58950
|
+
cardinality: "event",
|
|
58951
|
+
shape: "span",
|
|
58952
|
+
vocabulary: {
|
|
58953
|
+
cap: "motion",
|
|
58954
|
+
eventName: "onMotionChanged"
|
|
58955
|
+
},
|
|
58956
|
+
deviceTypes: [DeviceType.Camera],
|
|
58957
|
+
apply: "replace",
|
|
58958
|
+
applyAuthority: {
|
|
58959
|
+
kind: "camera-sensors",
|
|
58960
|
+
timeoutField: "motionCooldownMs"
|
|
58961
|
+
},
|
|
58962
|
+
eventName: "onMotionChanged",
|
|
58963
|
+
start: "rising-edge",
|
|
58964
|
+
end: "falling-edge-or-timeout",
|
|
58965
|
+
timeoutMs: 3e4,
|
|
58966
|
+
combine: "any",
|
|
58967
|
+
sourceModes: [
|
|
58968
|
+
"in-addition",
|
|
58969
|
+
"confirm",
|
|
58970
|
+
"replace"
|
|
58971
|
+
],
|
|
58972
|
+
sources: [{ kind: "binary" }, { kind: "switch" }],
|
|
58973
|
+
sourceReport: { status: "assignment-status" },
|
|
58974
|
+
advancedExpression: false
|
|
58975
|
+
}]
|
|
58976
|
+
};
|
|
58767
58977
|
var MotionStatusSchema = object({
|
|
58768
58978
|
detected: boolean(),
|
|
58769
58979
|
/** Ms epoch of the last detected-true observation. Null if never detected. */
|
|
@@ -58903,7 +59113,8 @@ onMotionChanged: { data: MotionOnMotionChangedDataSchema } },
|
|
|
58903
59113
|
history: { fields: { detected: {
|
|
58904
59114
|
kind: "boolean",
|
|
58905
59115
|
excludeDeviceTypes: [DeviceType.Camera]
|
|
58906
|
-
} } }
|
|
59116
|
+
} } },
|
|
59117
|
+
customize: motionCustomize
|
|
58907
59118
|
};
|
|
58908
59119
|
/**
|
|
58909
59120
|
* Motion-trigger toggle for accessory devices.
|
|
@@ -61777,6 +61988,16 @@ var ptzAutotrackCapability = {
|
|
|
61777
61988
|
*/
|
|
61778
61989
|
history: "none"
|
|
61779
61990
|
};
|
|
61991
|
+
var RUNNING_POWER_START_DELAY_MS = 3e4;
|
|
61992
|
+
var RUNNING_POWER_STOP_DELAY_MS = 18e4;
|
|
61993
|
+
/** Before any provider reading — all fields unknown (D933). */
|
|
61994
|
+
var RUNNING_STATE_COLD = {
|
|
61995
|
+
running: null,
|
|
61996
|
+
since: null,
|
|
61997
|
+
source: "native",
|
|
61998
|
+
phase: null,
|
|
61999
|
+
lastFetchedAt: null
|
|
62000
|
+
};
|
|
61780
62001
|
var RunningStateSourceSchema = _enum(["native", "assigned"]);
|
|
61781
62002
|
var RunningStateStatusSchema = object({
|
|
61782
62003
|
/** null = unknown — never coerced to false (D393). */
|
|
@@ -61785,19 +62006,100 @@ var RunningStateStatusSchema = object({
|
|
|
61785
62006
|
since: number().nullable(),
|
|
61786
62007
|
source: RunningStateSourceSchema,
|
|
61787
62008
|
phase: string().nullable(),
|
|
61788
|
-
|
|
62009
|
+
/** null until a reading has been published (D393). */
|
|
62010
|
+
lastFetchedAt: number().nullable()
|
|
61789
62011
|
});
|
|
61790
62012
|
var RunningFlipEventDataSchema = object({
|
|
61791
62013
|
deviceId: number(),
|
|
61792
62014
|
since: number().nullable(),
|
|
61793
62015
|
phase: string().nullable()
|
|
61794
62016
|
});
|
|
62017
|
+
var RUNNING_DEVICE_TYPES = Object.values(DeviceType);
|
|
62018
|
+
/** Generic Customize target for the running boolean (D936). */
|
|
62019
|
+
var runningCustomize = {
|
|
62020
|
+
version: 1,
|
|
62021
|
+
targets: [{
|
|
62022
|
+
id: "running",
|
|
62023
|
+
cardinality: "scalar",
|
|
62024
|
+
vocabulary: {
|
|
62025
|
+
cap: "running-state",
|
|
62026
|
+
stateField: "running"
|
|
62027
|
+
},
|
|
62028
|
+
deviceTypes: [
|
|
62029
|
+
DeviceType.Dishwasher,
|
|
62030
|
+
DeviceType.Vacuum,
|
|
62031
|
+
DeviceType.LawnMower,
|
|
62032
|
+
DeviceType.MediaPlayer,
|
|
62033
|
+
DeviceType.WaterHeater,
|
|
62034
|
+
DeviceType.Humidifier,
|
|
62035
|
+
DeviceType.Fan,
|
|
62036
|
+
DeviceType.Climate,
|
|
62037
|
+
DeviceType.Thermostat,
|
|
62038
|
+
DeviceType.PetFeeder
|
|
62039
|
+
],
|
|
62040
|
+
apply: "add-or-replace",
|
|
62041
|
+
path: "running",
|
|
62042
|
+
sources: [
|
|
62043
|
+
{
|
|
62044
|
+
kind: "switch",
|
|
62045
|
+
transforms: [{ kind: "identity" }]
|
|
62046
|
+
},
|
|
62047
|
+
{
|
|
62048
|
+
kind: "binary",
|
|
62049
|
+
transforms: [{ kind: "identity" }, { kind: "invert" }]
|
|
62050
|
+
},
|
|
62051
|
+
{
|
|
62052
|
+
kind: "numeric",
|
|
62053
|
+
requiredUnit: "W",
|
|
62054
|
+
transforms: [{
|
|
62055
|
+
kind: "threshold",
|
|
62056
|
+
comparison: "gte",
|
|
62057
|
+
defaultThreshold: 5,
|
|
62058
|
+
defaultStartDwellMs: RUNNING_POWER_START_DELAY_MS,
|
|
62059
|
+
defaultStopDwellMs: RUNNING_POWER_STOP_DELAY_MS,
|
|
62060
|
+
thresholdUnit: "W"
|
|
62061
|
+
}]
|
|
62062
|
+
}
|
|
62063
|
+
],
|
|
62064
|
+
companions: [
|
|
62065
|
+
{
|
|
62066
|
+
kind: "constant",
|
|
62067
|
+
path: "source",
|
|
62068
|
+
value: "assigned",
|
|
62069
|
+
when: "always"
|
|
62070
|
+
},
|
|
62071
|
+
{
|
|
62072
|
+
kind: "constant",
|
|
62073
|
+
path: "phase",
|
|
62074
|
+
value: null,
|
|
62075
|
+
when: "always"
|
|
62076
|
+
},
|
|
62077
|
+
{
|
|
62078
|
+
kind: "clock",
|
|
62079
|
+
path: "lastFetchedAt",
|
|
62080
|
+
when: "always"
|
|
62081
|
+
},
|
|
62082
|
+
{
|
|
62083
|
+
kind: "transition-time",
|
|
62084
|
+
path: "since",
|
|
62085
|
+
sourceChangedAt: "prefer"
|
|
62086
|
+
}
|
|
62087
|
+
],
|
|
62088
|
+
sourceReport: {
|
|
62089
|
+
status: "assignment-status",
|
|
62090
|
+
runtimeField: "source",
|
|
62091
|
+
nativeValue: "native",
|
|
62092
|
+
assignedValue: "assigned"
|
|
62093
|
+
},
|
|
62094
|
+
advancedExpression: true
|
|
62095
|
+
}]
|
|
62096
|
+
};
|
|
61795
62097
|
var runningStateCapability = {
|
|
61796
62098
|
name: "running-state",
|
|
61797
62099
|
scope: "device",
|
|
61798
62100
|
deviceNative: true,
|
|
61799
62101
|
mode: "singleton",
|
|
61800
|
-
deviceTypes:
|
|
62102
|
+
deviceTypes: RUNNING_DEVICE_TYPES,
|
|
61801
62103
|
methods: {},
|
|
61802
62104
|
events: {
|
|
61803
62105
|
onStarted: { data: RunningFlipEventDataSchema },
|
|
@@ -61810,7 +62112,8 @@ var runningStateCapability = {
|
|
|
61810
62112
|
runtimeState: RunningStateStatusSchema,
|
|
61811
62113
|
durability: "restored",
|
|
61812
62114
|
history: { fields: { running: { kind: "boolean" } } },
|
|
61813
|
-
volatileStateFields: ["lastFetchedAt"]
|
|
62115
|
+
volatileStateFields: ["lastFetchedAt"],
|
|
62116
|
+
customize: runningCustomize
|
|
61814
62117
|
};
|
|
61815
62118
|
DeviceType.Camera, DeviceType.Sensor, DeviceType.Switch, method(object({ deviceId: number().int().nonnegative() }), object({ success: literal(true) }), {
|
|
61816
62119
|
kind: "mutation",
|
|
@@ -66442,31 +66745,35 @@ method(object({}), array(TrainingBaseModelSchema).readonly(), { auth: "admin" })
|
|
|
66442
66745
|
kind: "mutation",
|
|
66443
66746
|
auth: "admin"
|
|
66444
66747
|
});
|
|
66445
|
-
function resolveSince(running, previous,
|
|
66748
|
+
function resolveSince(running, previous, transitionAtMs, bootstrapSinceMs) {
|
|
66446
66749
|
if (running === null) return null;
|
|
66447
|
-
|
|
66448
|
-
|
|
66750
|
+
const prevRunning = previous?.running ?? null;
|
|
66751
|
+
if (prevRunning === null) return bootstrapSinceMs;
|
|
66752
|
+
if (prevRunning !== running) return transitionAtMs;
|
|
66753
|
+
return previous?.since ?? null;
|
|
66449
66754
|
}
|
|
66450
|
-
function nativeSlice(running, phase, previous,
|
|
66755
|
+
function nativeSlice(running, phase, previous, transitionAtMs, fetchedAt, bootstrapSinceMs) {
|
|
66451
66756
|
return {
|
|
66452
66757
|
running,
|
|
66453
|
-
since: resolveSince(running, previous,
|
|
66758
|
+
since: resolveSince(running, previous, transitionAtMs, bootstrapSinceMs),
|
|
66454
66759
|
source: "native",
|
|
66455
66760
|
phase: running === null ? null : phase,
|
|
66456
|
-
lastFetchedAt:
|
|
66761
|
+
lastFetchedAt: fetchedAt
|
|
66457
66762
|
};
|
|
66458
66763
|
}
|
|
66459
|
-
function runningFromVacuumState(state, previous,
|
|
66460
|
-
|
|
66461
|
-
if (state ===
|
|
66462
|
-
if (state === "
|
|
66463
|
-
return nativeSlice(false,
|
|
66764
|
+
function runningFromVacuumState(state, previous, fetchedAt, transitionAt) {
|
|
66765
|
+
const transitionAtMs = transitionAt ?? fetchedAt;
|
|
66766
|
+
if (state === null) return nativeSlice(null, null, previous, transitionAtMs, fetchedAt, null);
|
|
66767
|
+
if (state === "cleaning" || state === "returning" || state === "drying") return nativeSlice(true, state, previous, transitionAtMs, fetchedAt, null);
|
|
66768
|
+
if (state === "paused") return nativeSlice(false, "paused", previous, transitionAtMs, fetchedAt, null);
|
|
66769
|
+
return nativeSlice(false, state, previous, transitionAtMs, fetchedAt, null);
|
|
66464
66770
|
}
|
|
66465
|
-
function runningFromLawnMower(activity, previous,
|
|
66466
|
-
|
|
66467
|
-
if (activity ===
|
|
66468
|
-
if (activity === "
|
|
66469
|
-
return nativeSlice(false,
|
|
66771
|
+
function runningFromLawnMower(activity, previous, fetchedAt, transitionAt) {
|
|
66772
|
+
const transitionAtMs = transitionAt ?? fetchedAt;
|
|
66773
|
+
if (activity === null) return nativeSlice(null, null, previous, transitionAtMs, fetchedAt, null);
|
|
66774
|
+
if (activity === "mowing") return nativeSlice(true, activity, previous, transitionAtMs, fetchedAt, null);
|
|
66775
|
+
if (activity === "paused") return nativeSlice(false, "paused", previous, transitionAtMs, fetchedAt, null);
|
|
66776
|
+
return nativeSlice(false, activity, previous, transitionAtMs, fetchedAt, null);
|
|
66470
66777
|
}
|
|
66471
66778
|
SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
|
|
66472
66779
|
Object.freeze({
|
|
@@ -84368,6 +84675,96 @@ Object.freeze({
|
|
|
84368
84675
|
"smtp-provider": "email"
|
|
84369
84676
|
});
|
|
84370
84677
|
DeviceType.Camera;
|
|
84678
|
+
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat, DeviceType.Camera, DeviceType.Hub, DeviceType.Light, DeviceType.Siren, DeviceType.Switch, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Fan, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.Dishwasher, DeviceType.Camera, DeviceType.Camera, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
|
|
84679
|
+
/**
|
|
84680
|
+
* A saved Customize assignment (D936). The schema is the type: callers use
|
|
84681
|
+
* `z.infer`, they do not restate the shape.
|
|
84682
|
+
*/
|
|
84683
|
+
var OverrideSourceSchema = object({
|
|
84684
|
+
addonId: string().min(1),
|
|
84685
|
+
stableId: string().min(1),
|
|
84686
|
+
cap: string().min(1),
|
|
84687
|
+
fieldPath: string().min(1)
|
|
84688
|
+
});
|
|
84689
|
+
var CustomizeTransformDraftSchema = discriminatedUnion("kind", [
|
|
84690
|
+
object({ kind: literal("identity") }),
|
|
84691
|
+
object({ kind: literal("invert") }),
|
|
84692
|
+
object({
|
|
84693
|
+
kind: literal("threshold"),
|
|
84694
|
+
comparison: _enum(["gte", "lte"]),
|
|
84695
|
+
threshold: number(),
|
|
84696
|
+
startDwellMs: number().nonnegative(),
|
|
84697
|
+
stopDwellMs: number().nonnegative()
|
|
84698
|
+
}),
|
|
84699
|
+
object({
|
|
84700
|
+
kind: literal("linear"),
|
|
84701
|
+
scale: number(),
|
|
84702
|
+
offset: number(),
|
|
84703
|
+
clampMin: number().optional(),
|
|
84704
|
+
clampMax: number().optional()
|
|
84705
|
+
}),
|
|
84706
|
+
object({
|
|
84707
|
+
kind: literal("enum-map"),
|
|
84708
|
+
mapping: record(string(), string().nullable())
|
|
84709
|
+
}),
|
|
84710
|
+
object({ kind: literal("number") })
|
|
84711
|
+
]);
|
|
84712
|
+
var ScalarOverrideDraftSchema = object({
|
|
84713
|
+
kind: literal("scalar"),
|
|
84714
|
+
cap: string().min(1),
|
|
84715
|
+
targetId: string().min(1),
|
|
84716
|
+
source: OverrideSourceSchema,
|
|
84717
|
+
transform: CustomizeTransformDraftSchema
|
|
84718
|
+
});
|
|
84719
|
+
var KeyedArrayOverrideDraftSchema = object({
|
|
84720
|
+
kind: literal("keyedArray"),
|
|
84721
|
+
cap: string().min(1),
|
|
84722
|
+
targetId: string().min(1),
|
|
84723
|
+
key: string().min(1),
|
|
84724
|
+
label: string().min(1),
|
|
84725
|
+
fieldPath: string().min(1),
|
|
84726
|
+
source: OverrideSourceSchema,
|
|
84727
|
+
transform: CustomizeTransformDraftSchema
|
|
84728
|
+
});
|
|
84729
|
+
var PulseOverrideDraftSchema = object({
|
|
84730
|
+
kind: literal("pulse"),
|
|
84731
|
+
cap: string().min(1),
|
|
84732
|
+
targetId: string().min(1),
|
|
84733
|
+
enabled: boolean(),
|
|
84734
|
+
debounceMs: number().nonnegative(),
|
|
84735
|
+
sources: array(OverrideSourceSchema).min(1)
|
|
84736
|
+
});
|
|
84737
|
+
var SpanSourceDraftSchema = OverrideSourceSchema.extend({ mode: _enum([
|
|
84738
|
+
"in-addition",
|
|
84739
|
+
"confirm",
|
|
84740
|
+
"replace"
|
|
84741
|
+
]).optional() });
|
|
84742
|
+
discriminatedUnion("kind", [
|
|
84743
|
+
ScalarOverrideDraftSchema,
|
|
84744
|
+
KeyedArrayOverrideDraftSchema,
|
|
84745
|
+
PulseOverrideDraftSchema,
|
|
84746
|
+
object({
|
|
84747
|
+
kind: literal("span"),
|
|
84748
|
+
cap: string().min(1),
|
|
84749
|
+
targetId: string().min(1),
|
|
84750
|
+
timeoutMs: number().nonnegative(),
|
|
84751
|
+
cooldownMs: number().nonnegative().optional(),
|
|
84752
|
+
sources: array(SpanSourceDraftSchema)
|
|
84753
|
+
})
|
|
84754
|
+
]);
|
|
84755
|
+
object({
|
|
84756
|
+
targetId: string().min(1),
|
|
84757
|
+
configured: boolean(),
|
|
84758
|
+
source: _enum(["native", "assigned"]),
|
|
84759
|
+
state: _enum([
|
|
84760
|
+
"active",
|
|
84761
|
+
"stale",
|
|
84762
|
+
"released",
|
|
84763
|
+
"unavailable"
|
|
84764
|
+
]),
|
|
84765
|
+
reason: string().nullable()
|
|
84766
|
+
});
|
|
84767
|
+
String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
|
|
84371
84768
|
var G711_SCALE_CORRECTION_DB = {
|
|
84372
84769
|
PCMU: 20 * Math.log10(4),
|
|
84373
84770
|
PCMA: 20 * Math.log10(8)
|
|
@@ -188491,13 +188888,6 @@ var MowerChargingEdge = class {
|
|
|
188491
188888
|
//#region src/devices/dreame-mower-device.ts
|
|
188492
188889
|
var CAP_NAME$9 = "lawn-mower-control";
|
|
188493
188890
|
var RUNNING_CAP$1 = "running-state";
|
|
188494
|
-
var RUNNING_COLD$1 = {
|
|
188495
|
-
running: null,
|
|
188496
|
-
since: null,
|
|
188497
|
-
source: "native",
|
|
188498
|
-
phase: null,
|
|
188499
|
-
lastFetchedAt: 0
|
|
188500
|
-
};
|
|
188501
188891
|
/**
|
|
188502
188892
|
* The CMS consumable custom-action only answers while the mower is momentarily
|
|
188503
188893
|
* awake and ACTIVELY charging — which it is the instant it docks with a depleted
|
|
@@ -188582,12 +188972,9 @@ var DreameMowerDevice = class extends DreameChildDevice {
|
|
|
188582
188972
|
await this.requireMower().dock();
|
|
188583
188973
|
}
|
|
188584
188974
|
});
|
|
188585
|
-
this.ctx.registerNativeCap(runningStateCapability, { getStatus: async () => this.runtimeState.getCapState(RUNNING_CAP$1) ??
|
|
188975
|
+
this.ctx.registerNativeCap(runningStateCapability, { getStatus: async () => this.runtimeState.getCapState(RUNNING_CAP$1) ?? RUNNING_STATE_COLD });
|
|
188586
188976
|
this.runtimeState.setCapState(CAP_NAME$9, COLD_START);
|
|
188587
|
-
this.runtimeState.setCapState(RUNNING_CAP$1,
|
|
188588
|
-
...RUNNING_COLD$1,
|
|
188589
|
-
lastFetchedAt: Date.now()
|
|
188590
|
-
});
|
|
188977
|
+
this.runtimeState.setCapState(RUNNING_CAP$1, RUNNING_STATE_COLD);
|
|
188591
188978
|
this.ctx.registerNativeCap(consumablesCapability, {
|
|
188592
188979
|
getStatus: async () => this.runtimeState.getCapState("consumables") ?? CONSUMABLES_COLD_START,
|
|
188593
188980
|
reset: async ({ key }) => {
|
|
@@ -188650,9 +189037,10 @@ var DreameMowerDevice = class extends DreameChildDevice {
|
|
|
188650
189037
|
lastChangedAt: Date.now()
|
|
188651
189038
|
};
|
|
188652
189039
|
this.runtimeState.setCapState(CAP_NAME$9, slice);
|
|
189040
|
+
const fetchedAt = Date.now();
|
|
188653
189041
|
const previous = this.runtimeState.getCapState(RUNNING_CAP$1);
|
|
188654
189042
|
const activityForRunning = status === null ? null : mapMowerStatusToActivity(status);
|
|
188655
|
-
this.runtimeState.setCapState(RUNNING_CAP$1, runningFromLawnMower(activityForRunning, previous, slice.lastChangedAt));
|
|
189043
|
+
this.runtimeState.setCapState(RUNNING_CAP$1, runningFromLawnMower(activityForRunning, previous, fetchedAt, slice.lastChangedAt));
|
|
188656
189044
|
if (this.#chargingEdge.observe(status, mower.charging)) this.#consumables.refresh("charging");
|
|
188657
189045
|
}
|
|
188658
189046
|
/** The live typed mower handle, or throw a clear error when disconnected. */
|
|
@@ -189400,13 +189788,6 @@ function resetMeta(result) {
|
|
|
189400
189788
|
//#region src/devices/dreame-vacuum-device.ts
|
|
189401
189789
|
var CAP_NAME$1 = "vacuum-control";
|
|
189402
189790
|
var RUNNING_CAP = "running-state";
|
|
189403
|
-
var RUNNING_COLD = {
|
|
189404
|
-
running: null,
|
|
189405
|
-
since: null,
|
|
189406
|
-
source: "native",
|
|
189407
|
-
phase: null,
|
|
189408
|
-
lastFetchedAt: 0
|
|
189409
|
-
};
|
|
189410
189791
|
var CONTROL_COLD_START = {
|
|
189411
189792
|
state: "idle",
|
|
189412
189793
|
batteryLevel: null,
|
|
@@ -189537,10 +189918,7 @@ var DreameVacuumDevice = class extends DreameChildDevice {
|
|
|
189537
189918
|
});
|
|
189538
189919
|
this.registerRunningCap();
|
|
189539
189920
|
this.runtimeState.setCapState(CAP_NAME$1, CONTROL_COLD_START);
|
|
189540
|
-
this.runtimeState.setCapState(RUNNING_CAP,
|
|
189541
|
-
...RUNNING_COLD,
|
|
189542
|
-
lastFetchedAt: Date.now()
|
|
189543
|
-
});
|
|
189921
|
+
this.runtimeState.setCapState(RUNNING_CAP, RUNNING_STATE_COLD);
|
|
189544
189922
|
this.registerConsumablesCap();
|
|
189545
189923
|
}
|
|
189546
189924
|
/**
|
|
@@ -189576,7 +189954,7 @@ var DreameVacuumDevice = class extends DreameChildDevice {
|
|
|
189576
189954
|
};
|
|
189577
189955
|
const toWrite = nextVacuumControlSlice(this.runtimeState.getCapState(CAP_NAME$1), controlSlice);
|
|
189578
189956
|
if (toWrite !== null) this.runtimeState.setCapState(CAP_NAME$1, toWrite);
|
|
189579
|
-
this.publishRunningSlice(miotStatus, controlSlice.lastChangedAt);
|
|
189957
|
+
this.publishRunningSlice(miotStatus, Date.now(), controlSlice.lastChangedAt);
|
|
189580
189958
|
this.consumables.onPush(controlSlice.state, tanks);
|
|
189581
189959
|
}
|
|
189582
189960
|
/**
|
|
@@ -189601,11 +189979,11 @@ var DreameVacuumDevice = class extends DreameChildDevice {
|
|
|
189601
189979
|
};
|
|
189602
189980
|
}
|
|
189603
189981
|
registerRunningCap() {
|
|
189604
|
-
this.ctx.registerNativeCap(runningStateCapability, { getStatus: async () => this.runtimeState.getCapState(RUNNING_CAP) ??
|
|
189982
|
+
this.ctx.registerNativeCap(runningStateCapability, { getStatus: async () => this.runtimeState.getCapState(RUNNING_CAP) ?? RUNNING_STATE_COLD });
|
|
189605
189983
|
}
|
|
189606
|
-
publishRunningSlice(miotStatus,
|
|
189984
|
+
publishRunningSlice(miotStatus, fetchedAt, transitionAt) {
|
|
189607
189985
|
const previous = this.runtimeState.getCapState(RUNNING_CAP);
|
|
189608
|
-
const next = runningFromVacuumState(miotStatus === null ? null : mapMiotStateToVacuumState(miotStatus), previous,
|
|
189986
|
+
const next = runningFromVacuumState(miotStatus === null ? null : mapMiotStateToVacuumState(miotStatus), previous, fetchedAt, transitionAt);
|
|
189609
189987
|
this.runtimeState.setCapState(RUNNING_CAP, next);
|
|
189610
189988
|
}
|
|
189611
189989
|
/** The live typed vacuum handle, or throw a clear error when disconnected. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-provider-dreame",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.154",
|
|
4
4
|
"description": "Dreame robot-vacuum / lawn-mower device-provider addon for CamStack — wraps the @apocaliss92/nodedreame Dreamehome cloud client",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"camstack",
|