homebridge-tuya-pool-heater 1.0.1

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.
@@ -0,0 +1,223 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HeaterCoolerAccessory = void 0;
4
+ const settings_1 = require("./settings");
5
+ class HeaterCoolerAccessory {
6
+ service;
7
+ platform;
8
+ accessory;
9
+ deviceConfig;
10
+ // Cached state
11
+ active = false;
12
+ currentTemperature = 20;
13
+ heatingThresholdTemperature = 28;
14
+ coolingThresholdTemperature = 20;
15
+ currentHeaterCoolerState = 0; // INACTIVE
16
+ targetHeaterCoolerState = 0; // AUTO
17
+ // Debounce polling after commands
18
+ lastCommandTime = 0;
19
+ commandDebounceMs = 10000; // Ignore polls for 10 seconds after command
20
+ constructor(platform, accessory, deviceConfig) {
21
+ this.platform = platform;
22
+ this.accessory = accessory;
23
+ this.deviceConfig = deviceConfig;
24
+ // Set accessory information
25
+ this.accessory.getService(this.platform.Service.AccessoryInformation)
26
+ .setCharacteristic(this.platform.Characteristic.Manufacturer, 'Tuya')
27
+ .setCharacteristic(this.platform.Characteristic.Model, 'Pool Heat Pump')
28
+ .setCharacteristic(this.platform.Characteristic.SerialNumber, deviceConfig.id);
29
+ // Get or create HeaterCooler service
30
+ this.service = this.accessory.getService(this.platform.Service.HeaterCooler)
31
+ || this.accessory.addService(this.platform.Service.HeaterCooler);
32
+ this.service.setCharacteristic(this.platform.Characteristic.Name, deviceConfig.name);
33
+ // Configure Active
34
+ this.service.getCharacteristic(this.platform.Characteristic.Active)
35
+ .onGet(this.getActive.bind(this))
36
+ .onSet(this.setActive.bind(this));
37
+ // Configure CurrentTemperature
38
+ this.service.getCharacteristic(this.platform.Characteristic.CurrentTemperature)
39
+ .setProps({
40
+ minValue: -10,
41
+ maxValue: 60,
42
+ minStep: 0.1,
43
+ })
44
+ .onGet(this.getCurrentTemperature.bind(this));
45
+ // Configure CurrentHeaterCoolerState (read-only)
46
+ this.service.getCharacteristic(this.platform.Characteristic.CurrentHeaterCoolerState)
47
+ .onGet(this.getCurrentHeaterCoolerState.bind(this));
48
+ // Configure TargetHeaterCoolerState
49
+ this.service.getCharacteristic(this.platform.Characteristic.TargetHeaterCoolerState)
50
+ .onGet(this.getTargetHeaterCoolerState.bind(this))
51
+ .onSet(this.setTargetHeaterCoolerState.bind(this));
52
+ // Configure HeatingThresholdTemperature
53
+ this.service.getCharacteristic(this.platform.Characteristic.HeatingThresholdTemperature)
54
+ .setProps({
55
+ minValue: 5,
56
+ maxValue: 55,
57
+ minStep: 1,
58
+ })
59
+ .onGet(this.getHeatingThresholdTemperature.bind(this))
60
+ .onSet(this.setHeatingThresholdTemperature.bind(this));
61
+ // Configure CoolingThresholdTemperature
62
+ this.service.getCharacteristic(this.platform.Characteristic.CoolingThresholdTemperature)
63
+ .setProps({
64
+ minValue: 5,
65
+ maxValue: 35,
66
+ minStep: 1,
67
+ })
68
+ .onGet(this.getCoolingThresholdTemperature.bind(this))
69
+ .onSet(this.setCoolingThresholdTemperature.bind(this));
70
+ // Register for status updates
71
+ this.platform.registerStatusCallback(this.deviceConfig.id, (status) => {
72
+ this.updateState(status);
73
+ });
74
+ // Initial status fetch
75
+ this.fetchInitialStatus();
76
+ }
77
+ async fetchInitialStatus() {
78
+ try {
79
+ const status = await this.platform.tuyaApi.getDeviceStatus(this.deviceConfig.id);
80
+ this.updateState(status);
81
+ }
82
+ catch (error) {
83
+ this.platform.log.error('Failed to fetch initial status:', error);
84
+ }
85
+ }
86
+ updateState(status) {
87
+ // Ignore polled updates briefly after sending a command to avoid race conditions
88
+ if (Date.now() - this.lastCommandTime < this.commandDebounceMs) {
89
+ this.platform.log.debug('Ignoring polled state update (recent command sent)');
90
+ return;
91
+ }
92
+ for (const dp of status) {
93
+ switch (dp.code) {
94
+ case settings_1.DP_CODES.SWITCH:
95
+ this.active = dp.value;
96
+ this.service.updateCharacteristic(this.platform.Characteristic.Active, this.active
97
+ ? this.platform.Characteristic.Active.ACTIVE
98
+ : this.platform.Characteristic.Active.INACTIVE);
99
+ if (!this.active) {
100
+ this.currentHeaterCoolerState = this.platform.Characteristic.CurrentHeaterCoolerState.INACTIVE;
101
+ this.service.updateCharacteristic(this.platform.Characteristic.CurrentHeaterCoolerState, this.currentHeaterCoolerState);
102
+ }
103
+ break;
104
+ case settings_1.DP_CODES.TEMP_CURRENT:
105
+ this.currentTemperature = (0, settings_1.tuyaTempToCelsius)(dp.value);
106
+ this.service.updateCharacteristic(this.platform.Characteristic.CurrentTemperature, this.currentTemperature);
107
+ break;
108
+ case settings_1.DP_CODES.SET_HEATING_TEMP:
109
+ this.heatingThresholdTemperature = (0, settings_1.tuyaTempToCelsius)(dp.value);
110
+ this.service.updateCharacteristic(this.platform.Characteristic.HeatingThresholdTemperature, this.heatingThresholdTemperature);
111
+ break;
112
+ case settings_1.DP_CODES.SET_COOLING_TEMP:
113
+ this.coolingThresholdTemperature = (0, settings_1.tuyaTempToCelsius)(dp.value);
114
+ this.service.updateCharacteristic(this.platform.Characteristic.CoolingThresholdTemperature, this.coolingThresholdTemperature);
115
+ break;
116
+ case settings_1.DP_CODES.MODE:
117
+ this.updateModeFromTuya(dp.value);
118
+ break;
119
+ }
120
+ }
121
+ }
122
+ updateModeFromTuya(mode) {
123
+ if (!this.active) {
124
+ this.currentHeaterCoolerState = this.platform.Characteristic.CurrentHeaterCoolerState.INACTIVE;
125
+ }
126
+ else if ((0, settings_1.isHeatingMode)(mode)) {
127
+ this.currentHeaterCoolerState = this.platform.Characteristic.CurrentHeaterCoolerState.HEATING;
128
+ this.targetHeaterCoolerState = this.platform.Characteristic.TargetHeaterCoolerState.HEAT;
129
+ }
130
+ else if ((0, settings_1.isCoolingMode)(mode)) {
131
+ this.currentHeaterCoolerState = this.platform.Characteristic.CurrentHeaterCoolerState.COOLING;
132
+ this.targetHeaterCoolerState = this.platform.Characteristic.TargetHeaterCoolerState.COOL;
133
+ }
134
+ else {
135
+ // Auto mode - determine current state based on current vs target temp
136
+ if (this.currentTemperature < this.heatingThresholdTemperature) {
137
+ this.currentHeaterCoolerState = this.platform.Characteristic.CurrentHeaterCoolerState.HEATING;
138
+ }
139
+ else if (this.currentTemperature > this.coolingThresholdTemperature) {
140
+ this.currentHeaterCoolerState = this.platform.Characteristic.CurrentHeaterCoolerState.COOLING;
141
+ }
142
+ else {
143
+ this.currentHeaterCoolerState = this.platform.Characteristic.CurrentHeaterCoolerState.IDLE;
144
+ }
145
+ this.targetHeaterCoolerState = this.platform.Characteristic.TargetHeaterCoolerState.AUTO;
146
+ }
147
+ this.service.updateCharacteristic(this.platform.Characteristic.CurrentHeaterCoolerState, this.currentHeaterCoolerState);
148
+ this.service.updateCharacteristic(this.platform.Characteristic.TargetHeaterCoolerState, this.targetHeaterCoolerState);
149
+ }
150
+ // Handlers
151
+ async getActive() {
152
+ return this.active
153
+ ? this.platform.Characteristic.Active.ACTIVE
154
+ : this.platform.Characteristic.Active.INACTIVE;
155
+ }
156
+ async setActive(value) {
157
+ const active = value === this.platform.Characteristic.Active.ACTIVE;
158
+ this.platform.log.info(`Setting active to ${active}`);
159
+ this.lastCommandTime = Date.now();
160
+ const success = await this.platform.tuyaApi.sendCommand(this.deviceConfig.id, settings_1.DP_CODES.SWITCH, active);
161
+ if (success) {
162
+ this.active = active;
163
+ }
164
+ }
165
+ async getCurrentTemperature() {
166
+ return this.currentTemperature;
167
+ }
168
+ async getCurrentHeaterCoolerState() {
169
+ return this.currentHeaterCoolerState;
170
+ }
171
+ async getTargetHeaterCoolerState() {
172
+ return this.targetHeaterCoolerState;
173
+ }
174
+ async setTargetHeaterCoolerState(value) {
175
+ const state = value;
176
+ this.platform.log.info(`Setting target heater/cooler state to ${state}`);
177
+ this.lastCommandTime = Date.now();
178
+ let mode;
179
+ switch (state) {
180
+ case this.platform.Characteristic.TargetHeaterCoolerState.HEAT:
181
+ mode = settings_1.TUYA_MODES.HEATING_SMART;
182
+ break;
183
+ case this.platform.Characteristic.TargetHeaterCoolerState.COOL:
184
+ mode = settings_1.TUYA_MODES.COOLING_SMART;
185
+ break;
186
+ case this.platform.Characteristic.TargetHeaterCoolerState.AUTO:
187
+ default:
188
+ mode = settings_1.TUYA_MODES.AUTO;
189
+ break;
190
+ }
191
+ const success = await this.platform.tuyaApi.sendCommand(this.deviceConfig.id, settings_1.DP_CODES.MODE, mode);
192
+ if (success) {
193
+ this.targetHeaterCoolerState = state;
194
+ }
195
+ }
196
+ async getHeatingThresholdTemperature() {
197
+ return this.heatingThresholdTemperature;
198
+ }
199
+ async setHeatingThresholdTemperature(value) {
200
+ const temp = value;
201
+ this.platform.log.info(`Setting heating threshold temperature to ${temp}°C`);
202
+ this.lastCommandTime = Date.now();
203
+ const tuyaTemp = (0, settings_1.celsiusToTuyaTemp)(temp);
204
+ const success = await this.platform.tuyaApi.sendCommand(this.deviceConfig.id, settings_1.DP_CODES.SET_HEATING_TEMP, tuyaTemp);
205
+ if (success) {
206
+ this.heatingThresholdTemperature = temp;
207
+ }
208
+ }
209
+ async getCoolingThresholdTemperature() {
210
+ return this.coolingThresholdTemperature;
211
+ }
212
+ async setCoolingThresholdTemperature(value) {
213
+ const temp = value;
214
+ this.platform.log.info(`Setting cooling threshold temperature to ${temp}°C`);
215
+ this.lastCommandTime = Date.now();
216
+ const tuyaTemp = (0, settings_1.celsiusToTuyaTemp)(temp);
217
+ const success = await this.platform.tuyaApi.sendCommand(this.deviceConfig.id, settings_1.DP_CODES.SET_COOLING_TEMP, tuyaTemp);
218
+ if (success) {
219
+ this.coolingThresholdTemperature = temp;
220
+ }
221
+ }
222
+ }
223
+ exports.HeaterCoolerAccessory = HeaterCoolerAccessory;
@@ -0,0 +1,3 @@
1
+ import { API } from 'homebridge';
2
+ declare const _default: (api: API) => void;
3
+ export default _default;
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const settings_1 = require("./settings");
4
+ const platform_1 = require("./platform");
5
+ exports.default = (api) => {
6
+ api.registerPlatform(settings_1.PLUGIN_NAME, settings_1.PLATFORM_NAME, platform_1.TuyaPoolHeatPumpPlatform);
7
+ };
@@ -0,0 +1,26 @@
1
+ import { API, DynamicPlatformPlugin, Logger, PlatformAccessory, Service, Characteristic } from 'homebridge';
2
+ import { TuyaPoolHeatPumpConfig, TuyaDeviceStatus } from './settings';
3
+ import { TuyaApi } from './tuyaApi';
4
+ type StatusCallback = (status: TuyaDeviceStatus[]) => void;
5
+ export declare class TuyaPoolHeatPumpPlatform implements DynamicPlatformPlugin {
6
+ readonly Service: typeof Service;
7
+ readonly Characteristic: typeof Characteristic;
8
+ readonly accessories: PlatformAccessory[];
9
+ readonly api: API;
10
+ readonly log: Logger;
11
+ readonly config: TuyaPoolHeatPumpConfig;
12
+ tuyaApi: TuyaApi;
13
+ private readonly pollInterval;
14
+ private pollTimer;
15
+ private readonly statusCallbacks;
16
+ constructor(log: Logger, config: TuyaPoolHeatPumpConfig, api: API);
17
+ configureAccessory(accessory: PlatformAccessory): void;
18
+ discoverDevices(): Promise<void>;
19
+ private authenticateWithRetry;
20
+ private scheduleReconnect;
21
+ private registerDevice;
22
+ private startPolling;
23
+ private pollDeviceStatus;
24
+ registerStatusCallback(deviceId: string, callback: StatusCallback): void;
25
+ }
26
+ export {};
@@ -0,0 +1,161 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TuyaPoolHeatPumpPlatform = void 0;
4
+ const settings_1 = require("./settings");
5
+ const tuyaApi_1 = require("./tuyaApi");
6
+ const thermostatAccessory_1 = require("./thermostatAccessory");
7
+ const heaterCoolerAccessory_1 = require("./heaterCoolerAccessory");
8
+ class TuyaPoolHeatPumpPlatform {
9
+ Service;
10
+ Characteristic;
11
+ accessories = [];
12
+ api;
13
+ log;
14
+ config;
15
+ tuyaApi;
16
+ pollInterval;
17
+ pollTimer = null;
18
+ statusCallbacks = new Map();
19
+ constructor(log, config, api) {
20
+ this.log = log;
21
+ this.config = config;
22
+ this.api = api;
23
+ this.Service = api.hap.Service;
24
+ this.Characteristic = api.hap.Characteristic;
25
+ this.pollInterval = config.options?.pollInterval || settings_1.DEFAULT_POLL_INTERVAL;
26
+ this.log.debug('Finished initializing platform:', config.name);
27
+ api.on('didFinishLaunching', () => {
28
+ this.log.debug('Executed didFinishLaunching callback');
29
+ this.discoverDevices();
30
+ });
31
+ api.on('shutdown', () => {
32
+ this.log.debug('Homebridge is shutting down');
33
+ if (this.pollTimer) {
34
+ clearInterval(this.pollTimer);
35
+ }
36
+ });
37
+ }
38
+ configureAccessory(accessory) {
39
+ this.log.info('Loading accessory from cache:', accessory.displayName);
40
+ this.accessories.push(accessory);
41
+ }
42
+ async discoverDevices() {
43
+ if (!this.config.options) {
44
+ this.log.error('No options configured. Please configure the plugin.');
45
+ return;
46
+ }
47
+ if (!this.config.devices || this.config.devices.length === 0) {
48
+ this.log.warn('No devices configured. Please add devices in the config.');
49
+ return;
50
+ }
51
+ // Initialize Tuya API
52
+ this.tuyaApi = new tuyaApi_1.TuyaApi(this.config.options, this.log);
53
+ const authenticated = await this.authenticateWithRetry(3, 10000);
54
+ if (!authenticated) {
55
+ this.log.error('Failed to authenticate after retries. Will keep trying in background.');
56
+ this.scheduleReconnect();
57
+ return;
58
+ }
59
+ // Register devices
60
+ for (const deviceConfig of this.config.devices) {
61
+ this.registerDevice(deviceConfig);
62
+ }
63
+ // Start polling for status updates
64
+ this.startPolling();
65
+ }
66
+ async authenticateWithRetry(maxRetries, delayMs) {
67
+ for (let attempt = 1; attempt <= maxRetries; attempt++) {
68
+ try {
69
+ await this.tuyaApi.authenticate();
70
+ return true;
71
+ }
72
+ catch (error) {
73
+ this.log.warn(`Authentication attempt ${attempt}/${maxRetries} failed:`, error);
74
+ if (attempt < maxRetries) {
75
+ this.log.info(`Retrying in ${delayMs / 1000} seconds...`);
76
+ await new Promise(resolve => setTimeout(resolve, delayMs));
77
+ }
78
+ }
79
+ }
80
+ return false;
81
+ }
82
+ scheduleReconnect() {
83
+ const reconnectDelay = 60000; // 1 minute
84
+ this.log.info(`Scheduling reconnection attempt in ${reconnectDelay / 1000} seconds...`);
85
+ setTimeout(async () => {
86
+ this.log.info('Attempting to reconnect to Tuya API...');
87
+ const authenticated = await this.authenticateWithRetry(3, 10000);
88
+ if (authenticated) {
89
+ this.log.info('Reconnection successful!');
90
+ // Register devices if not already done
91
+ for (const deviceConfig of this.config.devices) {
92
+ this.registerDevice(deviceConfig);
93
+ }
94
+ this.startPolling();
95
+ }
96
+ else {
97
+ this.scheduleReconnect();
98
+ }
99
+ }, reconnectDelay);
100
+ }
101
+ registerDevice(deviceConfig) {
102
+ const uuid = this.api.hap.uuid.generate(deviceConfig.id);
103
+ const existingAccessory = this.accessories.find(acc => acc.UUID === uuid);
104
+ if (existingAccessory) {
105
+ this.log.info('Restoring existing accessory from cache:', existingAccessory.displayName);
106
+ existingAccessory.context.device = deviceConfig;
107
+ if (deviceConfig.accessoryType === 'thermostat') {
108
+ new thermostatAccessory_1.ThermostatAccessory(this, existingAccessory, deviceConfig);
109
+ }
110
+ else {
111
+ new heaterCoolerAccessory_1.HeaterCoolerAccessory(this, existingAccessory, deviceConfig);
112
+ }
113
+ }
114
+ else {
115
+ this.log.info('Adding new accessory:', deviceConfig.name);
116
+ const accessory = new this.api.platformAccessory(deviceConfig.name, uuid);
117
+ accessory.context.device = deviceConfig;
118
+ if (deviceConfig.accessoryType === 'thermostat') {
119
+ new thermostatAccessory_1.ThermostatAccessory(this, accessory, deviceConfig);
120
+ }
121
+ else {
122
+ new heaterCoolerAccessory_1.HeaterCoolerAccessory(this, accessory, deviceConfig);
123
+ }
124
+ this.api.registerPlatformAccessories(settings_1.PLUGIN_NAME, settings_1.PLATFORM_NAME, [accessory]);
125
+ }
126
+ }
127
+ startPolling() {
128
+ this.log.info(`Starting status polling every ${this.pollInterval / 1000} seconds`);
129
+ this.pollTimer = setInterval(async () => {
130
+ for (const accessory of this.accessories) {
131
+ const deviceConfig = accessory.context.device;
132
+ if (deviceConfig) {
133
+ try {
134
+ await this.pollDeviceStatus(deviceConfig.id);
135
+ }
136
+ catch (error) {
137
+ this.log.error(`Failed to poll device ${deviceConfig.id}:`, error);
138
+ }
139
+ }
140
+ }
141
+ }, this.pollInterval);
142
+ }
143
+ async pollDeviceStatus(deviceId) {
144
+ try {
145
+ const status = await this.tuyaApi.getDeviceStatus(deviceId);
146
+ this.log.debug(`Device ${deviceId} status:`, JSON.stringify(status));
147
+ // Call registered callback for this device
148
+ const callback = this.statusCallbacks.get(deviceId);
149
+ if (callback) {
150
+ callback(status);
151
+ }
152
+ }
153
+ catch (error) {
154
+ this.log.error(`Failed to get status for device ${deviceId}:`, error);
155
+ }
156
+ }
157
+ registerStatusCallback(deviceId, callback) {
158
+ this.statusCallbacks.set(deviceId, callback);
159
+ }
160
+ }
161
+ exports.TuyaPoolHeatPumpPlatform = TuyaPoolHeatPumpPlatform;
@@ -0,0 +1,81 @@
1
+ import { PlatformConfig } from 'homebridge';
2
+ export declare const PLATFORM_NAME = "TuyaPoolHeatPump";
3
+ export declare const PLUGIN_NAME = "homebridge-tuya-pool-heater";
4
+ export declare const TUYA_ENDPOINTS: Record<string, string>;
5
+ export declare const DEFAULT_POLL_INTERVAL = 30000;
6
+ export declare const TEMP_SCALE = 10;
7
+ export declare const TEMP_RANGES: {
8
+ readonly heating: {
9
+ readonly min: 5;
10
+ readonly max: 55;
11
+ };
12
+ readonly cooling: {
13
+ readonly min: 5;
14
+ readonly max: 35;
15
+ };
16
+ readonly auto: {
17
+ readonly min: 5;
18
+ readonly max: 40;
19
+ };
20
+ };
21
+ export declare const DP_CODES: {
22
+ readonly SWITCH: "switch";
23
+ readonly MODE: "mode";
24
+ readonly TEMP_CURRENT: "temp_current";
25
+ readonly SET_HEATING_TEMP: "set_heating_temp";
26
+ readonly SET_COOLING_TEMP: "set_cold_temp";
27
+ readonly SET_AUTO_TEMP: "set_auto_temp";
28
+ };
29
+ export declare const TUYA_MODES: {
30
+ readonly AUTO: "Auto";
31
+ readonly HEATING_SMART: "Heating_Smart";
32
+ readonly HEATING_POWERFUL: "Heating_Powerful";
33
+ readonly HEATING_SILENT: "Heating_Silent";
34
+ readonly COOLING_SMART: "Cooling_Smart";
35
+ readonly COOLING_POWERFUL: "Cooling_Powerful";
36
+ readonly COOLING_SILENT: "Cooling_Silent";
37
+ };
38
+ export type TuyaMode = typeof TUYA_MODES[keyof typeof TUYA_MODES];
39
+ export type AccessoryType = 'thermostat' | 'heatercooler';
40
+ export interface TempRangeConfig {
41
+ min: number;
42
+ max: number;
43
+ }
44
+ export interface DeviceConfig {
45
+ id: string;
46
+ name: string;
47
+ accessoryType: AccessoryType;
48
+ heatingRange?: TempRangeConfig;
49
+ coolingRange?: TempRangeConfig;
50
+ autoRange?: TempRangeConfig;
51
+ }
52
+ export interface PluginOptions {
53
+ accessId: string;
54
+ accessKey: string;
55
+ endpoint: string;
56
+ username: string;
57
+ password: string;
58
+ countryCode: number;
59
+ pollInterval?: number;
60
+ }
61
+ export interface TuyaPoolHeatPumpConfig extends PlatformConfig {
62
+ options: PluginOptions;
63
+ devices: DeviceConfig[];
64
+ }
65
+ export interface TuyaDeviceStatus {
66
+ code: string;
67
+ value: boolean | number | string;
68
+ }
69
+ export interface HeatPumpState {
70
+ active: boolean;
71
+ mode: TuyaMode;
72
+ currentTemperature: number;
73
+ targetHeatingTemperature: number;
74
+ targetCoolingTemperature: number;
75
+ targetAutoTemperature: number;
76
+ }
77
+ export declare function isHeatingMode(mode: string): boolean;
78
+ export declare function isCoolingMode(mode: string): boolean;
79
+ export declare function isAutoMode(mode: string): boolean;
80
+ export declare function tuyaTempToCelsius(value: number): number;
81
+ export declare function celsiusToTuyaTemp(value: number): number;
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TUYA_MODES = exports.DP_CODES = exports.TEMP_RANGES = exports.TEMP_SCALE = exports.DEFAULT_POLL_INTERVAL = exports.TUYA_ENDPOINTS = exports.PLUGIN_NAME = exports.PLATFORM_NAME = void 0;
4
+ exports.isHeatingMode = isHeatingMode;
5
+ exports.isCoolingMode = isCoolingMode;
6
+ exports.isAutoMode = isAutoMode;
7
+ exports.tuyaTempToCelsius = tuyaTempToCelsius;
8
+ exports.celsiusToTuyaTemp = celsiusToTuyaTemp;
9
+ exports.PLATFORM_NAME = 'TuyaPoolHeatPump';
10
+ exports.PLUGIN_NAME = 'homebridge-tuya-pool-heater';
11
+ // Tuya API Endpoints by region
12
+ exports.TUYA_ENDPOINTS = {
13
+ us: 'https://openapi.tuyaus.com',
14
+ eu: 'https://openapi.tuyaeu.com',
15
+ cn: 'https://openapi.tuyacn.com',
16
+ in: 'https://openapi.tuyain.com',
17
+ };
18
+ // Default polling interval in milliseconds
19
+ exports.DEFAULT_POLL_INTERVAL = 30000;
20
+ // Temperature scaling factor (Tuya stores temps as value * 10)
21
+ exports.TEMP_SCALE = 10;
22
+ // Temperature ranges per mode (in Celsius)
23
+ exports.TEMP_RANGES = {
24
+ heating: { min: 5, max: 55 },
25
+ cooling: { min: 5, max: 35 },
26
+ auto: { min: 5, max: 40 },
27
+ };
28
+ // Tuya DP codes for pool heat pumps
29
+ exports.DP_CODES = {
30
+ SWITCH: 'switch',
31
+ MODE: 'mode',
32
+ TEMP_CURRENT: 'temp_current',
33
+ SET_HEATING_TEMP: 'set_heating_temp',
34
+ SET_COOLING_TEMP: 'set_cold_temp',
35
+ SET_AUTO_TEMP: 'set_auto_temp',
36
+ };
37
+ // Tuya mode values
38
+ exports.TUYA_MODES = {
39
+ AUTO: 'Auto',
40
+ HEATING_SMART: 'Heating_Smart',
41
+ HEATING_POWERFUL: 'Heating_Powerful',
42
+ HEATING_SILENT: 'Heating_Silent',
43
+ COOLING_SMART: 'Cooling_Smart',
44
+ COOLING_POWERFUL: 'Cooling_Powerful',
45
+ COOLING_SILENT: 'Cooling_Silent',
46
+ };
47
+ // Helper to check if mode is heating
48
+ function isHeatingMode(mode) {
49
+ return mode.toLowerCase().includes('heating');
50
+ }
51
+ // Helper to check if mode is cooling
52
+ function isCoolingMode(mode) {
53
+ return mode.toLowerCase().includes('cooling');
54
+ }
55
+ // Helper to check if mode is auto
56
+ function isAutoMode(mode) {
57
+ return mode.toLowerCase() === 'auto';
58
+ }
59
+ // Convert Tuya temperature to Celsius
60
+ function tuyaTempToCelsius(value) {
61
+ return value / exports.TEMP_SCALE;
62
+ }
63
+ // Convert Celsius to Tuya temperature
64
+ function celsiusToTuyaTemp(value) {
65
+ return Math.round(value * exports.TEMP_SCALE);
66
+ }
@@ -0,0 +1 @@
1
+ export {};