Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 18 additions & 8 deletions src/devices/sonoff.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2355,30 +2355,35 @@ const sonoffExtend = {
const exposes = e
.composite("cyclic_timed_irrigation", "cyclic_timed_irrigation", ea.ALL)
.withDescription("Smart water valve cycle timing irrigation")
.withFeature(e.numeric("current_count", ea.STATE).withDescription("Number of times it has been executed").withUnit("times"))
.withFeature(
e.numeric("current_count", ea.STATE).withDescription("Number of times it has been executed").withUnit("times").withDefault(0),
)
.withFeature(
e
.numeric("total_number", ea.STATE_SET)
.withDescription("Total times of circulating irrigation")
.withUnit("times")
.withValueMin(0)
.withValueMax(100),
.withValueMax(100)
.withDefault(1),
)
.withFeature(
e
.numeric("irrigation_duration", ea.STATE_SET)
.withDescription("Single irrigation duration")
.withUnit("seconds")
.withValueMin(0)
.withValueMax(86400),
.withValueMax(86400)
.withDefault(60),
)
.withFeature(
e
.numeric("irrigation_interval", ea.STATE_SET)
.withDescription("Time interval between two adjacent irrigation")
.withUnit("seconds")
.withValueMin(0)
.withValueMax(86400),
.withValueMax(86400)
.withDefault(60),
);
const fromZigbee = [
{
Expand Down Expand Up @@ -2477,30 +2482,35 @@ const sonoffExtend = {
const exposes = e
.composite("cyclic_quantitative_irrigation", "cyclic_quantitative_irrigation", ea.ALL)
.withDescription("Smart water valve circulating quantitative irrigation")
.withFeature(e.numeric("current_count", ea.STATE).withDescription("Number of times it has been executed").withUnit("times"))
.withFeature(
e.numeric("current_count", ea.STATE).withDescription("Number of times it has been executed").withUnit("times").withDefault(0),
)
.withFeature(
e
.numeric("total_number", ea.STATE_SET)
.withDescription("Total times of circulating irrigation")
.withUnit("times")
.withValueMin(0)
.withValueMax(100),
.withValueMax(100)
.withDefault(1),
)
.withFeature(
e
.numeric("irrigation_capacity", ea.STATE_SET)
.withDescription("Single irrigation capacity")
.withUnit("liter")
.withValueMin(0)
.withValueMax(6500),
.withValueMax(6500)
.withDefault(1),
)
.withFeature(
e
.numeric("irrigation_interval", ea.STATE_SET)
.withDescription("Time interval between two adjacent irrigation")
.withUnit("seconds")
.withValueMin(0)
.withValueMax(86400),
.withValueMax(86400)
.withDefault(60),
);
const fromZigbee = [
{
Expand Down
11 changes: 11 additions & 0 deletions src/lib/exposes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import type {Access, LevelConfigFeatures, Range} from "./types";
import {getLabelFromName} from "./utils";

export type Feature = Numeric | Binary | Enum | Composite | List | Text;
export type DefaultValue = number | string | boolean;
export interface HomeAssistant {
type?: "valve";
entityCategory?: "config" | "diagnostic";
Expand All @@ -32,6 +33,8 @@ export class Base {
description?: string;
features?: Feature[];
category?: "config" | "diagnostic";
// Cards need explicit defaults to build complete payloads for new atomic composites, which must be written as one object.
default?: DefaultValue;
homeassistant?: HomeAssistant;

withEndpoint(endpointName: string) {
Expand Down Expand Up @@ -81,6 +84,11 @@ export class Base {
return this;
}

withDefault(value: DefaultValue) {
this.default = value;
return this;
}

withHomeAssistant(homeassistant: HomeAssistant) {
this.homeassistant = homeassistant;
return this;
Expand Down Expand Up @@ -134,6 +142,9 @@ export class Base {
target.features = this.features.map((f) => f.clone());
}
target.category = this.category;
if (this.default !== undefined) {
target.default = this.default;
}
target.homeassistant = this.homeassistant ? {...this.homeassistant} : undefined;
}
}
Expand Down
25 changes: 25 additions & 0 deletions test/utils.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {beforeEach, describe, expect, it} from "vitest";
import type {Device} from "zigbee-herdsman/dist/controller/model";
import {access, presets} from "../src/lib/exposes";
import type {Tz} from "../src/lib/types";
import {batteryVoltageToPercentage, getFromLookup, getFromLookupByValue, getTransition, mapNumberRange, toNumber} from "../src/lib/utils";
import {mockDevice} from "./utils";
Expand Down Expand Up @@ -231,4 +232,28 @@ describe("utils", () => {
});
});
});

describe("exposes defaults", () => {
it("sets explicit defaults", () => {
const expose = presets.numeric("irrigation_duration", access.ALL).withDefault(60);

expect(expose.default).toBe(60);
});

it("preserves defaults when cloned", () => {
const expose = presets
.composite("cyclic_timed_irrigation", "cyclic_timed_irrigation", access.ALL)
.withFeature(presets.numeric("total_number", access.STATE_SET).withDefault(1));

const clone = expose.clone();

expect(clone.features[0].default).toBe(1);
});

it("does not serialize unset defaults", () => {
const expose = presets.numeric("irrigation_interval", access.ALL);

expect(JSON.parse(JSON.stringify(expose))).not.toHaveProperty("default");
});
});
});
Loading