@seamapi/react 2.8.7 → 2.9.0

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.
@@ -1,21 +1,31 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import classNames from 'classnames';
3
- import { useState } from 'react';
3
+ import { useEffect, useState } from 'react';
4
+ import { debounce } from '../../../../lib/debounce.js';
4
5
  import { BeeIcon } from '../../../../lib/icons/Bee.js';
6
+ import { CheckBlackIcon } from '../../../../lib/icons/CheckBlack.js';
5
7
  import { ChevronWideIcon } from '../../../../lib/icons/ChevronWide.js';
6
8
  import { NestedClimateSettingScheduleTable } from '../../../../lib/seam/components/ClimateSettingScheduleTable/ClimateSettingScheduleTable.js';
7
9
  import { useConnectedAccount } from '../../../../lib/seam/connected-accounts/use-connected-account.js';
8
10
  import { useClimateSettingSchedules } from '../../../../lib/seam/thermostats/climate-setting-schedules/use-climate-setting-schedules.js';
11
+ import { useCoolThermostat } from '../../../../lib/seam/thermostats/use-cool-thermostat.js';
12
+ import { useHeatCoolThermostat } from '../../../../lib/seam/thermostats/use-heat-cool-thermostat.js';
13
+ import { useHeatThermostat } from '../../../../lib/seam/thermostats/use-heat-thermostat.js';
14
+ import { useSetThermostatOff } from '../../../../lib/seam/thermostats/use-set-thermostat-off.js';
9
15
  import { useUpdateFanMode } from '../../../../lib/seam/thermostats/use-update-fan-mode.js';
10
16
  import { useUpdateThermostat } from '../../../../lib/seam/thermostats/use-update-thermostat.js';
17
+ import { getSupportedThermostatModes } from '../../../../lib/temperature-bounds.js';
18
+ import { AccordionRow } from '../../../../lib/ui/layout/AccordionRow.js';
11
19
  import { ContentHeader } from '../../../../lib/ui/layout/ContentHeader.js';
12
20
  import { DetailRow } from '../../../../lib/ui/layout/DetailRow.js';
13
21
  import { DetailSection } from '../../../../lib/ui/layout/DetailSection.js';
14
22
  import { DetailSectionGroup } from '../../../../lib/ui/layout/DetailSectionGroup.js';
15
23
  import { Snackbar } from '../../../../lib/ui/Snackbar/Snackbar.js';
16
24
  import { Switch } from '../../../../lib/ui/Switch/Switch.js';
25
+ import { ClimateModeMenu } from '../../../../lib/ui/thermostat/ClimateModeMenu.js';
17
26
  import { ClimateSettingStatus } from '../../../../lib/ui/thermostat/ClimateSettingStatus.js';
18
27
  import { FanModeMenu } from '../../../../lib/ui/thermostat/FanModeMenu.js';
28
+ import { TemperatureControlGroup } from '../../../../lib/ui/thermostat/TemperatureControlGroup.js';
19
29
  import { ThermostatCard } from '../../../../lib/ui/thermostat/ThermostatCard.js';
20
30
  export function ThermostatDeviceDetails({ device, onBack, className, errorFilter = () => true, warningFilter = () => true, disableLockUnlock, disableCreateAccessCode, disableEditAccessCode, disableDeleteAccessCode, disableResourceIds = false, }) {
21
31
  const [climateSettingsOpen, setClimateSettingsOpen] = useState(false);
@@ -38,7 +48,7 @@ export function ThermostatDeviceDetails({ device, onBack, className, errorFilter
38
48
  ? t.viewingClimateSchedules
39
49
  : `${climateSettingSchedules.length} ${climateSettingSchedulesLabel}`, onClick: () => {
40
50
  setClimateSettingsOpen(true);
41
- }, children: _jsx("div", { className: 'seam-detail-row-rotated-icon', children: _jsx(ChevronWideIcon, {}) }) }) }), _jsxs(DetailSection, { label: t.currentSettings, tooltipContent: t.currentSettingsTooltip, children: [_jsx(DetailRow, { label: t.climate, children: _jsx(ClimateSettingStatus, { climateSetting: device.properties.current_climate_setting, temperatureUnit: 'fahrenheit' }) }), _jsx(FanModeRow, { device: device })] }), _jsxs(DetailSection, { label: t.defaultSettings, tooltipContent: t.defaultSettingsTooltip, children: [_jsx(DetailRow, { label: t.defaultClimate, children: device.properties.default_climate_setting != null ? (_jsx(ClimateSettingStatus, { climateSetting: device.properties.default_climate_setting, temperatureUnit: 'fahrenheit' })) : (_jsx("p", { children: t.none })) }), _jsx(ManualOverrideRow, { device: device })] }), _jsxs(DetailSection, { label: t.deviceDetails, children: [_jsx(DetailRow, { label: t.manufacturer, children: _jsxs("div", { className: 'seam-detail-row-hstack', children: [device.properties.model.manufacturer_display_name, device.properties.manufacturer === 'ecobee' && _jsx(BeeIcon, {})] }) }), _jsx(DetailRow, { label: t.linkedAccount, sublabel: connectedAccount?.user_identifier?.email ??
51
+ }, children: _jsx("div", { className: 'seam-detail-row-rotated-icon', children: _jsx(ChevronWideIcon, {}) }) }) }), _jsxs(DetailSection, { label: t.currentSettings, tooltipContent: t.currentSettingsTooltip, children: [_jsx(ClimateSettingRow, { device: device }), _jsx(FanModeRow, { device: device })] }), _jsxs(DetailSection, { label: t.defaultSettings, tooltipContent: t.defaultSettingsTooltip, children: [_jsx(DetailRow, { label: t.defaultClimate, children: device.properties.default_climate_setting != null ? (_jsx(ClimateSettingStatus, { climateSetting: device.properties.default_climate_setting, temperatureUnit: 'fahrenheit' })) : (_jsx("p", { children: t.none })) }), _jsx(ManualOverrideRow, { device: device })] }), _jsxs(DetailSection, { label: t.deviceDetails, children: [_jsx(DetailRow, { label: t.manufacturer, children: _jsxs("div", { className: 'seam-detail-row-hstack', children: [device.properties.model.manufacturer_display_name, device.properties.manufacturer === 'ecobee' && _jsx(BeeIcon, {})] }) }), _jsx(DetailRow, { label: t.linkedAccount, sublabel: connectedAccount?.user_identifier?.email ??
42
52
  device.connected_account_id }), !disableResourceIds && (_jsx(DetailRow, { label: t.deviceId, sublabel: device.device_id }))] })] }) })] })] }));
43
53
  }
44
54
  function ManualOverrideRow({ device, }) {
@@ -62,6 +72,88 @@ function FanModeRow({ device }) {
62
72
  });
63
73
  } }) }) }), _jsx(Snackbar, { message: t.fanModeSuccess, variant: 'success', visible: isSuccess, automaticVisibility: true, autoDismiss: true }), _jsx(Snackbar, { message: t.fanModeError, variant: 'error', visible: isError, automaticVisibility: true })] }));
64
74
  }
75
+ function ClimateSettingRow({ device, }) {
76
+ const deviceHeatValue = device.properties.current_climate_setting.heating_set_point_fahrenheit;
77
+ const deviceCoolValue = device.properties.current_climate_setting.cooling_set_point_fahrenheit;
78
+ const supportedModes = getSupportedThermostatModes(device);
79
+ const [showSuccess, setShowSuccess] = useState(false);
80
+ const [mode, setMode] = useState((supportedModes.includes('heat_cool') ? 'heat_cool' : supportedModes[0]) ??
81
+ 'off');
82
+ const [heatValue, setHeatValue] = useState(device.properties.current_climate_setting.heating_set_point_fahrenheit ?? 0);
83
+ const [coolValue, setCoolValue] = useState(device.properties.current_climate_setting.cooling_set_point_fahrenheit ?? 0);
84
+ const { mutate: heatCoolThermostat, isSuccess: isHeatCoolSuccess, isError: isHeatCoolError, } = useHeatCoolThermostat();
85
+ const { mutate: heatThermostat, isSuccess: isHeatSuccess, isError: isHeatError, } = useHeatThermostat();
86
+ const { mutate: coolThermostat, isSuccess: isCoolSuccess, isError: isCoolError, } = useCoolThermostat();
87
+ const { mutate: setThermostatOff, isSuccess: isSetOffSuccess, isError: isSetOffError, } = useSetThermostatOff();
88
+ useEffect(() => {
89
+ const handler = debounce(() => {
90
+ switch (mode) {
91
+ case 'heat_cool':
92
+ heatCoolThermostat({
93
+ device_id: device.device_id,
94
+ heating_set_point_fahrenheit: heatValue,
95
+ cooling_set_point_fahrenheit: coolValue,
96
+ });
97
+ break;
98
+ case 'heat':
99
+ heatThermostat({
100
+ device_id: device.device_id,
101
+ heating_set_point_fahrenheit: heatValue,
102
+ });
103
+ break;
104
+ case 'cool':
105
+ coolThermostat({
106
+ device_id: device.device_id,
107
+ cooling_set_point_fahrenheit: coolValue,
108
+ });
109
+ break;
110
+ case 'off':
111
+ setThermostatOff({
112
+ device_id: device.device_id,
113
+ });
114
+ break;
115
+ }
116
+ }, 2000);
117
+ if (heatValue !== deviceHeatValue ||
118
+ coolValue !== deviceCoolValue ||
119
+ mode === 'off') {
120
+ handler();
121
+ }
122
+ return () => {
123
+ handler.cancel();
124
+ };
125
+ }, [
126
+ heatValue,
127
+ coolValue,
128
+ mode,
129
+ deviceHeatValue,
130
+ deviceCoolValue,
131
+ device,
132
+ heatThermostat,
133
+ coolThermostat,
134
+ heatCoolThermostat,
135
+ setThermostatOff,
136
+ ]);
137
+ useEffect(() => {
138
+ if (isHeatCoolSuccess ||
139
+ isHeatSuccess ||
140
+ isCoolSuccess ||
141
+ isSetOffSuccess) {
142
+ setShowSuccess(true);
143
+ const timeout = globalThis.setTimeout(() => {
144
+ setShowSuccess(false);
145
+ }, 3000);
146
+ return () => {
147
+ globalThis.clearTimeout(timeout);
148
+ };
149
+ }
150
+ return () => { };
151
+ }, [isHeatCoolSuccess, isHeatSuccess, isCoolSuccess, isSetOffSuccess]);
152
+ return (_jsxs(_Fragment, { children: [_jsx(AccordionRow, { label: t.climate, leftContent: _jsxs("div", { className: classNames('seam-thermostat-mutation-status', {
153
+ 'is-visible': showSuccess,
154
+ }), children: [_jsx("div", { className: 'seam-thermostat-mutation-status-icon', children: _jsx(CheckBlackIcon, {}) }), _jsx("div", { className: 'seam-thermostat-mutation-status-label', children: t.saved })] }), rightCollapsedContent: _jsx(ClimateSettingStatus, { climateSetting: device.properties.current_climate_setting, temperatureUnit: 'fahrenheit' }), children: _jsxs("div", { className: 'seam-detail-row-end-alignment', children: [mode !== 'off' && (_jsx(TemperatureControlGroup, { mode: mode, heatValue: heatValue, coolValue: coolValue, onHeatValueChange: setHeatValue, onCoolValueChange: setCoolValue, delta: Number('min_heating_cooling_delta_fahrenheit' in device.properties &&
155
+ device.properties.min_heating_cooling_delta_fahrenheit) ?? 0 })), _jsx(ClimateModeMenu, { mode: mode, onChange: setMode, supportedModes: supportedModes })] }) }), _jsx(Snackbar, { message: t.climateSettingError, variant: 'error', visible: isHeatCoolError || isHeatError || isCoolError || isSetOffError, automaticVisibility: true })] }));
156
+ }
65
157
  const t = {
66
158
  thermostat: 'Thermostat',
67
159
  climateSchedule: 'scheduled climate',
@@ -86,5 +178,7 @@ const t = {
86
178
  fanModeError: 'Error updating fan mode. Please try again.',
87
179
  manualOverrideSuccess: 'Successfully updated manual override!',
88
180
  manualOverrideError: 'Error updating manual override. Please try again.',
181
+ climateSettingError: 'Error updating climate setting. Please try again.',
182
+ saved: 'Saved',
89
183
  };
90
184
  //# sourceMappingURL=ThermostatDeviceDetails.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ThermostatDeviceDetails.js","sourceRoot":"","sources":["../../../../src/lib/seam/components/DeviceDetails/ThermostatDeviceDetails.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ThermostatDeviceDetails.js","sourceRoot":"","sources":["../../../../src/lib/seam/components/DeviceDetails/ThermostatDeviceDetails.tsx"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import type { HvacModeSetting } from 'seamapi';
1
+ import type { HvacModeSetting, ThermostatDevice } from 'seamapi';
2
2
  export interface ControlBounds {
3
3
  mode: Exclude<HvacModeSetting, 'off'>;
4
4
  minHeat: number;
@@ -18,4 +18,5 @@ interface TemperatureBounds {
18
18
  export declare const getHeatBounds: ({ mode, minHeat, maxHeat, maxCool, delta, }: Omit<ControlBounds, 'minCool'>) => MinMax;
19
19
  export declare const getCoolBounds: ({ mode, minHeat, minCool, maxCool, delta, }: Omit<ControlBounds, 'maxHeat'>) => MinMax;
20
20
  export declare const getTemperatureBounds: (controlBounds: ControlBounds) => TemperatureBounds;
21
+ export declare const getSupportedThermostatModes: (device: ThermostatDevice) => HvacModeSetting[];
21
22
  export {};
@@ -10,4 +10,20 @@ export const getTemperatureBounds = (controlBounds) => ({
10
10
  heat: getHeatBounds(controlBounds),
11
11
  cool: getCoolBounds(controlBounds),
12
12
  });
13
+ export const getSupportedThermostatModes = (device) => {
14
+ const allModes = ['heat', 'cool', 'heat_cool', 'off'];
15
+ return allModes.filter((mode) => {
16
+ switch (mode) {
17
+ case 'cool':
18
+ return device.properties.is_cooling_available;
19
+ case 'heat':
20
+ return device.properties.is_heating_available;
21
+ case 'heat_cool':
22
+ return (device.properties.is_heating_available &&
23
+ device.properties.is_cooling_available);
24
+ default:
25
+ return true;
26
+ }
27
+ });
28
+ };
13
29
  //# sourceMappingURL=temperature-bounds.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"temperature-bounds.js","sourceRoot":"","sources":["../src/lib/temperature-bounds.ts"],"names":[],"mappings":"AAqBA,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,EAC5B,IAAI,EACJ,OAAO,EACP,OAAO,EACP,OAAO,EACP,KAAK,GAC0B,EAAU,EAAE;IAC3C,MAAM,aAAa,GACjB,IAAI,KAAK,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,GAAG,KAAK,EAAE,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAA;IAE7E,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,aAAa,EAAE,CAAA;AAC7C,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,EAC5B,IAAI,EACJ,OAAO,EACP,OAAO,EACP,OAAO,EACP,KAAK,GAC0B,EAAU,EAAE;IAC3C,MAAM,aAAa,GACjB,IAAI,KAAK,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,GAAG,KAAK,EAAE,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAA;IAE7E,OAAO,EAAE,GAAG,EAAE,aAAa,EAAE,GAAG,EAAE,OAAO,EAAE,CAAA;AAC7C,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAClC,aAA4B,EACT,EAAE,CAAC,CAAC;IACvB,IAAI,EAAE,aAAa,CAAC,aAAa,CAAC;IAClC,IAAI,EAAE,aAAa,CAAC,aAAa,CAAC;CACnC,CAAC,CAAA"}
1
+ {"version":3,"file":"temperature-bounds.js","sourceRoot":"","sources":["../src/lib/temperature-bounds.ts"],"names":[],"mappings":"AAqBA,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,EAC5B,IAAI,EACJ,OAAO,EACP,OAAO,EACP,OAAO,EACP,KAAK,GAC0B,EAAU,EAAE;IAC3C,MAAM,aAAa,GACjB,IAAI,KAAK,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,GAAG,KAAK,EAAE,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAA;IAE7E,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,aAAa,EAAE,CAAA;AAC7C,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,EAC5B,IAAI,EACJ,OAAO,EACP,OAAO,EACP,OAAO,EACP,KAAK,GAC0B,EAAU,EAAE;IAC3C,MAAM,aAAa,GACjB,IAAI,KAAK,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,GAAG,KAAK,EAAE,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAA;IAE7E,OAAO,EAAE,GAAG,EAAE,aAAa,EAAE,GAAG,EAAE,OAAO,EAAE,CAAA;AAC7C,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAClC,aAA4B,EACT,EAAE,CAAC,CAAC;IACvB,IAAI,EAAE,aAAa,CAAC,aAAa,CAAC;IAClC,IAAI,EAAE,aAAa,CAAC,aAAa,CAAC;CACnC,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,2BAA2B,GAAG,CACzC,MAAwB,EACL,EAAE;IACrB,MAAM,QAAQ,GAAsB,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,KAAK,CAAC,CAAA;IAExE,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE;QAC9B,QAAQ,IAAI,EAAE,CAAC;YACb,KAAK,MAAM;gBACT,OAAO,MAAM,CAAC,UAAU,CAAC,oBAAoB,CAAA;YAC/C,KAAK,MAAM;gBACT,OAAO,MAAM,CAAC,UAAU,CAAC,oBAAoB,CAAA;YAC/C,KAAK,WAAW;gBACd,OAAO,CACL,MAAM,CAAC,UAAU,CAAC,oBAAoB;oBACtC,MAAM,CAAC,UAAU,CAAC,oBAAoB,CACvC,CAAA;YACH;gBACE,OAAO,IAAI,CAAA;QACf,CAAC;IACH,CAAC,CAAC,CAAA;AACJ,CAAC,CAAA"}
@@ -1,7 +1,8 @@
1
1
  import type { PropsWithChildren } from 'react';
2
2
  interface AccordionRowProps extends PropsWithChildren {
3
3
  label: string;
4
+ leftContent?: JSX.Element;
4
5
  rightCollapsedContent?: JSX.Element;
5
6
  }
6
- export declare function AccordionRow({ label, rightCollapsedContent, children, }: AccordionRowProps): JSX.Element;
7
+ export declare function AccordionRow({ label, leftContent, rightCollapsedContent, children, }: AccordionRowProps): JSX.Element;
7
8
  export {};
@@ -1,8 +1,8 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { ChevronWideIcon } from '../../../lib/icons/ChevronWide.js';
3
3
  import { useToggle } from '../../../lib/ui/use-toggle.js';
4
- export function AccordionRow({ label, rightCollapsedContent, children, }) {
4
+ export function AccordionRow({ label, leftContent, rightCollapsedContent, children, }) {
5
5
  const [isExpanded, toggle] = useToggle();
6
- return (_jsxs("div", { className: 'seam-accordion-row', "aria-expanded": isExpanded, children: [_jsxs("button", { className: 'seam-accordion-row-trigger', onClick: toggle, children: [_jsx("p", { className: 'seam-row-label', children: label }), _jsxs("div", { className: 'seam-row-inner-wrap', children: [_jsx("div", { className: 'seam-row-trigger-right-content', children: rightCollapsedContent }), _jsx("div", { className: 'seam-accordion-icon-wrap', children: _jsx(ChevronWideIcon, {}) })] })] }), _jsx("div", { className: 'seam-accordion-row-content', children: _jsx("div", { className: 'seam-accordion-row-inner-content', children: children }) })] }));
6
+ return (_jsxs("div", { className: 'seam-accordion-row', "aria-expanded": isExpanded, children: [_jsxs("button", { className: 'seam-accordion-row-trigger', onClick: toggle, children: [_jsxs("div", { className: 'seam-row-inner-wrap', children: [_jsx("p", { className: 'seam-row-label', children: label }), _jsx("div", { className: 'seam-row-trigger-left-content', children: leftContent })] }), _jsxs("div", { className: 'seam-row-inner-wrap', children: [_jsx("div", { className: 'seam-row-trigger-right-content', children: rightCollapsedContent }), _jsx("div", { className: 'seam-accordion-icon-wrap', children: _jsx(ChevronWideIcon, {}) })] })] }), _jsx("div", { className: 'seam-accordion-row-content', children: _jsx("div", { className: 'seam-accordion-row-inner-content', children: children }) })] }));
7
7
  }
8
8
  //# sourceMappingURL=AccordionRow.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AccordionRow.js","sourceRoot":"","sources":["../../../src/lib/ui/layout/AccordionRow.tsx"],"names":[],"mappings":";AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;AAC1D,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAOhD,MAAM,UAAU,YAAY,CAAC,EAC3B,KAAK,EACL,qBAAqB,EACrB,QAAQ,GACU;IAClB,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,GAAG,SAAS,EAAE,CAAA;IAExC,OAAO,CACL,eAAK,SAAS,EAAC,oBAAoB,mBAAgB,UAAU,aAC3D,kBAAQ,SAAS,EAAC,4BAA4B,EAAC,OAAO,EAAE,MAAM,aAC5D,YAAG,SAAS,EAAC,gBAAgB,YAAE,KAAK,GAAK,EACzC,eAAK,SAAS,EAAC,qBAAqB,aAClC,cAAK,SAAS,EAAC,gCAAgC,YAC5C,qBAAqB,GAClB,EACN,cAAK,SAAS,EAAC,0BAA0B,YACvC,KAAC,eAAe,KAAG,GACf,IACF,IACC,EACT,cAAK,SAAS,EAAC,4BAA4B,YACzC,cAAK,SAAS,EAAC,kCAAkC,YAAE,QAAQ,GAAO,GAC9D,IACF,CACP,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"AccordionRow.js","sourceRoot":"","sources":["../../../src/lib/ui/layout/AccordionRow.tsx"],"names":[],"mappings":";AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;AAC1D,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAQhD,MAAM,UAAU,YAAY,CAAC,EAC3B,KAAK,EACL,WAAW,EACX,qBAAqB,EACrB,QAAQ,GACU;IAClB,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,GAAG,SAAS,EAAE,CAAA;IAExC,OAAO,CACL,eAAK,SAAS,EAAC,oBAAoB,mBAAgB,UAAU,aAC3D,kBAAQ,SAAS,EAAC,4BAA4B,EAAC,OAAO,EAAE,MAAM,aAC5D,eAAK,SAAS,EAAC,qBAAqB,aAClC,YAAG,SAAS,EAAC,gBAAgB,YAAE,KAAK,GAAK,EACzC,cAAK,SAAS,EAAC,+BAA+B,YAAE,WAAW,GAAO,IAC9D,EACN,eAAK,SAAS,EAAC,qBAAqB,aAClC,cAAK,SAAS,EAAC,gCAAgC,YAC5C,qBAAqB,GAClB,EACN,cAAK,SAAS,EAAC,0BAA0B,YACvC,KAAC,eAAe,KAAG,GACf,IACF,IACC,EACT,cAAK,SAAS,EAAC,4BAA4B,YACzC,cAAK,SAAS,EAAC,kCAAkC,YAAE,QAAQ,GAAO,GAC9D,IACF,CACP,CAAA;AACH,CAAC"}
@@ -3,6 +3,7 @@ import type { HvacModeSetting } from 'seamapi';
3
3
  interface ClimateModeMenuProps {
4
4
  mode: HvacModeSetting;
5
5
  onChange: (mode: HvacModeSetting) => void;
6
+ supportedModes?: HvacModeSetting[];
6
7
  }
7
- export declare function ClimateModeMenu({ mode, onChange, }: ClimateModeMenuProps): JSX.Element;
8
+ export declare function ClimateModeMenu({ mode, onChange, supportedModes, }: ClimateModeMenuProps): JSX.Element;
8
9
  export {};
@@ -6,11 +6,10 @@ import { ThermostatHeatIcon } from '../../../lib/icons/ThermostatHeat.js';
6
6
  import { ThermostatHeatCoolIcon } from '../../../lib/icons/ThermostatHeatCool.js';
7
7
  import { Menu } from '../../../lib/ui/Menu/Menu.js';
8
8
  import { ThermoModeMenuOption } from '../../../lib/ui/thermostat/ThermoModeMenuOption.js';
9
- const modes = ['heat', 'cool', 'heat_cool', 'off'];
10
- export function ClimateModeMenu({ mode, onChange, }) {
9
+ export function ClimateModeMenu({ mode, onChange, supportedModes = ['heat', 'cool', 'heat_cool', 'off'], }) {
11
10
  return (_jsx(Menu, { renderButton: ({ onOpen }) => (_jsxs("button", { onClick: onOpen, className: 'seam-climate-mode-menu-button', children: [_jsx("div", { className: 'seam-climate-mode-menu-button-icon', children: _jsx(ModeIcon, { mode: mode }) }), _jsx(ChevronDownIcon, {})] })), verticalOffset: -180, horizontalOffset: -32, backgroundProps: {
12
11
  className: 'seam-thermo-mode-menu',
13
- }, children: modes.map((m) => (_jsx(ThermoModeMenuOption, { label: t[m], icon: _jsx(ModeIcon, { mode: m }), isSelected: mode === m, onClick: () => {
12
+ }, children: supportedModes.map((m) => (_jsx(ThermoModeMenuOption, { label: t[m], icon: _jsx(ModeIcon, { mode: m }), isSelected: mode === m, onClick: () => {
14
13
  onChange(m);
15
14
  } }, m))) }));
16
15
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ClimateModeMenu.js","sourceRoot":"","sources":["../../../src/lib/ui/thermostat/ClimateModeMenu.tsx"],"names":[],"mappings":";AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;AAC1D,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AAC1C,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAA;AAChE,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAA;AAChE,OAAO,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAA;AACxE,OAAO,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAA;AAC1C,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAA;AAEhF,MAAM,KAAK,GAAsB,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,KAAK,CAAC,CAAA;AAOrE,MAAM,UAAU,eAAe,CAAC,EAC9B,IAAI,EACJ,QAAQ,GACa;IACrB,OAAO,CACL,KAAC,IAAI,IACH,YAAY,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAC5B,kBAAQ,OAAO,EAAE,MAAM,EAAE,SAAS,EAAC,+BAA+B,aAChE,cAAK,SAAS,EAAC,oCAAoC,YACjD,KAAC,QAAQ,IAAC,IAAI,EAAE,IAAI,GAAI,GACpB,EACN,KAAC,eAAe,KAAG,IACZ,CACV,EACD,cAAc,EAAE,CAAC,GAAG,EACpB,gBAAgB,EAAE,CAAC,EAAE,EACrB,eAAe,EAAE;YACf,SAAS,EAAE,uBAAuB;SACnC,YAEA,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAChB,KAAC,oBAAoB,IAEnB,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,EACX,IAAI,EAAE,KAAC,QAAQ,IAAC,IAAI,EAAE,CAAC,GAAI,EAC3B,UAAU,EAAE,IAAI,KAAK,CAAC,EACtB,OAAO,EAAE,GAAG,EAAE;gBACZ,QAAQ,CAAC,CAAC,CAAC,CAAA;YACb,CAAC,IANI,CAAC,CAON,CACH,CAAC,GACG,CACR,CAAA;AACH,CAAC;AAED,SAAS,QAAQ,CAAC,KAAgC;IAChD,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;QACnB,KAAK,MAAM;YACT,OAAO,KAAC,kBAAkB,KAAG,CAAA;QAC/B,KAAK,MAAM;YACT,OAAO,KAAC,kBAAkB,KAAG,CAAA;QAC/B,KAAK,WAAW;YACd,OAAO,KAAC,sBAAsB,KAAG,CAAA;QACnC,KAAK,KAAK;YACR,OAAO,KAAC,OAAO,KAAG,CAAA;IACtB,CAAC;AACH,CAAC;AAED,MAAM,CAAC,GAAG;IACR,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,MAAM;IACZ,SAAS,EAAE,aAAa;IACxB,GAAG,EAAE,KAAK;CACX,CAAA"}
1
+ {"version":3,"file":"ClimateModeMenu.js","sourceRoot":"","sources":["../../../src/lib/ui/thermostat/ClimateModeMenu.tsx"],"names":[],"mappings":";AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;AAC1D,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AAC1C,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAA;AAChE,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAA;AAChE,OAAO,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAA;AACxE,OAAO,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAA;AAC1C,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAA;AAQhF,MAAM,UAAU,eAAe,CAAC,EAC9B,IAAI,EACJ,QAAQ,EACR,cAAc,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,KAAK,CAAC,GAChC;IACrB,OAAO,CACL,KAAC,IAAI,IACH,YAAY,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAC5B,kBAAQ,OAAO,EAAE,MAAM,EAAE,SAAS,EAAC,+BAA+B,aAChE,cAAK,SAAS,EAAC,oCAAoC,YACjD,KAAC,QAAQ,IAAC,IAAI,EAAE,IAAI,GAAI,GACpB,EACN,KAAC,eAAe,KAAG,IACZ,CACV,EACD,cAAc,EAAE,CAAC,GAAG,EACpB,gBAAgB,EAAE,CAAC,EAAE,EACrB,eAAe,EAAE;YACf,SAAS,EAAE,uBAAuB;SACnC,YAEA,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CACzB,KAAC,oBAAoB,IAEnB,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,EACX,IAAI,EAAE,KAAC,QAAQ,IAAC,IAAI,EAAE,CAAC,GAAI,EAC3B,UAAU,EAAE,IAAI,KAAK,CAAC,EACtB,OAAO,EAAE,GAAG,EAAE;gBACZ,QAAQ,CAAC,CAAC,CAAC,CAAA;YACb,CAAC,IANI,CAAC,CAON,CACH,CAAC,GACG,CACR,CAAA;AACH,CAAC;AAED,SAAS,QAAQ,CAAC,KAAgC;IAChD,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;QACnB,KAAK,MAAM;YACT,OAAO,KAAC,kBAAkB,KAAG,CAAA;QAC/B,KAAK,MAAM;YACT,OAAO,KAAC,kBAAkB,KAAG,CAAA;QAC/B,KAAK,WAAW;YACd,OAAO,KAAC,sBAAsB,KAAG,CAAA;QACnC,KAAK,KAAK;YACR,OAAO,KAAC,OAAO,KAAG,CAAA;IACtB,CAAC;AACH,CAAC;AAED,MAAM,CAAC,GAAG;IACR,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,MAAM;IACZ,SAAS,EAAE,aAAa;IACxB,GAAG,EAAE,KAAK;CACX,CAAA"}
package/lib/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- declare const seamapiReactVersion = "2.8.7";
1
+ declare const seamapiReactVersion = "2.9.0";
2
2
  export default seamapiReactVersion;
package/lib/version.js CHANGED
@@ -1,3 +1,3 @@
1
- const seamapiReactVersion = '2.8.7';
1
+ const seamapiReactVersion = '2.9.0';
2
2
  export default seamapiReactVersion;
3
3
  //# sourceMappingURL=version.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seamapi/react",
3
- "version": "2.8.7",
3
+ "version": "2.9.0",
4
4
  "description": "Seam Components.",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -132,7 +132,7 @@
132
132
  "luxon": "^3.3.0",
133
133
  "queue": "^7.0.0",
134
134
  "react-hook-form": "^7.46.1",
135
- "seamapi": "^8.19.0",
135
+ "seamapi": "^8.21.0",
136
136
  "uuid": "^9.0.0"
137
137
  },
138
138
  "devDependencies": {
@@ -141,7 +141,7 @@
141
141
  "@mui/material": "^5.12.2",
142
142
  "@rxfork/r2wc-react-to-web-component": "^2.4.0",
143
143
  "@seamapi/fake-devicedb": "^1.6.0",
144
- "@seamapi/fake-seam-connect": "^1.44.3",
144
+ "@seamapi/fake-seam-connect": "^1.60.2",
145
145
  "@seamapi/http": "^0.19.0",
146
146
  "@seamapi/types": "^1.122.0",
147
147
  "@storybook/addon-designs": "^7.0.1",
@@ -0,0 +1,33 @@
1
+ type Procedure = (...args: any[]) => void
2
+
3
+ export function debounce<F extends Procedure>(
4
+ func: F,
5
+ waitMilliseconds: number
6
+ ): {
7
+ (this: ThisParameterType<F>, ...args: Parameters<F>): void
8
+ cancel: () => void
9
+ } {
10
+ let timeoutId: ReturnType<typeof globalThis.setTimeout> | null = null
11
+
12
+ const debouncedFunction = function (
13
+ this: ThisParameterType<F>,
14
+ ...args: Parameters<F>
15
+ ): void {
16
+ if (timeoutId !== null) {
17
+ globalThis.clearTimeout(timeoutId)
18
+ }
19
+ timeoutId = globalThis.setTimeout(() => {
20
+ timeoutId = null
21
+ func.apply(this, args)
22
+ }, waitMilliseconds)
23
+ }
24
+
25
+ debouncedFunction.cancel = (): void => {
26
+ if (timeoutId !== null) {
27
+ globalThis.clearTimeout(timeoutId)
28
+ timeoutId = null
29
+ }
30
+ }
31
+
32
+ return debouncedFunction
33
+ }
@@ -1,23 +1,33 @@
1
1
  import classNames from 'classnames'
2
- import { useState } from 'react'
3
- import type { ThermostatDevice } from 'seamapi'
2
+ import { useEffect, useState } from 'react'
3
+ import type { HvacModeSetting, ThermostatDevice } from 'seamapi'
4
4
 
5
+ import { debounce } from 'lib/debounce.js'
5
6
  import { BeeIcon } from 'lib/icons/Bee.js'
7
+ import { CheckBlackIcon } from 'lib/icons/CheckBlack.js'
6
8
  import { ChevronWideIcon } from 'lib/icons/ChevronWide.js'
7
9
  import { NestedClimateSettingScheduleTable } from 'lib/seam/components/ClimateSettingScheduleTable/ClimateSettingScheduleTable.js'
8
10
  import type { CommonProps } from 'lib/seam/components/common-props.js'
9
11
  import { useConnectedAccount } from 'lib/seam/connected-accounts/use-connected-account.js'
10
12
  import { useClimateSettingSchedules } from 'lib/seam/thermostats/climate-setting-schedules/use-climate-setting-schedules.js'
13
+ import { useCoolThermostat } from 'lib/seam/thermostats/use-cool-thermostat.js'
14
+ import { useHeatCoolThermostat } from 'lib/seam/thermostats/use-heat-cool-thermostat.js'
15
+ import { useHeatThermostat } from 'lib/seam/thermostats/use-heat-thermostat.js'
16
+ import { useSetThermostatOff } from 'lib/seam/thermostats/use-set-thermostat-off.js'
11
17
  import { useUpdateFanMode } from 'lib/seam/thermostats/use-update-fan-mode.js'
12
18
  import { useUpdateThermostat } from 'lib/seam/thermostats/use-update-thermostat.js'
19
+ import { getSupportedThermostatModes } from 'lib/temperature-bounds.js'
20
+ import { AccordionRow } from 'lib/ui/layout/AccordionRow.js'
13
21
  import { ContentHeader } from 'lib/ui/layout/ContentHeader.js'
14
22
  import { DetailRow } from 'lib/ui/layout/DetailRow.js'
15
23
  import { DetailSection } from 'lib/ui/layout/DetailSection.js'
16
24
  import { DetailSectionGroup } from 'lib/ui/layout/DetailSectionGroup.js'
17
25
  import { Snackbar } from 'lib/ui/Snackbar/Snackbar.js'
18
26
  import { Switch } from 'lib/ui/Switch/Switch.js'
27
+ import { ClimateModeMenu } from 'lib/ui/thermostat/ClimateModeMenu.js'
19
28
  import { ClimateSettingStatus } from 'lib/ui/thermostat/ClimateSettingStatus.js'
20
29
  import { FanModeMenu } from 'lib/ui/thermostat/FanModeMenu.js'
30
+ import { TemperatureControlGroup } from 'lib/ui/thermostat/TemperatureControlGroup.js'
21
31
  import { ThermostatCard } from 'lib/ui/thermostat/ThermostatCard.js'
22
32
 
23
33
  interface ThermostatDeviceDetailsProps extends CommonProps {
@@ -105,12 +115,7 @@ export function ThermostatDeviceDetails({
105
115
  label={t.currentSettings}
106
116
  tooltipContent={t.currentSettingsTooltip}
107
117
  >
108
- <DetailRow label={t.climate}>
109
- <ClimateSettingStatus
110
- climateSetting={device.properties.current_climate_setting}
111
- temperatureUnit='fahrenheit'
112
- />
113
- </DetailRow>
118
+ <ClimateSettingRow device={device} />
114
119
  <FanModeRow device={device} />
115
120
  </DetailSection>
116
121
 
@@ -239,6 +244,191 @@ function FanModeRow({ device }: { device: ThermostatDevice }): JSX.Element {
239
244
  )
240
245
  }
241
246
 
247
+ function ClimateSettingRow({
248
+ device,
249
+ }: {
250
+ device: ThermostatDevice
251
+ }): JSX.Element {
252
+ const deviceHeatValue =
253
+ device.properties.current_climate_setting.heating_set_point_fahrenheit
254
+ const deviceCoolValue =
255
+ device.properties.current_climate_setting.cooling_set_point_fahrenheit
256
+
257
+ const supportedModes = getSupportedThermostatModes(device)
258
+
259
+ const [showSuccess, setShowSuccess] = useState(false)
260
+ const [mode, setMode] = useState<HvacModeSetting>(
261
+ (supportedModes.includes('heat_cool') ? 'heat_cool' : supportedModes[0]) ??
262
+ 'off'
263
+ )
264
+
265
+ const [heatValue, setHeatValue] = useState(
266
+ device.properties.current_climate_setting.heating_set_point_fahrenheit ?? 0
267
+ )
268
+
269
+ const [coolValue, setCoolValue] = useState(
270
+ device.properties.current_climate_setting.cooling_set_point_fahrenheit ?? 0
271
+ )
272
+
273
+ const {
274
+ mutate: heatCoolThermostat,
275
+ isSuccess: isHeatCoolSuccess,
276
+ isError: isHeatCoolError,
277
+ } = useHeatCoolThermostat()
278
+
279
+ const {
280
+ mutate: heatThermostat,
281
+ isSuccess: isHeatSuccess,
282
+ isError: isHeatError,
283
+ } = useHeatThermostat()
284
+
285
+ const {
286
+ mutate: coolThermostat,
287
+ isSuccess: isCoolSuccess,
288
+ isError: isCoolError,
289
+ } = useCoolThermostat()
290
+
291
+ const {
292
+ mutate: setThermostatOff,
293
+ isSuccess: isSetOffSuccess,
294
+ isError: isSetOffError,
295
+ } = useSetThermostatOff()
296
+
297
+ useEffect(() => {
298
+ const handler = debounce(() => {
299
+ switch (mode) {
300
+ case 'heat_cool':
301
+ heatCoolThermostat({
302
+ device_id: device.device_id,
303
+ heating_set_point_fahrenheit: heatValue,
304
+ cooling_set_point_fahrenheit: coolValue,
305
+ })
306
+ break
307
+ case 'heat':
308
+ heatThermostat({
309
+ device_id: device.device_id,
310
+ heating_set_point_fahrenheit: heatValue,
311
+ })
312
+ break
313
+ case 'cool':
314
+ coolThermostat({
315
+ device_id: device.device_id,
316
+ cooling_set_point_fahrenheit: coolValue,
317
+ })
318
+ break
319
+ case 'off':
320
+ setThermostatOff({
321
+ device_id: device.device_id,
322
+ })
323
+ break
324
+ }
325
+ }, 2000)
326
+
327
+ if (
328
+ heatValue !== deviceHeatValue ||
329
+ coolValue !== deviceCoolValue ||
330
+ mode === 'off'
331
+ ) {
332
+ handler()
333
+ }
334
+
335
+ return () => {
336
+ handler.cancel()
337
+ }
338
+ }, [
339
+ heatValue,
340
+ coolValue,
341
+ mode,
342
+ deviceHeatValue,
343
+ deviceCoolValue,
344
+ device,
345
+ heatThermostat,
346
+ coolThermostat,
347
+ heatCoolThermostat,
348
+ setThermostatOff,
349
+ ])
350
+
351
+ useEffect(() => {
352
+ if (
353
+ isHeatCoolSuccess ||
354
+ isHeatSuccess ||
355
+ isCoolSuccess ||
356
+ isSetOffSuccess
357
+ ) {
358
+ setShowSuccess(true)
359
+
360
+ const timeout = globalThis.setTimeout(() => {
361
+ setShowSuccess(false)
362
+ }, 3000)
363
+
364
+ return () => {
365
+ globalThis.clearTimeout(timeout)
366
+ }
367
+ }
368
+
369
+ return () => {}
370
+ }, [isHeatCoolSuccess, isHeatSuccess, isCoolSuccess, isSetOffSuccess])
371
+
372
+ return (
373
+ <>
374
+ <AccordionRow
375
+ label={t.climate}
376
+ leftContent={
377
+ <div
378
+ className={classNames('seam-thermostat-mutation-status', {
379
+ 'is-visible': showSuccess,
380
+ })}
381
+ >
382
+ <div className='seam-thermostat-mutation-status-icon'>
383
+ <CheckBlackIcon />
384
+ </div>
385
+ <div className='seam-thermostat-mutation-status-label'>
386
+ {t.saved}
387
+ </div>
388
+ </div>
389
+ }
390
+ rightCollapsedContent={
391
+ <ClimateSettingStatus
392
+ climateSetting={device.properties.current_climate_setting}
393
+ temperatureUnit='fahrenheit'
394
+ />
395
+ }
396
+ >
397
+ <div className='seam-detail-row-end-alignment'>
398
+ {mode !== 'off' && (
399
+ <TemperatureControlGroup
400
+ mode={mode}
401
+ heatValue={heatValue}
402
+ coolValue={coolValue}
403
+ onHeatValueChange={setHeatValue}
404
+ onCoolValueChange={setCoolValue}
405
+ delta={
406
+ Number(
407
+ 'min_heating_cooling_delta_fahrenheit' in device.properties &&
408
+ device.properties.min_heating_cooling_delta_fahrenheit
409
+ ) ?? 0
410
+ }
411
+ />
412
+ )}
413
+
414
+ <ClimateModeMenu
415
+ mode={mode}
416
+ onChange={setMode}
417
+ supportedModes={supportedModes}
418
+ />
419
+ </div>
420
+ </AccordionRow>
421
+
422
+ <Snackbar
423
+ message={t.climateSettingError}
424
+ variant='error'
425
+ visible={isHeatCoolError || isHeatError || isCoolError || isSetOffError}
426
+ automaticVisibility
427
+ />
428
+ </>
429
+ )
430
+ }
431
+
242
432
  const t = {
243
433
  thermostat: 'Thermostat',
244
434
  climateSchedule: 'scheduled climate',
@@ -266,4 +456,6 @@ const t = {
266
456
  fanModeError: 'Error updating fan mode. Please try again.',
267
457
  manualOverrideSuccess: 'Successfully updated manual override!',
268
458
  manualOverrideError: 'Error updating manual override. Please try again.',
459
+ climateSettingError: 'Error updating climate setting. Please try again.',
460
+ saved: 'Saved',
269
461
  }
@@ -1,4 +1,4 @@
1
- import type { HvacModeSetting } from 'seamapi'
1
+ import type { HvacModeSetting, ThermostatDevice } from 'seamapi'
2
2
 
3
3
  export interface ControlBounds {
4
4
  mode: Exclude<HvacModeSetting, 'off'>
@@ -51,3 +51,25 @@ export const getTemperatureBounds = (
51
51
  heat: getHeatBounds(controlBounds),
52
52
  cool: getCoolBounds(controlBounds),
53
53
  })
54
+
55
+ export const getSupportedThermostatModes = (
56
+ device: ThermostatDevice
57
+ ): HvacModeSetting[] => {
58
+ const allModes: HvacModeSetting[] = ['heat', 'cool', 'heat_cool', 'off']
59
+
60
+ return allModes.filter((mode) => {
61
+ switch (mode) {
62
+ case 'cool':
63
+ return device.properties.is_cooling_available
64
+ case 'heat':
65
+ return device.properties.is_heating_available
66
+ case 'heat_cool':
67
+ return (
68
+ device.properties.is_heating_available &&
69
+ device.properties.is_cooling_available
70
+ )
71
+ default:
72
+ return true
73
+ }
74
+ })
75
+ }