@camstack/addon-provider-gree 0.1.4 → 0.1.6
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 +198 -34
- package/dist/addon.mjs +198 -34
- package/package.json +2 -2
package/dist/addon.js
CHANGED
|
@@ -4645,7 +4645,7 @@ function preprocess(fn, schema) {
|
|
|
4645
4645
|
});
|
|
4646
4646
|
}
|
|
4647
4647
|
//#endregion
|
|
4648
|
-
//#region ../types/dist/sleep-
|
|
4648
|
+
//#region ../types/dist/sleep-DVmKHFGi.mjs
|
|
4649
4649
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
4650
4650
|
EventCategory["SystemBoot"] = "system.boot";
|
|
4651
4651
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -6445,6 +6445,17 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
|
|
|
6445
6445
|
DeviceRole["HumiditySensor"] = "humidity-sensor";
|
|
6446
6446
|
DeviceRole["AmbientLightSensor"] = "ambient-light-sensor";
|
|
6447
6447
|
DeviceRole["PressureSensor"] = "pressure-sensor";
|
|
6448
|
+
/** Wind speed or direction (weather-station `wind-sensor` cap). */
|
|
6449
|
+
DeviceRole["WindSensor"] = "wind-sensor";
|
|
6450
|
+
/** Rain accumulation or rate (weather-station `rain-sensor` cap). */
|
|
6451
|
+
DeviceRole["RainSensor"] = "rain-sensor";
|
|
6452
|
+
/** UV index (weather-station `uv-sensor` cap). */
|
|
6453
|
+
DeviceRole["UvSensor"] = "uv-sensor";
|
|
6454
|
+
/** Solar irradiance W/m² (weather-station `solar-radiation-sensor` cap).
|
|
6455
|
+
* Distinct from AmbientLightSensor (lux). */
|
|
6456
|
+
DeviceRole["SolarRadiationSensor"] = "solar-radiation-sensor";
|
|
6457
|
+
/** Soil moisture % (garden/weather `soil-moisture-sensor` cap). */
|
|
6458
|
+
DeviceRole["SoilMoistureSensor"] = "soil-moisture-sensor";
|
|
6448
6459
|
DeviceRole["PowerSensor"] = "power-sensor";
|
|
6449
6460
|
DeviceRole["EnergySensor"] = "energy-sensor";
|
|
6450
6461
|
DeviceRole["VoltageSensor"] = "voltage-sensor";
|
|
@@ -10069,15 +10080,18 @@ var humiditySensorCapability = {
|
|
|
10069
10080
|
runtimeState: HumiditySensorStatusSchema
|
|
10070
10081
|
};
|
|
10071
10082
|
/**
|
|
10072
|
-
* Image display cap. Models
|
|
10073
|
-
*
|
|
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.
|
|
10074
10085
|
*
|
|
10075
|
-
* Read-only: there are no setters. The provider resolves
|
|
10076
|
-
*
|
|
10077
|
-
*
|
|
10078
|
-
*
|
|
10079
|
-
*
|
|
10080
|
-
*
|
|
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.
|
|
10081
10095
|
*/
|
|
10082
10096
|
var ImageStatusSchema = object({
|
|
10083
10097
|
/** Absolute signed URL the browser loads directly. Null when the
|
|
@@ -10103,18 +10117,47 @@ var imageCapability = {
|
|
|
10103
10117
|
*/
|
|
10104
10118
|
runtimeState: ImageStatusSchema
|
|
10105
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
|
+
]);
|
|
10106
10144
|
var LawnMowerControlStatusSchema = object({
|
|
10107
10145
|
/** Lifecycle activity of the mower. */
|
|
10108
|
-
activity:
|
|
10109
|
-
"idle",
|
|
10110
|
-
"mowing",
|
|
10111
|
-
"paused",
|
|
10112
|
-
"docked",
|
|
10113
|
-
"error"
|
|
10114
|
-
]),
|
|
10146
|
+
activity: LawnMowerActivitySchema,
|
|
10115
10147
|
/** 0..100 battery percentage. Null when the device has no battery
|
|
10116
10148
|
* reading. */
|
|
10117
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,
|
|
10118
10161
|
/** Ms epoch when the slice was last updated. */
|
|
10119
10162
|
lastChangedAt: number()
|
|
10120
10163
|
});
|
|
@@ -12340,6 +12383,7 @@ var VacuumStateSchema = _enum([
|
|
|
12340
12383
|
"paused",
|
|
12341
12384
|
"returning",
|
|
12342
12385
|
"docked",
|
|
12386
|
+
"drying",
|
|
12343
12387
|
"error"
|
|
12344
12388
|
]);
|
|
12345
12389
|
/**
|
|
@@ -12378,6 +12422,12 @@ var VacuumControlStatusSchema = object({
|
|
|
12378
12422
|
detergent: TankStatusSchema.nullable(),
|
|
12379
12423
|
/** Dust bin. Null when the hardware has no dust bin. */
|
|
12380
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(),
|
|
12381
12431
|
/** Ms epoch when the slice was last updated. */
|
|
12382
12432
|
lastChangedAt: number()
|
|
12383
12433
|
});
|
|
@@ -16893,6 +16943,9 @@ method(object({
|
|
|
16893
16943
|
}), method(ReleaseInputSchema.extend({ addonId: string() }), _void(), {
|
|
16894
16944
|
kind: "mutation",
|
|
16895
16945
|
auth: "admin"
|
|
16946
|
+
}), method(ResyncInputSchema, ResyncResultSchema, {
|
|
16947
|
+
kind: "mutation",
|
|
16948
|
+
auth: "admin"
|
|
16896
16949
|
}), method(object({
|
|
16897
16950
|
deviceId: number(),
|
|
16898
16951
|
key: string(),
|
|
@@ -20655,6 +20708,12 @@ Object.freeze({
|
|
|
20655
20708
|
addonId: null,
|
|
20656
20709
|
access: "create"
|
|
20657
20710
|
},
|
|
20711
|
+
"deviceManager.adoptionResync": {
|
|
20712
|
+
capName: "device-manager",
|
|
20713
|
+
capScope: "system",
|
|
20714
|
+
addonId: null,
|
|
20715
|
+
access: "create"
|
|
20716
|
+
},
|
|
20658
20717
|
"deviceManager.allocateDeviceId": {
|
|
20659
20718
|
capName: "device-manager",
|
|
20660
20719
|
capScope: "system",
|
|
@@ -25526,6 +25585,90 @@ function swingToOscillating(vertical, horizontal) {
|
|
|
25526
25585
|
function oscillatingToVerticalSwing(oscillating) {
|
|
25527
25586
|
return oscillating ? VerticalSwing.FullSwing : VerticalSwing.Default;
|
|
25528
25587
|
}
|
|
25588
|
+
/**
|
|
25589
|
+
* Gree fan-speed names surfaced on the `climate-control` cap's `fanMode` /
|
|
25590
|
+
* `availableFanModes` strings, mirroring the HA Gree integration's `fan_modes`
|
|
25591
|
+
* attribute (`auto`/`low`/`medium_low`/`medium`/`medium_high`/`high`).
|
|
25592
|
+
*
|
|
25593
|
+
* NOTE: HA's Gree integration also folds `turbo` and `quiet` INTO `fan_modes`.
|
|
25594
|
+
* We deliberately keep turbo/quiet on the dedicated `preset` surface instead
|
|
25595
|
+
* (they are independent boolean device flags in the protocol — `Tur` / `Quiet`
|
|
25596
|
+
* — not points on the `WdSpd` speed axis), so the speed picker stays a pure
|
|
25597
|
+
* speed axis and the two flags stay independently togglable. The `fan-control`
|
|
25598
|
+
* percentage surface continues to mirror the same `WdSpd` speed for the
|
|
25599
|
+
* fan-style UI.
|
|
25600
|
+
*/
|
|
25601
|
+
var GREE_FAN_MODES = [
|
|
25602
|
+
"auto",
|
|
25603
|
+
"low",
|
|
25604
|
+
"medium_low",
|
|
25605
|
+
"medium",
|
|
25606
|
+
"medium_high",
|
|
25607
|
+
"high"
|
|
25608
|
+
];
|
|
25609
|
+
/** Map a library {@link FanSpeed} to its `climate-control` `fanMode` string. Pure. */
|
|
25610
|
+
function fanSpeedToFanMode(speed) {
|
|
25611
|
+
switch (speed) {
|
|
25612
|
+
case FanSpeed.Auto: return "auto";
|
|
25613
|
+
case FanSpeed.Low: return "low";
|
|
25614
|
+
case FanSpeed.MediumLow: return "medium_low";
|
|
25615
|
+
case FanSpeed.Medium: return "medium";
|
|
25616
|
+
case FanSpeed.MediumHigh: return "medium_high";
|
|
25617
|
+
case FanSpeed.High: return "high";
|
|
25618
|
+
}
|
|
25619
|
+
}
|
|
25620
|
+
/**
|
|
25621
|
+
* Map a `climate-control` `fanMode` string back to a library {@link FanSpeed},
|
|
25622
|
+
* or null when the string is not a known Gree speed. Pure.
|
|
25623
|
+
*/
|
|
25624
|
+
function fanModeToFanSpeed(fanMode) {
|
|
25625
|
+
switch (fanMode) {
|
|
25626
|
+
case "auto": return FanSpeed.Auto;
|
|
25627
|
+
case "low": return FanSpeed.Low;
|
|
25628
|
+
case "medium_low": return FanSpeed.MediumLow;
|
|
25629
|
+
case "medium": return FanSpeed.Medium;
|
|
25630
|
+
case "medium_high": return FanSpeed.MediumHigh;
|
|
25631
|
+
case "high": return FanSpeed.High;
|
|
25632
|
+
default: return null;
|
|
25633
|
+
}
|
|
25634
|
+
}
|
|
25635
|
+
var GREE_PRESETS = [
|
|
25636
|
+
"none",
|
|
25637
|
+
"turbo",
|
|
25638
|
+
"quiet",
|
|
25639
|
+
"sleep",
|
|
25640
|
+
"eco",
|
|
25641
|
+
"8c_heat"
|
|
25642
|
+
];
|
|
25643
|
+
/**
|
|
25644
|
+
* Derive the single active `preset` string from the device's comfort flags.
|
|
25645
|
+
* Precedence is fixed (turbo > quiet > sleep > eco > 8c_heat) so a coherent
|
|
25646
|
+
* single value is reported even if the device has more than one flag set.
|
|
25647
|
+
* Returns `'none'` when no flag is set. Pure.
|
|
25648
|
+
*/
|
|
25649
|
+
function presetFromFlags(flags) {
|
|
25650
|
+
if (flags.turbo) return "turbo";
|
|
25651
|
+
if (flags.quiet) return "quiet";
|
|
25652
|
+
if (flags.sleep) return "sleep";
|
|
25653
|
+
if (flags.powerSave) return "eco";
|
|
25654
|
+
if (flags.steadyHeat) return "8c_heat";
|
|
25655
|
+
return "none";
|
|
25656
|
+
}
|
|
25657
|
+
/**
|
|
25658
|
+
* Resolve a requested `preset` string to the set of flag writes needed to make
|
|
25659
|
+
* it the active one — the chosen flag (if any) true, every other flag false.
|
|
25660
|
+
* Returns null when the string is not a known Gree preset. Pure.
|
|
25661
|
+
*/
|
|
25662
|
+
function presetToFlagWrites(preset) {
|
|
25663
|
+
if (!GREE_PRESETS.includes(preset)) return null;
|
|
25664
|
+
return {
|
|
25665
|
+
turbo: preset === "turbo",
|
|
25666
|
+
quiet: preset === "quiet",
|
|
25667
|
+
sleep: preset === "sleep",
|
|
25668
|
+
powerSave: preset === "eco",
|
|
25669
|
+
steadyHeat: preset === "8c_heat"
|
|
25670
|
+
};
|
|
25671
|
+
}
|
|
25529
25672
|
//#endregion
|
|
25530
25673
|
//#region src/devices/gree-ac-device.ts
|
|
25531
25674
|
var CLIMATE_CAP = "climate-control";
|
|
@@ -25534,9 +25677,9 @@ var CLIMATE_COLD_START = {
|
|
|
25534
25677
|
mode: "off",
|
|
25535
25678
|
availableModes: [...ADVERTISED_CAP_MODES],
|
|
25536
25679
|
fanMode: "",
|
|
25537
|
-
availableFanModes: [],
|
|
25680
|
+
availableFanModes: [...GREE_FAN_MODES],
|
|
25538
25681
|
preset: "",
|
|
25539
|
-
availablePresets: [],
|
|
25682
|
+
availablePresets: [...GREE_PRESETS],
|
|
25540
25683
|
target: null,
|
|
25541
25684
|
targetHigh: null,
|
|
25542
25685
|
targetLow: null,
|
|
@@ -25572,17 +25715,21 @@ var greeAcSchema = object({
|
|
|
25572
25715
|
* `stateChanged` push (and seeds on activate).
|
|
25573
25716
|
*
|
|
25574
25717
|
* Climate commands route to the bound handle: setMode `off`→`setPower(false)`,
|
|
25575
|
-
* any other→`setPower(true)`+`setMode()`; setTarget→`setTargetTemperature()
|
|
25576
|
-
*
|
|
25718
|
+
* any other→`setPower(true)`+`setMode()`; setTarget→`setTargetTemperature()`;
|
|
25719
|
+
* setFanMode→`setFanSpeed()` (climate `fanMode` string ↔ Gree speed); setPreset→
|
|
25720
|
+
* the comfort-flag setters (turbo/quiet/sleep/eco/8c_heat → `setTurbo`/`setQuiet`/
|
|
25721
|
+
* `setSleep`/`setPowerSave`/`setSteadyHeat`, exclusive). Fan commands:
|
|
25722
|
+
* setPercentage→`setFanSpeed()` (percentage↔FanSpeed bucket);
|
|
25577
25723
|
* setOscillating→`setSwingVertical(FullSwing|Default)`.
|
|
25578
25724
|
*
|
|
25579
|
-
* TODO (deferred):
|
|
25580
|
-
*
|
|
25581
|
-
*
|
|
25582
|
-
*
|
|
25583
|
-
*
|
|
25584
|
-
*
|
|
25585
|
-
*
|
|
25725
|
+
* TODO (deferred — needs protocol RE / live confirmation): `heat_cool`
|
|
25726
|
+
* dual-setpoint (Gree single-setpoint ACs have none), `setTargetHumidity`
|
|
25727
|
+
* (`Dwet`/`DwatSen` dehumidifier props exist in PROPS but the library exposes no
|
|
25728
|
+
* getter/setter yet), the light toggle (`setLight`), X-Fan / fresh-air / health
|
|
25729
|
+
* toggles (`setXfan`/`setFreshAir`/`setHealth`) — all real library setters with
|
|
25730
|
+
* no cap surface (a vendor toggle cap would carry them), and the fine-grained
|
|
25731
|
+
* 12-position vertical / 7-position horizontal swing (collapsed to a single
|
|
25732
|
+
* `oscillating` boolean — a vendor swing-position cap would carry them).
|
|
25586
25733
|
*/
|
|
25587
25734
|
var GreeAcDevice = class extends BaseDevice$1 {
|
|
25588
25735
|
features = [];
|
|
@@ -25660,10 +25807,19 @@ var GreeAcDevice = class extends BaseDevice$1 {
|
|
|
25660
25807
|
await ac.setMode(libMode);
|
|
25661
25808
|
},
|
|
25662
25809
|
setFanMode: async ({ fanMode }) => {
|
|
25663
|
-
|
|
25810
|
+
const speed = fanModeToFanSpeed(fanMode);
|
|
25811
|
+
if (speed === null) throw new Error(`gree ac: unsupported fan mode "${fanMode}"`);
|
|
25812
|
+
await this.requireAc().setFanSpeed(speed);
|
|
25664
25813
|
},
|
|
25665
25814
|
setPreset: async ({ preset }) => {
|
|
25666
|
-
|
|
25815
|
+
const writes = presetToFlagWrites(preset);
|
|
25816
|
+
if (writes === null) throw new Error(`gree ac: unsupported preset "${preset}"`);
|
|
25817
|
+
const ac = this.requireAc();
|
|
25818
|
+
if (ac.turbo !== writes.turbo) await ac.setTurbo(writes.turbo);
|
|
25819
|
+
if (ac.quiet !== writes.quiet) await ac.setQuiet(writes.quiet);
|
|
25820
|
+
if (ac.sleep !== writes.sleep) await ac.setSleep(writes.sleep);
|
|
25821
|
+
if (ac.powerSave !== writes.powerSave) await ac.setPowerSave(writes.powerSave);
|
|
25822
|
+
if (ac.steadyHeat !== writes.steadyHeat) await ac.setSteadyHeat(writes.steadyHeat);
|
|
25667
25823
|
},
|
|
25668
25824
|
setTarget: async ({ target }) => {
|
|
25669
25825
|
await this.requireAc().setTargetTemperature(target);
|
|
@@ -25697,13 +25853,21 @@ var GreeAcDevice = class extends BaseDevice$1 {
|
|
|
25697
25853
|
const ac = this.resolveAc();
|
|
25698
25854
|
if (ac === null) return;
|
|
25699
25855
|
const now = Date.now();
|
|
25856
|
+
const mode = ac.power ? libModeToCapMode(ac.mode) : "off";
|
|
25857
|
+
const preset = presetFromFlags({
|
|
25858
|
+
turbo: ac.turbo,
|
|
25859
|
+
quiet: ac.quiet,
|
|
25860
|
+
sleep: ac.sleep,
|
|
25861
|
+
powerSave: ac.powerSave,
|
|
25862
|
+
steadyHeat: ac.steadyHeat
|
|
25863
|
+
});
|
|
25700
25864
|
const climateSlice = {
|
|
25701
|
-
mode
|
|
25865
|
+
mode,
|
|
25702
25866
|
availableModes: [...ADVERTISED_CAP_MODES],
|
|
25703
|
-
fanMode:
|
|
25704
|
-
availableFanModes: [],
|
|
25705
|
-
preset
|
|
25706
|
-
availablePresets: [],
|
|
25867
|
+
fanMode: fanSpeedToFanMode(ac.fanSpeed),
|
|
25868
|
+
availableFanModes: [...GREE_FAN_MODES],
|
|
25869
|
+
preset,
|
|
25870
|
+
availablePresets: [...GREE_PRESETS],
|
|
25707
25871
|
target: ac.targetTemperature,
|
|
25708
25872
|
targetHigh: null,
|
|
25709
25873
|
targetLow: null,
|
package/dist/addon.mjs
CHANGED
|
@@ -4644,7 +4644,7 @@ function preprocess(fn, schema) {
|
|
|
4644
4644
|
});
|
|
4645
4645
|
}
|
|
4646
4646
|
//#endregion
|
|
4647
|
-
//#region ../types/dist/sleep-
|
|
4647
|
+
//#region ../types/dist/sleep-DVmKHFGi.mjs
|
|
4648
4648
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
4649
4649
|
EventCategory["SystemBoot"] = "system.boot";
|
|
4650
4650
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -6444,6 +6444,17 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
|
|
|
6444
6444
|
DeviceRole["HumiditySensor"] = "humidity-sensor";
|
|
6445
6445
|
DeviceRole["AmbientLightSensor"] = "ambient-light-sensor";
|
|
6446
6446
|
DeviceRole["PressureSensor"] = "pressure-sensor";
|
|
6447
|
+
/** Wind speed or direction (weather-station `wind-sensor` cap). */
|
|
6448
|
+
DeviceRole["WindSensor"] = "wind-sensor";
|
|
6449
|
+
/** Rain accumulation or rate (weather-station `rain-sensor` cap). */
|
|
6450
|
+
DeviceRole["RainSensor"] = "rain-sensor";
|
|
6451
|
+
/** UV index (weather-station `uv-sensor` cap). */
|
|
6452
|
+
DeviceRole["UvSensor"] = "uv-sensor";
|
|
6453
|
+
/** Solar irradiance W/m² (weather-station `solar-radiation-sensor` cap).
|
|
6454
|
+
* Distinct from AmbientLightSensor (lux). */
|
|
6455
|
+
DeviceRole["SolarRadiationSensor"] = "solar-radiation-sensor";
|
|
6456
|
+
/** Soil moisture % (garden/weather `soil-moisture-sensor` cap). */
|
|
6457
|
+
DeviceRole["SoilMoistureSensor"] = "soil-moisture-sensor";
|
|
6447
6458
|
DeviceRole["PowerSensor"] = "power-sensor";
|
|
6448
6459
|
DeviceRole["EnergySensor"] = "energy-sensor";
|
|
6449
6460
|
DeviceRole["VoltageSensor"] = "voltage-sensor";
|
|
@@ -10068,15 +10079,18 @@ var humiditySensorCapability = {
|
|
|
10068
10079
|
runtimeState: HumiditySensorStatusSchema
|
|
10069
10080
|
};
|
|
10070
10081
|
/**
|
|
10071
|
-
* Image display cap. Models
|
|
10072
|
-
*
|
|
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.
|
|
10073
10084
|
*
|
|
10074
|
-
* Read-only: there are no setters. The provider resolves
|
|
10075
|
-
*
|
|
10076
|
-
*
|
|
10077
|
-
*
|
|
10078
|
-
*
|
|
10079
|
-
*
|
|
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.
|
|
10080
10094
|
*/
|
|
10081
10095
|
var ImageStatusSchema = object({
|
|
10082
10096
|
/** Absolute signed URL the browser loads directly. Null when the
|
|
@@ -10102,18 +10116,47 @@ var imageCapability = {
|
|
|
10102
10116
|
*/
|
|
10103
10117
|
runtimeState: ImageStatusSchema
|
|
10104
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
|
+
]);
|
|
10105
10143
|
var LawnMowerControlStatusSchema = object({
|
|
10106
10144
|
/** Lifecycle activity of the mower. */
|
|
10107
|
-
activity:
|
|
10108
|
-
"idle",
|
|
10109
|
-
"mowing",
|
|
10110
|
-
"paused",
|
|
10111
|
-
"docked",
|
|
10112
|
-
"error"
|
|
10113
|
-
]),
|
|
10145
|
+
activity: LawnMowerActivitySchema,
|
|
10114
10146
|
/** 0..100 battery percentage. Null when the device has no battery
|
|
10115
10147
|
* reading. */
|
|
10116
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,
|
|
10117
10160
|
/** Ms epoch when the slice was last updated. */
|
|
10118
10161
|
lastChangedAt: number()
|
|
10119
10162
|
});
|
|
@@ -12339,6 +12382,7 @@ var VacuumStateSchema = _enum([
|
|
|
12339
12382
|
"paused",
|
|
12340
12383
|
"returning",
|
|
12341
12384
|
"docked",
|
|
12385
|
+
"drying",
|
|
12342
12386
|
"error"
|
|
12343
12387
|
]);
|
|
12344
12388
|
/**
|
|
@@ -12377,6 +12421,12 @@ var VacuumControlStatusSchema = object({
|
|
|
12377
12421
|
detergent: TankStatusSchema.nullable(),
|
|
12378
12422
|
/** Dust bin. Null when the hardware has no dust bin. */
|
|
12379
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(),
|
|
12380
12430
|
/** Ms epoch when the slice was last updated. */
|
|
12381
12431
|
lastChangedAt: number()
|
|
12382
12432
|
});
|
|
@@ -16892,6 +16942,9 @@ method(object({
|
|
|
16892
16942
|
}), method(ReleaseInputSchema.extend({ addonId: string() }), _void(), {
|
|
16893
16943
|
kind: "mutation",
|
|
16894
16944
|
auth: "admin"
|
|
16945
|
+
}), method(ResyncInputSchema, ResyncResultSchema, {
|
|
16946
|
+
kind: "mutation",
|
|
16947
|
+
auth: "admin"
|
|
16895
16948
|
}), method(object({
|
|
16896
16949
|
deviceId: number(),
|
|
16897
16950
|
key: string(),
|
|
@@ -20654,6 +20707,12 @@ Object.freeze({
|
|
|
20654
20707
|
addonId: null,
|
|
20655
20708
|
access: "create"
|
|
20656
20709
|
},
|
|
20710
|
+
"deviceManager.adoptionResync": {
|
|
20711
|
+
capName: "device-manager",
|
|
20712
|
+
capScope: "system",
|
|
20713
|
+
addonId: null,
|
|
20714
|
+
access: "create"
|
|
20715
|
+
},
|
|
20657
20716
|
"deviceManager.allocateDeviceId": {
|
|
20658
20717
|
capName: "device-manager",
|
|
20659
20718
|
capScope: "system",
|
|
@@ -25525,6 +25584,90 @@ function swingToOscillating(vertical, horizontal) {
|
|
|
25525
25584
|
function oscillatingToVerticalSwing(oscillating) {
|
|
25526
25585
|
return oscillating ? VerticalSwing.FullSwing : VerticalSwing.Default;
|
|
25527
25586
|
}
|
|
25587
|
+
/**
|
|
25588
|
+
* Gree fan-speed names surfaced on the `climate-control` cap's `fanMode` /
|
|
25589
|
+
* `availableFanModes` strings, mirroring the HA Gree integration's `fan_modes`
|
|
25590
|
+
* attribute (`auto`/`low`/`medium_low`/`medium`/`medium_high`/`high`).
|
|
25591
|
+
*
|
|
25592
|
+
* NOTE: HA's Gree integration also folds `turbo` and `quiet` INTO `fan_modes`.
|
|
25593
|
+
* We deliberately keep turbo/quiet on the dedicated `preset` surface instead
|
|
25594
|
+
* (they are independent boolean device flags in the protocol — `Tur` / `Quiet`
|
|
25595
|
+
* — not points on the `WdSpd` speed axis), so the speed picker stays a pure
|
|
25596
|
+
* speed axis and the two flags stay independently togglable. The `fan-control`
|
|
25597
|
+
* percentage surface continues to mirror the same `WdSpd` speed for the
|
|
25598
|
+
* fan-style UI.
|
|
25599
|
+
*/
|
|
25600
|
+
var GREE_FAN_MODES = [
|
|
25601
|
+
"auto",
|
|
25602
|
+
"low",
|
|
25603
|
+
"medium_low",
|
|
25604
|
+
"medium",
|
|
25605
|
+
"medium_high",
|
|
25606
|
+
"high"
|
|
25607
|
+
];
|
|
25608
|
+
/** Map a library {@link FanSpeed} to its `climate-control` `fanMode` string. Pure. */
|
|
25609
|
+
function fanSpeedToFanMode(speed) {
|
|
25610
|
+
switch (speed) {
|
|
25611
|
+
case FanSpeed.Auto: return "auto";
|
|
25612
|
+
case FanSpeed.Low: return "low";
|
|
25613
|
+
case FanSpeed.MediumLow: return "medium_low";
|
|
25614
|
+
case FanSpeed.Medium: return "medium";
|
|
25615
|
+
case FanSpeed.MediumHigh: return "medium_high";
|
|
25616
|
+
case FanSpeed.High: return "high";
|
|
25617
|
+
}
|
|
25618
|
+
}
|
|
25619
|
+
/**
|
|
25620
|
+
* Map a `climate-control` `fanMode` string back to a library {@link FanSpeed},
|
|
25621
|
+
* or null when the string is not a known Gree speed. Pure.
|
|
25622
|
+
*/
|
|
25623
|
+
function fanModeToFanSpeed(fanMode) {
|
|
25624
|
+
switch (fanMode) {
|
|
25625
|
+
case "auto": return FanSpeed.Auto;
|
|
25626
|
+
case "low": return FanSpeed.Low;
|
|
25627
|
+
case "medium_low": return FanSpeed.MediumLow;
|
|
25628
|
+
case "medium": return FanSpeed.Medium;
|
|
25629
|
+
case "medium_high": return FanSpeed.MediumHigh;
|
|
25630
|
+
case "high": return FanSpeed.High;
|
|
25631
|
+
default: return null;
|
|
25632
|
+
}
|
|
25633
|
+
}
|
|
25634
|
+
var GREE_PRESETS = [
|
|
25635
|
+
"none",
|
|
25636
|
+
"turbo",
|
|
25637
|
+
"quiet",
|
|
25638
|
+
"sleep",
|
|
25639
|
+
"eco",
|
|
25640
|
+
"8c_heat"
|
|
25641
|
+
];
|
|
25642
|
+
/**
|
|
25643
|
+
* Derive the single active `preset` string from the device's comfort flags.
|
|
25644
|
+
* Precedence is fixed (turbo > quiet > sleep > eco > 8c_heat) so a coherent
|
|
25645
|
+
* single value is reported even if the device has more than one flag set.
|
|
25646
|
+
* Returns `'none'` when no flag is set. Pure.
|
|
25647
|
+
*/
|
|
25648
|
+
function presetFromFlags(flags) {
|
|
25649
|
+
if (flags.turbo) return "turbo";
|
|
25650
|
+
if (flags.quiet) return "quiet";
|
|
25651
|
+
if (flags.sleep) return "sleep";
|
|
25652
|
+
if (flags.powerSave) return "eco";
|
|
25653
|
+
if (flags.steadyHeat) return "8c_heat";
|
|
25654
|
+
return "none";
|
|
25655
|
+
}
|
|
25656
|
+
/**
|
|
25657
|
+
* Resolve a requested `preset` string to the set of flag writes needed to make
|
|
25658
|
+
* it the active one — the chosen flag (if any) true, every other flag false.
|
|
25659
|
+
* Returns null when the string is not a known Gree preset. Pure.
|
|
25660
|
+
*/
|
|
25661
|
+
function presetToFlagWrites(preset) {
|
|
25662
|
+
if (!GREE_PRESETS.includes(preset)) return null;
|
|
25663
|
+
return {
|
|
25664
|
+
turbo: preset === "turbo",
|
|
25665
|
+
quiet: preset === "quiet",
|
|
25666
|
+
sleep: preset === "sleep",
|
|
25667
|
+
powerSave: preset === "eco",
|
|
25668
|
+
steadyHeat: preset === "8c_heat"
|
|
25669
|
+
};
|
|
25670
|
+
}
|
|
25528
25671
|
//#endregion
|
|
25529
25672
|
//#region src/devices/gree-ac-device.ts
|
|
25530
25673
|
var CLIMATE_CAP = "climate-control";
|
|
@@ -25533,9 +25676,9 @@ var CLIMATE_COLD_START = {
|
|
|
25533
25676
|
mode: "off",
|
|
25534
25677
|
availableModes: [...ADVERTISED_CAP_MODES],
|
|
25535
25678
|
fanMode: "",
|
|
25536
|
-
availableFanModes: [],
|
|
25679
|
+
availableFanModes: [...GREE_FAN_MODES],
|
|
25537
25680
|
preset: "",
|
|
25538
|
-
availablePresets: [],
|
|
25681
|
+
availablePresets: [...GREE_PRESETS],
|
|
25539
25682
|
target: null,
|
|
25540
25683
|
targetHigh: null,
|
|
25541
25684
|
targetLow: null,
|
|
@@ -25571,17 +25714,21 @@ var greeAcSchema = object({
|
|
|
25571
25714
|
* `stateChanged` push (and seeds on activate).
|
|
25572
25715
|
*
|
|
25573
25716
|
* Climate commands route to the bound handle: setMode `off`→`setPower(false)`,
|
|
25574
|
-
* any other→`setPower(true)`+`setMode()`; setTarget→`setTargetTemperature()
|
|
25575
|
-
*
|
|
25717
|
+
* any other→`setPower(true)`+`setMode()`; setTarget→`setTargetTemperature()`;
|
|
25718
|
+
* setFanMode→`setFanSpeed()` (climate `fanMode` string ↔ Gree speed); setPreset→
|
|
25719
|
+
* the comfort-flag setters (turbo/quiet/sleep/eco/8c_heat → `setTurbo`/`setQuiet`/
|
|
25720
|
+
* `setSleep`/`setPowerSave`/`setSteadyHeat`, exclusive). Fan commands:
|
|
25721
|
+
* setPercentage→`setFanSpeed()` (percentage↔FanSpeed bucket);
|
|
25576
25722
|
* setOscillating→`setSwingVertical(FullSwing|Default)`.
|
|
25577
25723
|
*
|
|
25578
|
-
* TODO (deferred):
|
|
25579
|
-
*
|
|
25580
|
-
*
|
|
25581
|
-
*
|
|
25582
|
-
*
|
|
25583
|
-
*
|
|
25584
|
-
*
|
|
25724
|
+
* TODO (deferred — needs protocol RE / live confirmation): `heat_cool`
|
|
25725
|
+
* dual-setpoint (Gree single-setpoint ACs have none), `setTargetHumidity`
|
|
25726
|
+
* (`Dwet`/`DwatSen` dehumidifier props exist in PROPS but the library exposes no
|
|
25727
|
+
* getter/setter yet), the light toggle (`setLight`), X-Fan / fresh-air / health
|
|
25728
|
+
* toggles (`setXfan`/`setFreshAir`/`setHealth`) — all real library setters with
|
|
25729
|
+
* no cap surface (a vendor toggle cap would carry them), and the fine-grained
|
|
25730
|
+
* 12-position vertical / 7-position horizontal swing (collapsed to a single
|
|
25731
|
+
* `oscillating` boolean — a vendor swing-position cap would carry them).
|
|
25585
25732
|
*/
|
|
25586
25733
|
var GreeAcDevice = class extends BaseDevice$1 {
|
|
25587
25734
|
features = [];
|
|
@@ -25659,10 +25806,19 @@ var GreeAcDevice = class extends BaseDevice$1 {
|
|
|
25659
25806
|
await ac.setMode(libMode);
|
|
25660
25807
|
},
|
|
25661
25808
|
setFanMode: async ({ fanMode }) => {
|
|
25662
|
-
|
|
25809
|
+
const speed = fanModeToFanSpeed(fanMode);
|
|
25810
|
+
if (speed === null) throw new Error(`gree ac: unsupported fan mode "${fanMode}"`);
|
|
25811
|
+
await this.requireAc().setFanSpeed(speed);
|
|
25663
25812
|
},
|
|
25664
25813
|
setPreset: async ({ preset }) => {
|
|
25665
|
-
|
|
25814
|
+
const writes = presetToFlagWrites(preset);
|
|
25815
|
+
if (writes === null) throw new Error(`gree ac: unsupported preset "${preset}"`);
|
|
25816
|
+
const ac = this.requireAc();
|
|
25817
|
+
if (ac.turbo !== writes.turbo) await ac.setTurbo(writes.turbo);
|
|
25818
|
+
if (ac.quiet !== writes.quiet) await ac.setQuiet(writes.quiet);
|
|
25819
|
+
if (ac.sleep !== writes.sleep) await ac.setSleep(writes.sleep);
|
|
25820
|
+
if (ac.powerSave !== writes.powerSave) await ac.setPowerSave(writes.powerSave);
|
|
25821
|
+
if (ac.steadyHeat !== writes.steadyHeat) await ac.setSteadyHeat(writes.steadyHeat);
|
|
25666
25822
|
},
|
|
25667
25823
|
setTarget: async ({ target }) => {
|
|
25668
25824
|
await this.requireAc().setTargetTemperature(target);
|
|
@@ -25696,13 +25852,21 @@ var GreeAcDevice = class extends BaseDevice$1 {
|
|
|
25696
25852
|
const ac = this.resolveAc();
|
|
25697
25853
|
if (ac === null) return;
|
|
25698
25854
|
const now = Date.now();
|
|
25855
|
+
const mode = ac.power ? libModeToCapMode(ac.mode) : "off";
|
|
25856
|
+
const preset = presetFromFlags({
|
|
25857
|
+
turbo: ac.turbo,
|
|
25858
|
+
quiet: ac.quiet,
|
|
25859
|
+
sleep: ac.sleep,
|
|
25860
|
+
powerSave: ac.powerSave,
|
|
25861
|
+
steadyHeat: ac.steadyHeat
|
|
25862
|
+
});
|
|
25699
25863
|
const climateSlice = {
|
|
25700
|
-
mode
|
|
25864
|
+
mode,
|
|
25701
25865
|
availableModes: [...ADVERTISED_CAP_MODES],
|
|
25702
|
-
fanMode:
|
|
25703
|
-
availableFanModes: [],
|
|
25704
|
-
preset
|
|
25705
|
-
availablePresets: [],
|
|
25866
|
+
fanMode: fanSpeedToFanMode(ac.fanSpeed),
|
|
25867
|
+
availableFanModes: [...GREE_FAN_MODES],
|
|
25868
|
+
preset,
|
|
25869
|
+
availablePresets: [...GREE_PRESETS],
|
|
25706
25870
|
target: ac.targetTemperature,
|
|
25707
25871
|
targetHigh: null,
|
|
25708
25872
|
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.6",
|
|
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
|
{
|