@camstack/addon-provider-gree 0.1.5 → 0.1.7
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 +235 -42
- package/dist/addon.mjs +235 -42
- package/package.json +2 -2
package/dist/addon.js
CHANGED
|
@@ -10080,15 +10080,18 @@ var humiditySensorCapability = {
|
|
|
10080
10080
|
runtimeState: HumiditySensorStatusSchema
|
|
10081
10081
|
};
|
|
10082
10082
|
/**
|
|
10083
|
-
* Image display cap. Models
|
|
10084
|
-
*
|
|
10083
|
+
* Image display cap. Models a single still image exposed by an integration —
|
|
10084
|
+
* a snapshot, a chart, a generated picture, or a robot's cleaning-map render.
|
|
10085
10085
|
*
|
|
10086
|
-
* Read-only: there are no setters. The provider resolves
|
|
10087
|
-
*
|
|
10088
|
-
*
|
|
10089
|
-
*
|
|
10090
|
-
*
|
|
10091
|
-
*
|
|
10086
|
+
* Read-only: there are no setters. The provider resolves whatever upstream
|
|
10087
|
+
* source it has into an ABSOLUTE URL the browser loads directly:
|
|
10088
|
+
* - HA `image.*` entities → the `entity_picture` signed-token path
|
|
10089
|
+
* (token stays in the query string, so no auth header is needed);
|
|
10090
|
+
* - a Dreame/robot map → the cloud/OSS map-image URL (or an addon
|
|
10091
|
+
* data-plane URL serving the rendered map bytes), exposed as its own
|
|
10092
|
+
* Image child device grouped under the robot's container.
|
|
10093
|
+
* The slice carries that URL plus the upstream last-updated timestamp; the
|
|
10094
|
+
* image changes when the source's last-updated marker changes.
|
|
10092
10095
|
*/
|
|
10093
10096
|
var ImageStatusSchema = object({
|
|
10094
10097
|
/** Absolute signed URL the browser loads directly. Null when the
|
|
@@ -10114,18 +10117,47 @@ var imageCapability = {
|
|
|
10114
10117
|
*/
|
|
10115
10118
|
runtimeState: ImageStatusSchema
|
|
10116
10119
|
};
|
|
10120
|
+
/**
|
|
10121
|
+
* Robotic lawn-mower cap. Models HA `lawn_mower.*` entities — anything
|
|
10122
|
+
* with a mowing lifecycle plus a dock action.
|
|
10123
|
+
*
|
|
10124
|
+
* Activity follows HA's canonical lawn-mower lifecycle: `idle` /
|
|
10125
|
+
* `mowing` / `paused` / `docked` / `error`. `batteryLevel` (0..100) is
|
|
10126
|
+
* nullable — some mowers don't report a battery percentage.
|
|
10127
|
+
*
|
|
10128
|
+
* `startMowing` begins a mowing run, `pause` halts it in place, and
|
|
10129
|
+
* `dock` sends the mower back to its charging station.
|
|
10130
|
+
*/
|
|
10131
|
+
var LawnMowerActivitySchema = _enum([
|
|
10132
|
+
"idle",
|
|
10133
|
+
"mowing",
|
|
10134
|
+
"paused",
|
|
10135
|
+
"docked",
|
|
10136
|
+
"error"
|
|
10137
|
+
]);
|
|
10138
|
+
/** Severity of the current device/error code — info (status), warning, error. */
|
|
10139
|
+
var DeviceCodeSeveritySchema = _enum([
|
|
10140
|
+
"info",
|
|
10141
|
+
"warning",
|
|
10142
|
+
"error"
|
|
10143
|
+
]);
|
|
10117
10144
|
var LawnMowerControlStatusSchema = object({
|
|
10118
10145
|
/** Lifecycle activity of the mower. */
|
|
10119
|
-
activity:
|
|
10120
|
-
"idle",
|
|
10121
|
-
"mowing",
|
|
10122
|
-
"paused",
|
|
10123
|
-
"docked",
|
|
10124
|
-
"error"
|
|
10125
|
-
]),
|
|
10146
|
+
activity: LawnMowerActivitySchema,
|
|
10126
10147
|
/** 0..100 battery percentage. Null when the device has no battery
|
|
10127
10148
|
* reading. */
|
|
10128
10149
|
batteryLevel: number().min(0).max(100).nullable(),
|
|
10150
|
+
/** 0..100 mowing-completion percentage of the current task, or null when no
|
|
10151
|
+
* task is active / progress is unavailable. */
|
|
10152
|
+
progressPercent: number().min(0).max(100).nullable(),
|
|
10153
|
+
/** Current device/event code (dynamic — mostly status, sometimes an error),
|
|
10154
|
+
* or null when unknown. */
|
|
10155
|
+
currentCode: number().nullable(),
|
|
10156
|
+
/** Human label for {@link currentCode}, or null when undecodable. */
|
|
10157
|
+
currentCodeLabel: string().nullable(),
|
|
10158
|
+
/** Severity of {@link currentCode}. `error` (and often `warning`) warrants UI
|
|
10159
|
+
* attention; `info` is normal status. */
|
|
10160
|
+
severity: DeviceCodeSeveritySchema,
|
|
10129
10161
|
/** Ms epoch when the slice was last updated. */
|
|
10130
10162
|
lastChangedAt: number()
|
|
10131
10163
|
});
|
|
@@ -12351,6 +12383,7 @@ var VacuumStateSchema = _enum([
|
|
|
12351
12383
|
"paused",
|
|
12352
12384
|
"returning",
|
|
12353
12385
|
"docked",
|
|
12386
|
+
"drying",
|
|
12354
12387
|
"error"
|
|
12355
12388
|
]);
|
|
12356
12389
|
/**
|
|
@@ -12389,6 +12422,12 @@ var VacuumControlStatusSchema = object({
|
|
|
12389
12422
|
detergent: TankStatusSchema.nullable(),
|
|
12390
12423
|
/** Dust bin. Null when the hardware has no dust bin. */
|
|
12391
12424
|
dustBin: TankStatusSchema.nullable(),
|
|
12425
|
+
/** 0..100 cleaning-completion percentage of the current task, or null. */
|
|
12426
|
+
progressPercent: number().min(0).max(100).nullable(),
|
|
12427
|
+
/** Current error code (0 / null = no error). */
|
|
12428
|
+
errorCode: number().nullable(),
|
|
12429
|
+
/** Human label for {@link errorCode}, or null when none / undecodable. */
|
|
12430
|
+
errorLabel: string().nullable(),
|
|
12392
12431
|
/** Ms epoch when the slice was last updated. */
|
|
12393
12432
|
lastChangedAt: number()
|
|
12394
12433
|
});
|
|
@@ -13355,9 +13394,29 @@ var BaseDevice$1 = class {
|
|
|
13355
13394
|
* is open (Reolink writes `hasPtz/hasIntercom`, Hikvision writes
|
|
13356
13395
|
* `hasSupplementalLight/hasAlarmIo`, etc).
|
|
13357
13396
|
*
|
|
13358
|
-
* Default:
|
|
13397
|
+
* Default: nothing to probe → mark the device PROBED (set `lastProbedAt`) so
|
|
13398
|
+
* the kernel treats it as ready immediately. A device that derives its shape
|
|
13399
|
+
* from a spec (a container, or an accessory sensor) rather than from a
|
|
13400
|
+
* hardware probe has no probe to "complete"; without stamping `lastProbedAt`
|
|
13401
|
+
* it would look perpetually un-probed — logging "Initial probe did not
|
|
13402
|
+
* complete" on every boot and spinning a pointless retry chain. Drivers that
|
|
13403
|
+
* DO probe override this and write their own `feature-probe` slice (including
|
|
13404
|
+
* `lastProbedAt`) once their probe actually succeeds.
|
|
13359
13405
|
*/
|
|
13360
|
-
async onProbe() {
|
|
13406
|
+
async onProbe() {
|
|
13407
|
+
const base = this.runtimeState.getCapState("feature-probe") ?? {
|
|
13408
|
+
flags: {},
|
|
13409
|
+
deviceType: null,
|
|
13410
|
+
model: null,
|
|
13411
|
+
channelCount: null,
|
|
13412
|
+
lastProbedAt: 0,
|
|
13413
|
+
lastFetchedAt: 0
|
|
13414
|
+
};
|
|
13415
|
+
this.runtimeState.setCapState("feature-probe", {
|
|
13416
|
+
...base,
|
|
13417
|
+
lastProbedAt: Date.now()
|
|
13418
|
+
});
|
|
13419
|
+
}
|
|
13361
13420
|
/**
|
|
13362
13421
|
* Phase 5 — fired after the device + its accessories are registered.
|
|
13363
13422
|
* Drivers publish streams to the broker, kick off background tasks,
|
|
@@ -14819,17 +14878,32 @@ var ReleaseInputSchema = object({
|
|
|
14819
14878
|
* the parent cascades into every accessory. */
|
|
14820
14879
|
camDeviceId: number().int().nonnegative()
|
|
14821
14880
|
});
|
|
14822
|
-
var ResyncInputSchema = object({
|
|
14823
|
-
/** Parent CamStack device id of an adopted device. The provider resolves its
|
|
14824
|
-
* source (integration/broker + native id) and re-aligns the device's
|
|
14825
|
-
* structural spec (type/role/capabilities/units) with the live mapping,
|
|
14826
|
-
* rebuilding any child whose class changed while preserving operator edits. */
|
|
14827
|
-
camDeviceId: number().int().nonnegative()
|
|
14881
|
+
var ResyncInputSchema = object({
|
|
14882
|
+
/** Parent CamStack device id of an adopted device. The provider resolves its
|
|
14883
|
+
* source (integration/broker + native id) and re-aligns the device's
|
|
14884
|
+
* structural spec (type/role/capabilities/units) with the live mapping,
|
|
14885
|
+
* rebuilding any child whose class changed while preserving operator edits. */
|
|
14886
|
+
camDeviceId: number().int().nonnegative(),
|
|
14887
|
+
/** "Resync from zero" (#19). When true, the kernel PURGES every accessory
|
|
14888
|
+
* child of `camDeviceId` BEFORE the provider re-derives the device, so the
|
|
14889
|
+
* children are rebuilt fresh from source — correct names, coords, and units —
|
|
14890
|
+
* instead of being preserved by the incremental reconcile. Use to recover from
|
|
14891
|
+
* legacy generic/placeholder names that the normal name-precedence keeps frozen
|
|
14892
|
+
* (the operator's explicit reset). Push-driven integrations (no-op resync)
|
|
14893
|
+
* rebuild on their next snapshot; pull/command integrations rebuild in `resync`.
|
|
14894
|
+
* Operator edits on the PARENT (its name, layout, primary-child pick) survive —
|
|
14895
|
+
* only the children are torn down. Omitted/false ⇒ the normal incremental
|
|
14896
|
+
* re-sync that preserves children. */
|
|
14897
|
+
resetToSource: boolean().optional()
|
|
14898
|
+
});
|
|
14828
14899
|
var ResyncResultSchema = object({
|
|
14829
14900
|
/** True when the persisted spec actually changed (children may have been rebuilt). */
|
|
14830
14901
|
changed: boolean(),
|
|
14831
14902
|
/** Number of child devices rebuilt into a new class by this re-sync. */
|
|
14832
|
-
rebuiltChildren: number().int().nonnegative()
|
|
14903
|
+
rebuiltChildren: number().int().nonnegative(),
|
|
14904
|
+
/** Number of accessory children torn down by a `resetToSource` purge before the
|
|
14905
|
+
* provider re-derived the device. 0/absent for a normal incremental re-sync. */
|
|
14906
|
+
removedChildren: number().int().nonnegative().optional()
|
|
14833
14907
|
});
|
|
14834
14908
|
var deviceAdoptionCapability = {
|
|
14835
14909
|
name: "device-adoption",
|
|
@@ -16594,6 +16668,11 @@ var DeviceMetaSchema = object({
|
|
|
16594
16668
|
addonId: string(),
|
|
16595
16669
|
type: string(),
|
|
16596
16670
|
name: string(),
|
|
16671
|
+
/** True once an operator explicitly renamed the device via `setName`. Drives
|
|
16672
|
+
* reconcile name-precedence (preserve operator name vs adopt fresh provider
|
|
16673
|
+
* name). Absent ⇒ treated as user-named (PRESERVE) for legacy rows. See
|
|
16674
|
+
* `DeviceMeta.userNamed`. */
|
|
16675
|
+
userNamed: boolean().optional(),
|
|
16597
16676
|
location: string().nullable(),
|
|
16598
16677
|
disabled: boolean(),
|
|
16599
16678
|
parentDeviceId: number().nullable(),
|
|
@@ -16904,6 +16983,9 @@ method(object({
|
|
|
16904
16983
|
}), method(ReleaseInputSchema.extend({ addonId: string() }), _void(), {
|
|
16905
16984
|
kind: "mutation",
|
|
16906
16985
|
auth: "admin"
|
|
16986
|
+
}), method(ResyncInputSchema, ResyncResultSchema, {
|
|
16987
|
+
kind: "mutation",
|
|
16988
|
+
auth: "admin"
|
|
16907
16989
|
}), method(object({
|
|
16908
16990
|
deviceId: number(),
|
|
16909
16991
|
key: string(),
|
|
@@ -20666,6 +20748,12 @@ Object.freeze({
|
|
|
20666
20748
|
addonId: null,
|
|
20667
20749
|
access: "create"
|
|
20668
20750
|
},
|
|
20751
|
+
"deviceManager.adoptionResync": {
|
|
20752
|
+
capName: "device-manager",
|
|
20753
|
+
capScope: "system",
|
|
20754
|
+
addonId: null,
|
|
20755
|
+
access: "create"
|
|
20756
|
+
},
|
|
20669
20757
|
"deviceManager.allocateDeviceId": {
|
|
20670
20758
|
capName: "device-manager",
|
|
20671
20759
|
capScope: "system",
|
|
@@ -25537,6 +25625,90 @@ function swingToOscillating(vertical, horizontal) {
|
|
|
25537
25625
|
function oscillatingToVerticalSwing(oscillating) {
|
|
25538
25626
|
return oscillating ? VerticalSwing.FullSwing : VerticalSwing.Default;
|
|
25539
25627
|
}
|
|
25628
|
+
/**
|
|
25629
|
+
* Gree fan-speed names surfaced on the `climate-control` cap's `fanMode` /
|
|
25630
|
+
* `availableFanModes` strings, mirroring the HA Gree integration's `fan_modes`
|
|
25631
|
+
* attribute (`auto`/`low`/`medium_low`/`medium`/`medium_high`/`high`).
|
|
25632
|
+
*
|
|
25633
|
+
* NOTE: HA's Gree integration also folds `turbo` and `quiet` INTO `fan_modes`.
|
|
25634
|
+
* We deliberately keep turbo/quiet on the dedicated `preset` surface instead
|
|
25635
|
+
* (they are independent boolean device flags in the protocol — `Tur` / `Quiet`
|
|
25636
|
+
* — not points on the `WdSpd` speed axis), so the speed picker stays a pure
|
|
25637
|
+
* speed axis and the two flags stay independently togglable. The `fan-control`
|
|
25638
|
+
* percentage surface continues to mirror the same `WdSpd` speed for the
|
|
25639
|
+
* fan-style UI.
|
|
25640
|
+
*/
|
|
25641
|
+
var GREE_FAN_MODES = [
|
|
25642
|
+
"auto",
|
|
25643
|
+
"low",
|
|
25644
|
+
"medium_low",
|
|
25645
|
+
"medium",
|
|
25646
|
+
"medium_high",
|
|
25647
|
+
"high"
|
|
25648
|
+
];
|
|
25649
|
+
/** Map a library {@link FanSpeed} to its `climate-control` `fanMode` string. Pure. */
|
|
25650
|
+
function fanSpeedToFanMode(speed) {
|
|
25651
|
+
switch (speed) {
|
|
25652
|
+
case FanSpeed.Auto: return "auto";
|
|
25653
|
+
case FanSpeed.Low: return "low";
|
|
25654
|
+
case FanSpeed.MediumLow: return "medium_low";
|
|
25655
|
+
case FanSpeed.Medium: return "medium";
|
|
25656
|
+
case FanSpeed.MediumHigh: return "medium_high";
|
|
25657
|
+
case FanSpeed.High: return "high";
|
|
25658
|
+
}
|
|
25659
|
+
}
|
|
25660
|
+
/**
|
|
25661
|
+
* Map a `climate-control` `fanMode` string back to a library {@link FanSpeed},
|
|
25662
|
+
* or null when the string is not a known Gree speed. Pure.
|
|
25663
|
+
*/
|
|
25664
|
+
function fanModeToFanSpeed(fanMode) {
|
|
25665
|
+
switch (fanMode) {
|
|
25666
|
+
case "auto": return FanSpeed.Auto;
|
|
25667
|
+
case "low": return FanSpeed.Low;
|
|
25668
|
+
case "medium_low": return FanSpeed.MediumLow;
|
|
25669
|
+
case "medium": return FanSpeed.Medium;
|
|
25670
|
+
case "medium_high": return FanSpeed.MediumHigh;
|
|
25671
|
+
case "high": return FanSpeed.High;
|
|
25672
|
+
default: return null;
|
|
25673
|
+
}
|
|
25674
|
+
}
|
|
25675
|
+
var GREE_PRESETS = [
|
|
25676
|
+
"none",
|
|
25677
|
+
"turbo",
|
|
25678
|
+
"quiet",
|
|
25679
|
+
"sleep",
|
|
25680
|
+
"eco",
|
|
25681
|
+
"8c_heat"
|
|
25682
|
+
];
|
|
25683
|
+
/**
|
|
25684
|
+
* Derive the single active `preset` string from the device's comfort flags.
|
|
25685
|
+
* Precedence is fixed (turbo > quiet > sleep > eco > 8c_heat) so a coherent
|
|
25686
|
+
* single value is reported even if the device has more than one flag set.
|
|
25687
|
+
* Returns `'none'` when no flag is set. Pure.
|
|
25688
|
+
*/
|
|
25689
|
+
function presetFromFlags(flags) {
|
|
25690
|
+
if (flags.turbo) return "turbo";
|
|
25691
|
+
if (flags.quiet) return "quiet";
|
|
25692
|
+
if (flags.sleep) return "sleep";
|
|
25693
|
+
if (flags.powerSave) return "eco";
|
|
25694
|
+
if (flags.steadyHeat) return "8c_heat";
|
|
25695
|
+
return "none";
|
|
25696
|
+
}
|
|
25697
|
+
/**
|
|
25698
|
+
* Resolve a requested `preset` string to the set of flag writes needed to make
|
|
25699
|
+
* it the active one — the chosen flag (if any) true, every other flag false.
|
|
25700
|
+
* Returns null when the string is not a known Gree preset. Pure.
|
|
25701
|
+
*/
|
|
25702
|
+
function presetToFlagWrites(preset) {
|
|
25703
|
+
if (!GREE_PRESETS.includes(preset)) return null;
|
|
25704
|
+
return {
|
|
25705
|
+
turbo: preset === "turbo",
|
|
25706
|
+
quiet: preset === "quiet",
|
|
25707
|
+
sleep: preset === "sleep",
|
|
25708
|
+
powerSave: preset === "eco",
|
|
25709
|
+
steadyHeat: preset === "8c_heat"
|
|
25710
|
+
};
|
|
25711
|
+
}
|
|
25540
25712
|
//#endregion
|
|
25541
25713
|
//#region src/devices/gree-ac-device.ts
|
|
25542
25714
|
var CLIMATE_CAP = "climate-control";
|
|
@@ -25545,9 +25717,9 @@ var CLIMATE_COLD_START = {
|
|
|
25545
25717
|
mode: "off",
|
|
25546
25718
|
availableModes: [...ADVERTISED_CAP_MODES],
|
|
25547
25719
|
fanMode: "",
|
|
25548
|
-
availableFanModes: [],
|
|
25720
|
+
availableFanModes: [...GREE_FAN_MODES],
|
|
25549
25721
|
preset: "",
|
|
25550
|
-
availablePresets: [],
|
|
25722
|
+
availablePresets: [...GREE_PRESETS],
|
|
25551
25723
|
target: null,
|
|
25552
25724
|
targetHigh: null,
|
|
25553
25725
|
targetLow: null,
|
|
@@ -25583,17 +25755,21 @@ var greeAcSchema = object({
|
|
|
25583
25755
|
* `stateChanged` push (and seeds on activate).
|
|
25584
25756
|
*
|
|
25585
25757
|
* Climate commands route to the bound handle: setMode `off`→`setPower(false)`,
|
|
25586
|
-
* any other→`setPower(true)`+`setMode()`; setTarget→`setTargetTemperature()
|
|
25587
|
-
*
|
|
25758
|
+
* any other→`setPower(true)`+`setMode()`; setTarget→`setTargetTemperature()`;
|
|
25759
|
+
* setFanMode→`setFanSpeed()` (climate `fanMode` string ↔ Gree speed); setPreset→
|
|
25760
|
+
* the comfort-flag setters (turbo/quiet/sleep/eco/8c_heat → `setTurbo`/`setQuiet`/
|
|
25761
|
+
* `setSleep`/`setPowerSave`/`setSteadyHeat`, exclusive). Fan commands:
|
|
25762
|
+
* setPercentage→`setFanSpeed()` (percentage↔FanSpeed bucket);
|
|
25588
25763
|
* setOscillating→`setSwingVertical(FullSwing|Default)`.
|
|
25589
25764
|
*
|
|
25590
|
-
* TODO (deferred):
|
|
25591
|
-
*
|
|
25592
|
-
*
|
|
25593
|
-
*
|
|
25594
|
-
*
|
|
25595
|
-
*
|
|
25596
|
-
*
|
|
25765
|
+
* TODO (deferred — needs protocol RE / live confirmation): `heat_cool`
|
|
25766
|
+
* dual-setpoint (Gree single-setpoint ACs have none), `setTargetHumidity`
|
|
25767
|
+
* (`Dwet`/`DwatSen` dehumidifier props exist in PROPS but the library exposes no
|
|
25768
|
+
* getter/setter yet), the light toggle (`setLight`), X-Fan / fresh-air / health
|
|
25769
|
+
* toggles (`setXfan`/`setFreshAir`/`setHealth`) — all real library setters with
|
|
25770
|
+
* no cap surface (a vendor toggle cap would carry them), and the fine-grained
|
|
25771
|
+
* 12-position vertical / 7-position horizontal swing (collapsed to a single
|
|
25772
|
+
* `oscillating` boolean — a vendor swing-position cap would carry them).
|
|
25597
25773
|
*/
|
|
25598
25774
|
var GreeAcDevice = class extends BaseDevice$1 {
|
|
25599
25775
|
features = [];
|
|
@@ -25671,10 +25847,19 @@ var GreeAcDevice = class extends BaseDevice$1 {
|
|
|
25671
25847
|
await ac.setMode(libMode);
|
|
25672
25848
|
},
|
|
25673
25849
|
setFanMode: async ({ fanMode }) => {
|
|
25674
|
-
|
|
25850
|
+
const speed = fanModeToFanSpeed(fanMode);
|
|
25851
|
+
if (speed === null) throw new Error(`gree ac: unsupported fan mode "${fanMode}"`);
|
|
25852
|
+
await this.requireAc().setFanSpeed(speed);
|
|
25675
25853
|
},
|
|
25676
25854
|
setPreset: async ({ preset }) => {
|
|
25677
|
-
|
|
25855
|
+
const writes = presetToFlagWrites(preset);
|
|
25856
|
+
if (writes === null) throw new Error(`gree ac: unsupported preset "${preset}"`);
|
|
25857
|
+
const ac = this.requireAc();
|
|
25858
|
+
if (ac.turbo !== writes.turbo) await ac.setTurbo(writes.turbo);
|
|
25859
|
+
if (ac.quiet !== writes.quiet) await ac.setQuiet(writes.quiet);
|
|
25860
|
+
if (ac.sleep !== writes.sleep) await ac.setSleep(writes.sleep);
|
|
25861
|
+
if (ac.powerSave !== writes.powerSave) await ac.setPowerSave(writes.powerSave);
|
|
25862
|
+
if (ac.steadyHeat !== writes.steadyHeat) await ac.setSteadyHeat(writes.steadyHeat);
|
|
25678
25863
|
},
|
|
25679
25864
|
setTarget: async ({ target }) => {
|
|
25680
25865
|
await this.requireAc().setTargetTemperature(target);
|
|
@@ -25708,13 +25893,21 @@ var GreeAcDevice = class extends BaseDevice$1 {
|
|
|
25708
25893
|
const ac = this.resolveAc();
|
|
25709
25894
|
if (ac === null) return;
|
|
25710
25895
|
const now = Date.now();
|
|
25896
|
+
const mode = ac.power ? libModeToCapMode(ac.mode) : "off";
|
|
25897
|
+
const preset = presetFromFlags({
|
|
25898
|
+
turbo: ac.turbo,
|
|
25899
|
+
quiet: ac.quiet,
|
|
25900
|
+
sleep: ac.sleep,
|
|
25901
|
+
powerSave: ac.powerSave,
|
|
25902
|
+
steadyHeat: ac.steadyHeat
|
|
25903
|
+
});
|
|
25711
25904
|
const climateSlice = {
|
|
25712
|
-
mode
|
|
25905
|
+
mode,
|
|
25713
25906
|
availableModes: [...ADVERTISED_CAP_MODES],
|
|
25714
|
-
fanMode:
|
|
25715
|
-
availableFanModes: [],
|
|
25716
|
-
preset
|
|
25717
|
-
availablePresets: [],
|
|
25907
|
+
fanMode: fanSpeedToFanMode(ac.fanSpeed),
|
|
25908
|
+
availableFanModes: [...GREE_FAN_MODES],
|
|
25909
|
+
preset,
|
|
25910
|
+
availablePresets: [...GREE_PRESETS],
|
|
25718
25911
|
target: ac.targetTemperature,
|
|
25719
25912
|
targetHigh: null,
|
|
25720
25913
|
targetLow: null,
|
package/dist/addon.mjs
CHANGED
|
@@ -10079,15 +10079,18 @@ var humiditySensorCapability = {
|
|
|
10079
10079
|
runtimeState: HumiditySensorStatusSchema
|
|
10080
10080
|
};
|
|
10081
10081
|
/**
|
|
10082
|
-
* Image display cap. Models
|
|
10083
|
-
*
|
|
10082
|
+
* Image display cap. Models a single still image exposed by an integration —
|
|
10083
|
+
* a snapshot, a chart, a generated picture, or a robot's cleaning-map render.
|
|
10084
10084
|
*
|
|
10085
|
-
* Read-only: there are no setters. The provider resolves
|
|
10086
|
-
*
|
|
10087
|
-
*
|
|
10088
|
-
*
|
|
10089
|
-
*
|
|
10090
|
-
*
|
|
10085
|
+
* Read-only: there are no setters. The provider resolves whatever upstream
|
|
10086
|
+
* source it has into an ABSOLUTE URL the browser loads directly:
|
|
10087
|
+
* - HA `image.*` entities → the `entity_picture` signed-token path
|
|
10088
|
+
* (token stays in the query string, so no auth header is needed);
|
|
10089
|
+
* - a Dreame/robot map → the cloud/OSS map-image URL (or an addon
|
|
10090
|
+
* data-plane URL serving the rendered map bytes), exposed as its own
|
|
10091
|
+
* Image child device grouped under the robot's container.
|
|
10092
|
+
* The slice carries that URL plus the upstream last-updated timestamp; the
|
|
10093
|
+
* image changes when the source's last-updated marker changes.
|
|
10091
10094
|
*/
|
|
10092
10095
|
var ImageStatusSchema = object({
|
|
10093
10096
|
/** Absolute signed URL the browser loads directly. Null when the
|
|
@@ -10113,18 +10116,47 @@ var imageCapability = {
|
|
|
10113
10116
|
*/
|
|
10114
10117
|
runtimeState: ImageStatusSchema
|
|
10115
10118
|
};
|
|
10119
|
+
/**
|
|
10120
|
+
* Robotic lawn-mower cap. Models HA `lawn_mower.*` entities — anything
|
|
10121
|
+
* with a mowing lifecycle plus a dock action.
|
|
10122
|
+
*
|
|
10123
|
+
* Activity follows HA's canonical lawn-mower lifecycle: `idle` /
|
|
10124
|
+
* `mowing` / `paused` / `docked` / `error`. `batteryLevel` (0..100) is
|
|
10125
|
+
* nullable — some mowers don't report a battery percentage.
|
|
10126
|
+
*
|
|
10127
|
+
* `startMowing` begins a mowing run, `pause` halts it in place, and
|
|
10128
|
+
* `dock` sends the mower back to its charging station.
|
|
10129
|
+
*/
|
|
10130
|
+
var LawnMowerActivitySchema = _enum([
|
|
10131
|
+
"idle",
|
|
10132
|
+
"mowing",
|
|
10133
|
+
"paused",
|
|
10134
|
+
"docked",
|
|
10135
|
+
"error"
|
|
10136
|
+
]);
|
|
10137
|
+
/** Severity of the current device/error code — info (status), warning, error. */
|
|
10138
|
+
var DeviceCodeSeveritySchema = _enum([
|
|
10139
|
+
"info",
|
|
10140
|
+
"warning",
|
|
10141
|
+
"error"
|
|
10142
|
+
]);
|
|
10116
10143
|
var LawnMowerControlStatusSchema = object({
|
|
10117
10144
|
/** Lifecycle activity of the mower. */
|
|
10118
|
-
activity:
|
|
10119
|
-
"idle",
|
|
10120
|
-
"mowing",
|
|
10121
|
-
"paused",
|
|
10122
|
-
"docked",
|
|
10123
|
-
"error"
|
|
10124
|
-
]),
|
|
10145
|
+
activity: LawnMowerActivitySchema,
|
|
10125
10146
|
/** 0..100 battery percentage. Null when the device has no battery
|
|
10126
10147
|
* reading. */
|
|
10127
10148
|
batteryLevel: number().min(0).max(100).nullable(),
|
|
10149
|
+
/** 0..100 mowing-completion percentage of the current task, or null when no
|
|
10150
|
+
* task is active / progress is unavailable. */
|
|
10151
|
+
progressPercent: number().min(0).max(100).nullable(),
|
|
10152
|
+
/** Current device/event code (dynamic — mostly status, sometimes an error),
|
|
10153
|
+
* or null when unknown. */
|
|
10154
|
+
currentCode: number().nullable(),
|
|
10155
|
+
/** Human label for {@link currentCode}, or null when undecodable. */
|
|
10156
|
+
currentCodeLabel: string().nullable(),
|
|
10157
|
+
/** Severity of {@link currentCode}. `error` (and often `warning`) warrants UI
|
|
10158
|
+
* attention; `info` is normal status. */
|
|
10159
|
+
severity: DeviceCodeSeveritySchema,
|
|
10128
10160
|
/** Ms epoch when the slice was last updated. */
|
|
10129
10161
|
lastChangedAt: number()
|
|
10130
10162
|
});
|
|
@@ -12350,6 +12382,7 @@ var VacuumStateSchema = _enum([
|
|
|
12350
12382
|
"paused",
|
|
12351
12383
|
"returning",
|
|
12352
12384
|
"docked",
|
|
12385
|
+
"drying",
|
|
12353
12386
|
"error"
|
|
12354
12387
|
]);
|
|
12355
12388
|
/**
|
|
@@ -12388,6 +12421,12 @@ var VacuumControlStatusSchema = object({
|
|
|
12388
12421
|
detergent: TankStatusSchema.nullable(),
|
|
12389
12422
|
/** Dust bin. Null when the hardware has no dust bin. */
|
|
12390
12423
|
dustBin: TankStatusSchema.nullable(),
|
|
12424
|
+
/** 0..100 cleaning-completion percentage of the current task, or null. */
|
|
12425
|
+
progressPercent: number().min(0).max(100).nullable(),
|
|
12426
|
+
/** Current error code (0 / null = no error). */
|
|
12427
|
+
errorCode: number().nullable(),
|
|
12428
|
+
/** Human label for {@link errorCode}, or null when none / undecodable. */
|
|
12429
|
+
errorLabel: string().nullable(),
|
|
12391
12430
|
/** Ms epoch when the slice was last updated. */
|
|
12392
12431
|
lastChangedAt: number()
|
|
12393
12432
|
});
|
|
@@ -13354,9 +13393,29 @@ var BaseDevice$1 = class {
|
|
|
13354
13393
|
* is open (Reolink writes `hasPtz/hasIntercom`, Hikvision writes
|
|
13355
13394
|
* `hasSupplementalLight/hasAlarmIo`, etc).
|
|
13356
13395
|
*
|
|
13357
|
-
* Default:
|
|
13396
|
+
* Default: nothing to probe → mark the device PROBED (set `lastProbedAt`) so
|
|
13397
|
+
* the kernel treats it as ready immediately. A device that derives its shape
|
|
13398
|
+
* from a spec (a container, or an accessory sensor) rather than from a
|
|
13399
|
+
* hardware probe has no probe to "complete"; without stamping `lastProbedAt`
|
|
13400
|
+
* it would look perpetually un-probed — logging "Initial probe did not
|
|
13401
|
+
* complete" on every boot and spinning a pointless retry chain. Drivers that
|
|
13402
|
+
* DO probe override this and write their own `feature-probe` slice (including
|
|
13403
|
+
* `lastProbedAt`) once their probe actually succeeds.
|
|
13358
13404
|
*/
|
|
13359
|
-
async onProbe() {
|
|
13405
|
+
async onProbe() {
|
|
13406
|
+
const base = this.runtimeState.getCapState("feature-probe") ?? {
|
|
13407
|
+
flags: {},
|
|
13408
|
+
deviceType: null,
|
|
13409
|
+
model: null,
|
|
13410
|
+
channelCount: null,
|
|
13411
|
+
lastProbedAt: 0,
|
|
13412
|
+
lastFetchedAt: 0
|
|
13413
|
+
};
|
|
13414
|
+
this.runtimeState.setCapState("feature-probe", {
|
|
13415
|
+
...base,
|
|
13416
|
+
lastProbedAt: Date.now()
|
|
13417
|
+
});
|
|
13418
|
+
}
|
|
13360
13419
|
/**
|
|
13361
13420
|
* Phase 5 — fired after the device + its accessories are registered.
|
|
13362
13421
|
* Drivers publish streams to the broker, kick off background tasks,
|
|
@@ -14818,17 +14877,32 @@ var ReleaseInputSchema = object({
|
|
|
14818
14877
|
* the parent cascades into every accessory. */
|
|
14819
14878
|
camDeviceId: number().int().nonnegative()
|
|
14820
14879
|
});
|
|
14821
|
-
var ResyncInputSchema = object({
|
|
14822
|
-
/** Parent CamStack device id of an adopted device. The provider resolves its
|
|
14823
|
-
* source (integration/broker + native id) and re-aligns the device's
|
|
14824
|
-
* structural spec (type/role/capabilities/units) with the live mapping,
|
|
14825
|
-
* rebuilding any child whose class changed while preserving operator edits. */
|
|
14826
|
-
camDeviceId: number().int().nonnegative()
|
|
14880
|
+
var ResyncInputSchema = object({
|
|
14881
|
+
/** Parent CamStack device id of an adopted device. The provider resolves its
|
|
14882
|
+
* source (integration/broker + native id) and re-aligns the device's
|
|
14883
|
+
* structural spec (type/role/capabilities/units) with the live mapping,
|
|
14884
|
+
* rebuilding any child whose class changed while preserving operator edits. */
|
|
14885
|
+
camDeviceId: number().int().nonnegative(),
|
|
14886
|
+
/** "Resync from zero" (#19). When true, the kernel PURGES every accessory
|
|
14887
|
+
* child of `camDeviceId` BEFORE the provider re-derives the device, so the
|
|
14888
|
+
* children are rebuilt fresh from source — correct names, coords, and units —
|
|
14889
|
+
* instead of being preserved by the incremental reconcile. Use to recover from
|
|
14890
|
+
* legacy generic/placeholder names that the normal name-precedence keeps frozen
|
|
14891
|
+
* (the operator's explicit reset). Push-driven integrations (no-op resync)
|
|
14892
|
+
* rebuild on their next snapshot; pull/command integrations rebuild in `resync`.
|
|
14893
|
+
* Operator edits on the PARENT (its name, layout, primary-child pick) survive —
|
|
14894
|
+
* only the children are torn down. Omitted/false ⇒ the normal incremental
|
|
14895
|
+
* re-sync that preserves children. */
|
|
14896
|
+
resetToSource: boolean().optional()
|
|
14897
|
+
});
|
|
14827
14898
|
var ResyncResultSchema = object({
|
|
14828
14899
|
/** True when the persisted spec actually changed (children may have been rebuilt). */
|
|
14829
14900
|
changed: boolean(),
|
|
14830
14901
|
/** Number of child devices rebuilt into a new class by this re-sync. */
|
|
14831
|
-
rebuiltChildren: number().int().nonnegative()
|
|
14902
|
+
rebuiltChildren: number().int().nonnegative(),
|
|
14903
|
+
/** Number of accessory children torn down by a `resetToSource` purge before the
|
|
14904
|
+
* provider re-derived the device. 0/absent for a normal incremental re-sync. */
|
|
14905
|
+
removedChildren: number().int().nonnegative().optional()
|
|
14832
14906
|
});
|
|
14833
14907
|
var deviceAdoptionCapability = {
|
|
14834
14908
|
name: "device-adoption",
|
|
@@ -16593,6 +16667,11 @@ var DeviceMetaSchema = object({
|
|
|
16593
16667
|
addonId: string(),
|
|
16594
16668
|
type: string(),
|
|
16595
16669
|
name: string(),
|
|
16670
|
+
/** True once an operator explicitly renamed the device via `setName`. Drives
|
|
16671
|
+
* reconcile name-precedence (preserve operator name vs adopt fresh provider
|
|
16672
|
+
* name). Absent ⇒ treated as user-named (PRESERVE) for legacy rows. See
|
|
16673
|
+
* `DeviceMeta.userNamed`. */
|
|
16674
|
+
userNamed: boolean().optional(),
|
|
16596
16675
|
location: string().nullable(),
|
|
16597
16676
|
disabled: boolean(),
|
|
16598
16677
|
parentDeviceId: number().nullable(),
|
|
@@ -16903,6 +16982,9 @@ method(object({
|
|
|
16903
16982
|
}), method(ReleaseInputSchema.extend({ addonId: string() }), _void(), {
|
|
16904
16983
|
kind: "mutation",
|
|
16905
16984
|
auth: "admin"
|
|
16985
|
+
}), method(ResyncInputSchema, ResyncResultSchema, {
|
|
16986
|
+
kind: "mutation",
|
|
16987
|
+
auth: "admin"
|
|
16906
16988
|
}), method(object({
|
|
16907
16989
|
deviceId: number(),
|
|
16908
16990
|
key: string(),
|
|
@@ -20665,6 +20747,12 @@ Object.freeze({
|
|
|
20665
20747
|
addonId: null,
|
|
20666
20748
|
access: "create"
|
|
20667
20749
|
},
|
|
20750
|
+
"deviceManager.adoptionResync": {
|
|
20751
|
+
capName: "device-manager",
|
|
20752
|
+
capScope: "system",
|
|
20753
|
+
addonId: null,
|
|
20754
|
+
access: "create"
|
|
20755
|
+
},
|
|
20668
20756
|
"deviceManager.allocateDeviceId": {
|
|
20669
20757
|
capName: "device-manager",
|
|
20670
20758
|
capScope: "system",
|
|
@@ -25536,6 +25624,90 @@ function swingToOscillating(vertical, horizontal) {
|
|
|
25536
25624
|
function oscillatingToVerticalSwing(oscillating) {
|
|
25537
25625
|
return oscillating ? VerticalSwing.FullSwing : VerticalSwing.Default;
|
|
25538
25626
|
}
|
|
25627
|
+
/**
|
|
25628
|
+
* Gree fan-speed names surfaced on the `climate-control` cap's `fanMode` /
|
|
25629
|
+
* `availableFanModes` strings, mirroring the HA Gree integration's `fan_modes`
|
|
25630
|
+
* attribute (`auto`/`low`/`medium_low`/`medium`/`medium_high`/`high`).
|
|
25631
|
+
*
|
|
25632
|
+
* NOTE: HA's Gree integration also folds `turbo` and `quiet` INTO `fan_modes`.
|
|
25633
|
+
* We deliberately keep turbo/quiet on the dedicated `preset` surface instead
|
|
25634
|
+
* (they are independent boolean device flags in the protocol — `Tur` / `Quiet`
|
|
25635
|
+
* — not points on the `WdSpd` speed axis), so the speed picker stays a pure
|
|
25636
|
+
* speed axis and the two flags stay independently togglable. The `fan-control`
|
|
25637
|
+
* percentage surface continues to mirror the same `WdSpd` speed for the
|
|
25638
|
+
* fan-style UI.
|
|
25639
|
+
*/
|
|
25640
|
+
var GREE_FAN_MODES = [
|
|
25641
|
+
"auto",
|
|
25642
|
+
"low",
|
|
25643
|
+
"medium_low",
|
|
25644
|
+
"medium",
|
|
25645
|
+
"medium_high",
|
|
25646
|
+
"high"
|
|
25647
|
+
];
|
|
25648
|
+
/** Map a library {@link FanSpeed} to its `climate-control` `fanMode` string. Pure. */
|
|
25649
|
+
function fanSpeedToFanMode(speed) {
|
|
25650
|
+
switch (speed) {
|
|
25651
|
+
case FanSpeed.Auto: return "auto";
|
|
25652
|
+
case FanSpeed.Low: return "low";
|
|
25653
|
+
case FanSpeed.MediumLow: return "medium_low";
|
|
25654
|
+
case FanSpeed.Medium: return "medium";
|
|
25655
|
+
case FanSpeed.MediumHigh: return "medium_high";
|
|
25656
|
+
case FanSpeed.High: return "high";
|
|
25657
|
+
}
|
|
25658
|
+
}
|
|
25659
|
+
/**
|
|
25660
|
+
* Map a `climate-control` `fanMode` string back to a library {@link FanSpeed},
|
|
25661
|
+
* or null when the string is not a known Gree speed. Pure.
|
|
25662
|
+
*/
|
|
25663
|
+
function fanModeToFanSpeed(fanMode) {
|
|
25664
|
+
switch (fanMode) {
|
|
25665
|
+
case "auto": return FanSpeed.Auto;
|
|
25666
|
+
case "low": return FanSpeed.Low;
|
|
25667
|
+
case "medium_low": return FanSpeed.MediumLow;
|
|
25668
|
+
case "medium": return FanSpeed.Medium;
|
|
25669
|
+
case "medium_high": return FanSpeed.MediumHigh;
|
|
25670
|
+
case "high": return FanSpeed.High;
|
|
25671
|
+
default: return null;
|
|
25672
|
+
}
|
|
25673
|
+
}
|
|
25674
|
+
var GREE_PRESETS = [
|
|
25675
|
+
"none",
|
|
25676
|
+
"turbo",
|
|
25677
|
+
"quiet",
|
|
25678
|
+
"sleep",
|
|
25679
|
+
"eco",
|
|
25680
|
+
"8c_heat"
|
|
25681
|
+
];
|
|
25682
|
+
/**
|
|
25683
|
+
* Derive the single active `preset` string from the device's comfort flags.
|
|
25684
|
+
* Precedence is fixed (turbo > quiet > sleep > eco > 8c_heat) so a coherent
|
|
25685
|
+
* single value is reported even if the device has more than one flag set.
|
|
25686
|
+
* Returns `'none'` when no flag is set. Pure.
|
|
25687
|
+
*/
|
|
25688
|
+
function presetFromFlags(flags) {
|
|
25689
|
+
if (flags.turbo) return "turbo";
|
|
25690
|
+
if (flags.quiet) return "quiet";
|
|
25691
|
+
if (flags.sleep) return "sleep";
|
|
25692
|
+
if (flags.powerSave) return "eco";
|
|
25693
|
+
if (flags.steadyHeat) return "8c_heat";
|
|
25694
|
+
return "none";
|
|
25695
|
+
}
|
|
25696
|
+
/**
|
|
25697
|
+
* Resolve a requested `preset` string to the set of flag writes needed to make
|
|
25698
|
+
* it the active one — the chosen flag (if any) true, every other flag false.
|
|
25699
|
+
* Returns null when the string is not a known Gree preset. Pure.
|
|
25700
|
+
*/
|
|
25701
|
+
function presetToFlagWrites(preset) {
|
|
25702
|
+
if (!GREE_PRESETS.includes(preset)) return null;
|
|
25703
|
+
return {
|
|
25704
|
+
turbo: preset === "turbo",
|
|
25705
|
+
quiet: preset === "quiet",
|
|
25706
|
+
sleep: preset === "sleep",
|
|
25707
|
+
powerSave: preset === "eco",
|
|
25708
|
+
steadyHeat: preset === "8c_heat"
|
|
25709
|
+
};
|
|
25710
|
+
}
|
|
25539
25711
|
//#endregion
|
|
25540
25712
|
//#region src/devices/gree-ac-device.ts
|
|
25541
25713
|
var CLIMATE_CAP = "climate-control";
|
|
@@ -25544,9 +25716,9 @@ var CLIMATE_COLD_START = {
|
|
|
25544
25716
|
mode: "off",
|
|
25545
25717
|
availableModes: [...ADVERTISED_CAP_MODES],
|
|
25546
25718
|
fanMode: "",
|
|
25547
|
-
availableFanModes: [],
|
|
25719
|
+
availableFanModes: [...GREE_FAN_MODES],
|
|
25548
25720
|
preset: "",
|
|
25549
|
-
availablePresets: [],
|
|
25721
|
+
availablePresets: [...GREE_PRESETS],
|
|
25550
25722
|
target: null,
|
|
25551
25723
|
targetHigh: null,
|
|
25552
25724
|
targetLow: null,
|
|
@@ -25582,17 +25754,21 @@ var greeAcSchema = object({
|
|
|
25582
25754
|
* `stateChanged` push (and seeds on activate).
|
|
25583
25755
|
*
|
|
25584
25756
|
* Climate commands route to the bound handle: setMode `off`→`setPower(false)`,
|
|
25585
|
-
* any other→`setPower(true)`+`setMode()`; setTarget→`setTargetTemperature()
|
|
25586
|
-
*
|
|
25757
|
+
* any other→`setPower(true)`+`setMode()`; setTarget→`setTargetTemperature()`;
|
|
25758
|
+
* setFanMode→`setFanSpeed()` (climate `fanMode` string ↔ Gree speed); setPreset→
|
|
25759
|
+
* the comfort-flag setters (turbo/quiet/sleep/eco/8c_heat → `setTurbo`/`setQuiet`/
|
|
25760
|
+
* `setSleep`/`setPowerSave`/`setSteadyHeat`, exclusive). Fan commands:
|
|
25761
|
+
* setPercentage→`setFanSpeed()` (percentage↔FanSpeed bucket);
|
|
25587
25762
|
* setOscillating→`setSwingVertical(FullSwing|Default)`.
|
|
25588
25763
|
*
|
|
25589
|
-
* TODO (deferred):
|
|
25590
|
-
*
|
|
25591
|
-
*
|
|
25592
|
-
*
|
|
25593
|
-
*
|
|
25594
|
-
*
|
|
25595
|
-
*
|
|
25764
|
+
* TODO (deferred — needs protocol RE / live confirmation): `heat_cool`
|
|
25765
|
+
* dual-setpoint (Gree single-setpoint ACs have none), `setTargetHumidity`
|
|
25766
|
+
* (`Dwet`/`DwatSen` dehumidifier props exist in PROPS but the library exposes no
|
|
25767
|
+
* getter/setter yet), the light toggle (`setLight`), X-Fan / fresh-air / health
|
|
25768
|
+
* toggles (`setXfan`/`setFreshAir`/`setHealth`) — all real library setters with
|
|
25769
|
+
* no cap surface (a vendor toggle cap would carry them), and the fine-grained
|
|
25770
|
+
* 12-position vertical / 7-position horizontal swing (collapsed to a single
|
|
25771
|
+
* `oscillating` boolean — a vendor swing-position cap would carry them).
|
|
25596
25772
|
*/
|
|
25597
25773
|
var GreeAcDevice = class extends BaseDevice$1 {
|
|
25598
25774
|
features = [];
|
|
@@ -25670,10 +25846,19 @@ var GreeAcDevice = class extends BaseDevice$1 {
|
|
|
25670
25846
|
await ac.setMode(libMode);
|
|
25671
25847
|
},
|
|
25672
25848
|
setFanMode: async ({ fanMode }) => {
|
|
25673
|
-
|
|
25849
|
+
const speed = fanModeToFanSpeed(fanMode);
|
|
25850
|
+
if (speed === null) throw new Error(`gree ac: unsupported fan mode "${fanMode}"`);
|
|
25851
|
+
await this.requireAc().setFanSpeed(speed);
|
|
25674
25852
|
},
|
|
25675
25853
|
setPreset: async ({ preset }) => {
|
|
25676
|
-
|
|
25854
|
+
const writes = presetToFlagWrites(preset);
|
|
25855
|
+
if (writes === null) throw new Error(`gree ac: unsupported preset "${preset}"`);
|
|
25856
|
+
const ac = this.requireAc();
|
|
25857
|
+
if (ac.turbo !== writes.turbo) await ac.setTurbo(writes.turbo);
|
|
25858
|
+
if (ac.quiet !== writes.quiet) await ac.setQuiet(writes.quiet);
|
|
25859
|
+
if (ac.sleep !== writes.sleep) await ac.setSleep(writes.sleep);
|
|
25860
|
+
if (ac.powerSave !== writes.powerSave) await ac.setPowerSave(writes.powerSave);
|
|
25861
|
+
if (ac.steadyHeat !== writes.steadyHeat) await ac.setSteadyHeat(writes.steadyHeat);
|
|
25677
25862
|
},
|
|
25678
25863
|
setTarget: async ({ target }) => {
|
|
25679
25864
|
await this.requireAc().setTargetTemperature(target);
|
|
@@ -25707,13 +25892,21 @@ var GreeAcDevice = class extends BaseDevice$1 {
|
|
|
25707
25892
|
const ac = this.resolveAc();
|
|
25708
25893
|
if (ac === null) return;
|
|
25709
25894
|
const now = Date.now();
|
|
25895
|
+
const mode = ac.power ? libModeToCapMode(ac.mode) : "off";
|
|
25896
|
+
const preset = presetFromFlags({
|
|
25897
|
+
turbo: ac.turbo,
|
|
25898
|
+
quiet: ac.quiet,
|
|
25899
|
+
sleep: ac.sleep,
|
|
25900
|
+
powerSave: ac.powerSave,
|
|
25901
|
+
steadyHeat: ac.steadyHeat
|
|
25902
|
+
});
|
|
25710
25903
|
const climateSlice = {
|
|
25711
|
-
mode
|
|
25904
|
+
mode,
|
|
25712
25905
|
availableModes: [...ADVERTISED_CAP_MODES],
|
|
25713
|
-
fanMode:
|
|
25714
|
-
availableFanModes: [],
|
|
25715
|
-
preset
|
|
25716
|
-
availablePresets: [],
|
|
25906
|
+
fanMode: fanSpeedToFanMode(ac.fanSpeed),
|
|
25907
|
+
availableFanModes: [...GREE_FAN_MODES],
|
|
25908
|
+
preset,
|
|
25909
|
+
availablePresets: [...GREE_PRESETS],
|
|
25717
25910
|
target: ac.targetTemperature,
|
|
25718
25911
|
targetHigh: null,
|
|
25719
25912
|
targetLow: null,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-provider-gree",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"description": "Gree air-conditioner device-provider addon for CamStack — wraps the @apocaliss92/nodegree local-UDP client (LAN discovery + AES control), exposing climate-control and fan-control",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"camstack",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"instanceMode": "multiple",
|
|
45
45
|
"brokerKind": "gree",
|
|
46
46
|
"execution": {
|
|
47
|
-
"placement": "
|
|
47
|
+
"placement": "hub-only"
|
|
48
48
|
},
|
|
49
49
|
"capabilities": [
|
|
50
50
|
{
|