UNPKG

homebridge-daikin-local-platform

Version:

Homebridge platform plugin providing HomeKit support for Daikin air conditioners with local control

453 lines 19.6 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.DaikinLocalAPI = exports.DaikinDevice = exports.CLIMATE_FAN_SPEED_5 = exports.CLIMATE_FAN_SPEED_4 = exports.CLIMATE_FAN_SPEED_3 = exports.CLIMATE_FAN_SPEED_2 = exports.CLIMATE_FAN_SPEED_1 = exports.CLIMATE_FAN_SPEED_SLIENT = exports.CLIMATE_FAN_SPEED_AUTO = exports.CLIMATE_MODE_HUMIDIFY = exports.CLIMATE_MODE_DEHUMIDIFY = exports.CLIMATE_MODE_AUTO = exports.CLIMATE_MODE_COOLING = exports.CLIMATE_MODE_HEATING = exports.CLIMATE_MODE_FAN = void 0; const axios_1 = __importDefault(require("axios")); const axios_rate_limit_1 = __importDefault(require("axios-rate-limit")); const const_1 = require("./const"); exports.CLIMATE_MODE_FAN = '0000'; exports.CLIMATE_MODE_HEATING = '0100'; exports.CLIMATE_MODE_COOLING = '0200'; exports.CLIMATE_MODE_AUTO = '0300'; exports.CLIMATE_MODE_DEHUMIDIFY = '0500'; exports.CLIMATE_MODE_HUMIDIFY = '0800'; exports.CLIMATE_FAN_SPEED_AUTO = '0A00'; exports.CLIMATE_FAN_SPEED_SLIENT = '0B00'; exports.CLIMATE_FAN_SPEED_1 = '0300'; exports.CLIMATE_FAN_SPEED_2 = '0400'; exports.CLIMATE_FAN_SPEED_3 = '0500'; exports.CLIMATE_FAN_SPEED_4 = '0600'; exports.CLIMATE_FAN_SPEED_5 = '0700'; const CLIMATE_OPERATE_ON = '00'; const CLIMATE_OPERATE_OFF = '01'; const CLIMATE_OPERATE_SETTING = '02'; const COMMAND_QUERY = '{"requests":[{"op":2,"to":"/dsiot/edge.adp_i?filter=pv"},{"op":2,"to":"/dsiot/edge.adp_d?filter=pv"},{"op":2,"to":"/dsiot/edge.adp_f?filter=pv"},{"op":2,"to":"/dsiot/edge.dev_i?filter=pv"},{"op":2,"to":"/dsiot/edge/adr_0100.dgc_status?filter=pv"}]}'; const COMMAND_QUERY_WITH_MD = '{"requests":[{"op":2,"to":"/dsiot/edge.adp_i?filter=pv"},{"op":2,"to":"/dsiot/edge.adp_d?filter=pv"},{"op":2,"to":"/dsiot/edge.adp_f?filter=pv"},{"op":2,"to":"/dsiot/edge.dev_i?filter=pv"},{"op":2,"to":"/dsiot/edge/adr_0100.dgc_status"},{"op":2,"to":"/dsiot/edge/adr_0200.dgc_status"}]}'; const http = (0, axios_rate_limit_1.default)(axios_1.default.create(), { maxRequests: 1, perMilliseconds: 500 }); class DaikinDevice { constructor(IP, log) { this.IP = IP; this.log = log; this._lastUpdateTimestamp = 0; this._callback = null; this._IP = IP; this._Response = {}; this._log = log; } setCallback(callback) { this._callback = callback; } async queryDevice(bForce = false) { if (!bForce && (Date.now() - this._lastUpdateTimestamp) < const_1.SECONDS_BETWEEN_REQUEST) { this.log.debug(`Daikin - queryDevice('${this._IP}'): Skipping query as last update was less than ${const_1.SECONDS_BETWEEN_REQUEST} micro seconds ago`); return this._Response; } const response = await http.request({ method: 'post', url: `http://${this._IP}${const_1.ENDPOINT}`, headers: { 'Accept': 'application/json; charset=UTF-8', 'Content-Type': 'application/json', 'User-Agent': const_1.USER_AGENT, }, data: COMMAND_QUERY_WITH_MD, }); this._lastUpdateTimestamp = Date.now(); if (response.status === 200) { //this.log.debug(`Daikin - queryDevice('${this._IP}'): Response: '${JSON.stringify(response.data)}'`); return response.data; } this.log.debug(`Daikin - queryDevice('${this._IP}'): Error: Invalid response status code: '${response.status}'`); return undefined; } async fetchDeviceStatus(bForce = false) { const response = await this.queryDevice(bForce); this._Response = response; this.log.debug(`Daikin - fetchDeviceStatus(${bForce}): Name: ${this.getDeviceName()} MAC:${this.getMacAddress()} Power:${this.getPowerStatus()} Temp:${this.getIndoorTemperature()} Humidity:${this.getIndoorHumidity()} Target Temp:${this.getTargetTemperature()}' Mode:${this.getOperationModeName()} FanSpeed:${this.getFanSpeedName()} `); if (this._callback) { this._callback(this); } return true; } async setShowSSID(bShow) { this.log.debug(`Daikin - setShowSSID(${bShow}): Name: ${this.getDeviceName()}`); const command = { "requests": [{ "op": 3, "to": "/dsiot/edge.adp_d", "pc": { "pn": "adp_d", "pch": [{ "pn": "disp_ssid", "pv": bShow ? 0 : 1 }] } }] }; const response = await http.request({ method: 'post', url: `http://${this._IP}${const_1.ENDPOINT}`, headers: { 'Accept': 'application/json; charset=UTF-8', 'Content-Type': 'application/json', 'User-Agent': const_1.USER_AGENT, }, data: JSON.stringify(command), }); return response.status === 200; } getMacAddress() { return this.extractValue(this._Response, '/dsiot/edge.adp_i', 'mac'); } getSSID() { return this.extractValue(this._Response, '/dsiot/edge.adp_i', 'ssid'); } getDeviceName() { return this.extractValue(this._Response, '/dsiot/edge.adp_d', 'name'); } getDeviceReg() { return this.extractValue(this._Response, '/dsiot/edge.adp_i', 'reg'); } getDeviceType() { return this.extractValue(this._Response, '/dsiot/edge.dev_i', 'type') + this.extractValue(this._Response, '/dsiot/edge.adp_i', 'enlv'); } getFirmwareVersion() { return this.extractValue(this._Response, '/dsiot/edge.adp_i', 'ver'); } getDeviceIP() { return this._IP; } getPowerStatus() { return this.extractValue(this._Response, '/dsiot/edge/adr_0100.dgc_status', 'e_1002/e_A002/p_01') === '01'; } getIndoorTemperature() { return parseInt(this.extractValue(this._Response, '/dsiot/edge/adr_0100.dgc_status', 'e_1002/e_A00B/p_01'), 16); } getIndoorHumidity() { return parseInt(this.extractValue(this._Response, '/dsiot/edge/adr_0100.dgc_status', 'e_1002/e_A00B/p_02'), 16); } //0000:fan 0100:heating 0200:cooling 0300:auto 0500:dehumidify getOperationMode() { return this.extractValue(this._Response, '/dsiot/edge/adr_0100.dgc_status', 'e_1002/e_3001/p_01'); } getOperationModeName() { const mode = this.getOperationMode(); if (mode === exports.CLIMATE_MODE_FAN) { return 'Fan'; } else if (mode === exports.CLIMATE_MODE_DEHUMIDIFY) { return 'Dehumidify'; } else if (mode === exports.CLIMATE_MODE_AUTO) { return 'Auto'; } else if (mode === exports.CLIMATE_MODE_HEATING) { return 'Heating'; } else if (mode === exports.CLIMATE_MODE_COOLING) { return 'Cooling'; } return 'Unknown'; } getTargetTemperatureWithMode(mode) { if (mode === exports.CLIMATE_MODE_HEATING) { return parseInt(this.extractValue(this._Response, '/dsiot/edge/adr_0100.dgc_status', 'e_1002/e_3001/p_03'), 16) / 2.0; } else if (mode === exports.CLIMATE_MODE_COOLING) { return parseInt(this.extractValue(this._Response, '/dsiot/edge/adr_0100.dgc_status', 'e_1002/e_3001/p_02'), 16) / 2.0; } else if (mode === exports.CLIMATE_MODE_AUTO) { return parseInt(this.extractValue(this._Response, '/dsiot/edge/adr_0100.dgc_status', 'e_1002/e_3001/p_1D'), 16) / 2.0; } this.log.debug(`Daikin - getTargetTemperature(): Error: Invalid mode: '${mode}'`); return 0; } getTargetTemperature() { const mode = this.getOperationMode(); return this.getTargetTemperatureWithMode(mode); } getTargetTemperatureRange() { const mode = this.getOperationMode(); let pn = 'p_02'; if (mode === exports.CLIMATE_MODE_HEATING) { pn = 'p_03'; } else if (mode === exports.CLIMATE_MODE_COOLING) { pn = 'p_02'; } else if (mode === exports.CLIMATE_MODE_AUTO) { pn = 'p_1D'; } else { this.log.debug(`Daikin - getTargetTemperatureRange(): Error: Invalid mode: '${mode}'`); return [0, 0]; } const md = this.extractObject(this._Response, '/dsiot/edge/adr_0100.dgc_status', 'e_1002/e_3001/' + pn); const min = md ? parseInt(md['md']['mi'], 16) / 2.0 : 0; const max = md ? parseInt(md['md']['mx'], 16) / 2.0 : 0; return [min, max]; } getCoolingThresholdTemperatureRange() { const md = this.extractObject(this._Response, '/dsiot/edge/adr_0100.dgc_status', 'e_1002/e_3001/p_02'); const min = md ? parseInt(md['md']['mi'], 16) / 2.0 : 0; const max = md ? parseInt(md['md']['mx'], 16) / 2.0 : 0; return [min, max]; } getHeatingThresholdTemperatureRange() { const md = this.extractObject(this._Response, '/dsiot/edge/adr_0100.dgc_status', 'e_1002/e_3001/p_03'); const min = md ? parseInt(md['md']['mi'], 16) / 2.0 : 0; const max = md ? parseInt(md['md']['mx'], 16) / 2.0 : 0; return [min, max]; } getFanSpeed() { const mode = this.getOperationMode(); let pn = 'p_09'; if (mode === exports.CLIMATE_MODE_FAN) { pn = 'p_28'; } else if (mode === exports.CLIMATE_MODE_DEHUMIDIFY) { pn = 'p_27'; } else if (mode === exports.CLIMATE_MODE_AUTO) { pn = 'p_26'; } else if (mode === exports.CLIMATE_MODE_HEATING) { pn = 'p_0A'; } else if (mode === exports.CLIMATE_MODE_COOLING) { pn = 'p_09'; } return this.extractValue(this._Response, '/dsiot/edge/adr_0100.dgc_status', 'e_1002/e_3001/' + pn); } getFanSpeedName() { const speed = this.getFanSpeed(); if (speed === exports.CLIMATE_FAN_SPEED_AUTO) { return 'Auto'; } else if (speed === exports.CLIMATE_FAN_SPEED_SLIENT) { return 'Silent'; } else if (speed === exports.CLIMATE_FAN_SPEED_1) { return '1'; } else if (speed === exports.CLIMATE_FAN_SPEED_2) { return '2'; } else if (speed === exports.CLIMATE_FAN_SPEED_3) { return '3'; } else if (speed === exports.CLIMATE_FAN_SPEED_4) { return '4'; } else if (speed === exports.CLIMATE_FAN_SPEED_5) { return '5'; } return 'Unknown'; } getFanSpeedNumber() { const speed = this.getFanSpeed(); if (speed === exports.CLIMATE_FAN_SPEED_AUTO) { return 0; } else if (speed === exports.CLIMATE_FAN_SPEED_SLIENT) { return 1; } else if (speed === exports.CLIMATE_FAN_SPEED_1) { return 2; } else if (speed === exports.CLIMATE_FAN_SPEED_2) { return 3; } else if (speed === exports.CLIMATE_FAN_SPEED_3) { return 4; } else if (speed === exports.CLIMATE_FAN_SPEED_4) { return 5; } else if (speed === exports.CLIMATE_FAN_SPEED_5) { return 6; } return 0; } getMotionDetection() { return this.extractValue(this._Response, '/dsiot/edge/adr_0100.dgc_status', 'e_1002/e_3003/p_27') === '01'; } async setMotionDetection(bEnable) { const command = [{ "pn": "e_3003", "pch": [{ "pn": "p_27", "pv": bEnable ? '01' : '00' }] }]; return await this.sendCommand(command); } async setPowerStatus(power) { const command = [{ "pn": "e_3003", "pch": [{ "pn": "p_2D", "pv": CLIMATE_OPERATE_SETTING }] }, { "pn": "e_A002", "pch": [{ "pn": "p_01", "pv": power ? '01' : '00' }] }]; return await this.sendCommand(command); } async setOperationMode(mode) { const command = [{ "pn": "e_3003", "pch": [{ "pn": "p_2D", "pv": CLIMATE_OPERATE_SETTING }] }, { "pn": "e_3001", "pch": [{ "pn": "p_01", "pv": mode }] }]; return await this.sendCommand(command); } async setTargetTemperature(temperature) { const mode = this.getOperationMode(); let pn = 'p_02'; const pv = (temperature * 2).toString(16); if (mode === exports.CLIMATE_MODE_HEATING) { pn = 'p_03'; } else if (mode === exports.CLIMATE_MODE_COOLING) { pn = 'p_02'; } else if (mode === exports.CLIMATE_MODE_AUTO) { pn = 'p_1D'; } else { return false; } let command = [{ "pn": "e_3003", "pch": [{ "pn": "p_2D", "pv": CLIMATE_OPERATE_SETTING }] }, { "pn": "e_3001", "pch": [{ "pn": pn, "pv": pv }] }]; if (mode === exports.CLIMATE_MODE_COOLING) { this.pushObject(command, 'e_3001', { "pn": "p_0B", "pv": '0A' }); this.pushObject(command, 'e_3001', { "pn": "p_0C", "pv": '01' }); } return await this.sendCommand(command); } async setFanSpeed(speed) { const mode = this.getOperationMode(); let pn = 'p_09'; if (mode === exports.CLIMATE_MODE_FAN) { pn = 'p_28'; } else if (mode === exports.CLIMATE_MODE_DEHUMIDIFY) { pn = 'p_27'; } else if (mode === exports.CLIMATE_MODE_AUTO) { pn = 'p_26'; } else if (mode === exports.CLIMATE_MODE_HEATING) { pn = 'p_0A'; } else if (mode === exports.CLIMATE_MODE_COOLING) { pn = 'p_09'; } const command = [{ "pn": "e_3003", "pch": [{ "pn": "p_2D", "pv": CLIMATE_OPERATE_SETTING }] }, { "pn": "e_3001", "pch": [{ "pn": pn, "pv": speed }] }]; return await this.sendCommand(command); } extractValue(responsesData, fr, path) { try { if (responsesData === undefined || responsesData.hasOwnProperty('responses') === false) { this.log.debug('Daikin - extractValue(): Error: No responses object found'); return undefined; } let currentObject = responsesData['responses']; for (const response of currentObject) { if (response['fr'] === fr) { currentObject = response['pc']['pch']; } } const pathKeys = path.split('/'); for (let i = 0; i < pathKeys.length; i++) { try { const key = pathKeys[i]; for (const currentObjectElement of currentObject) { if ((currentObjectElement['pn'] === key && currentObjectElement.hasOwnProperty('pch'))) { currentObject = currentObjectElement['pch']; break; } else if (currentObjectElement['pn'] === key && currentObjectElement.hasOwnProperty('pv')) { if (i === pathKeys.length - 1) { return currentObjectElement['pv']; } } } } catch (e) { this.log.debug('Daikin - extractValue(): Error:' + e); } } } catch (e) { this.log.debug('Daikin - extractValue(): Error:' + e); } this.log.debug('Daikin - extractValue(): Error: No value found for path:' + path); return undefined; } extractObject(responsesData, fr, path) { try { if (responsesData === undefined || responsesData.hasOwnProperty('responses') === false) { this.log.debug('Daikin - extractObject(): Error: No responses object found'); return undefined; } let currentObject = responsesData['responses']; for (const response of currentObject) { if (response['fr'] === fr) { currentObject = response['pc']['pch']; } } const pathKeys = path.split('/'); for (const key of pathKeys) { try { for (const currentObjectElement of currentObject) { if (currentObjectElement['pn'] === key && currentObjectElement.hasOwnProperty('pch')) { currentObject = currentObjectElement['pch']; break; } else if (currentObjectElement['pn'] === key && currentObjectElement.hasOwnProperty('pv')) { return currentObjectElement; } } } catch (e) { this.log.debug('Daikin - extractValue(): Error:' + e); } } } catch (e) { this.log.debug('Daikin - extractValue(): Error:' + e); } this.log.debug('Daikin - extractValue(): Error: No value found for path:' + path); return undefined; } // const command = [{"pn": "e_3003", "pch": [{"pn": "p_2D", "pv": CLIMATE_OPERATE_SETTING}]}, {"pn": "e_3001","pch": [{"pn": pn, "pv": speed}]}]; pushObject(jsonData, pn, obj) { try { for (const i in jsonData) { const currentObject = jsonData[i]; if (currentObject['pn'] === pn && currentObject.hasOwnProperty('pch')) { currentObject['pch'].push(obj); return jsonData; } } } catch (e) { this.log.debug('Daikin - pushObject(): Error:' + e); } return undefined; } async sendCommand(command) { const param = { "requests": [{ "op": 3, "to": "/dsiot/edge/adr_0100.dgc_status", "pc": { "pn": "dgc_status", "pch": [{ "pn": "e_1002", "pch": command }] } }] }; const response = await http.request({ method: 'post', url: `http://${this._IP}${const_1.ENDPOINT}`, headers: { 'Accept': 'application/json; charset=UTF-8', 'Content-Type': 'application/json', 'User-Agent': const_1.USER_AGENT, }, data: JSON.stringify(param), }); if (response.status === 200) { this.log.debug(`Daikin - sendCommand('${this._IP}'): '${JSON.stringify(param)} ' : Response: '${JSON.stringify(response.data)}'`); } else { this.log.debug(`Daikin - sendCommand('${this._IP}'): '${JSON.stringify(param)} ' : Error: Invalid response status code: '${response.status}'`); } await this.fetchDeviceStatus(true); return response.status === 200; } } exports.DaikinDevice = DaikinDevice; class DaikinLocalAPI { constructor(log) { this.log = log; this._devices = []; } async fetchDevices(climateIPs, bForce = false) { this.log.debug('Daikin: fetchDevices()'); this._devices = []; for (const ip of climateIPs) { const daikinDevice = new DaikinDevice(ip, this.log); if (await daikinDevice.fetchDeviceStatus(bForce)) { this._devices.push(daikinDevice); } } return this._devices; } } exports.DaikinLocalAPI = DaikinLocalAPI; //# sourceMappingURL=daikin-local.js.map