homebridge-openhab2-complete icon indicating copy to clipboard operation
homebridge-openhab2-complete copied to clipboard

Heater/Cooler Accessory with sepparate min-max temp for thresholds

Open kanivaloss opened this issue 3 years ago • 5 comments

Homekit uses heatingThresholdTempItem and coolingThresholdTempItem to set the temperature when both heatingItem and coolingItem are sellected. I wasn't able to manipulate the currentTempItem throug homekit/Siri. I also needed to be able to set heating and cooling individualy so I played aroundwith the climate.js file.

I added seperate variables ( minHeatThrTemp, minCoolThrTemp etc) and edited the addHeatingThresholdCharacteristic and addCoolingThresholdCharacteristic functions..

Not sure if this could be implimented in some future release.

I have attached the edited file below.

Thanks for all the great work you are doing!


'use strict';

const {addNumericSensorCharacteristic,
    addNumericSensorCharacteristicWithTransformation,
    addNumericSensorActorCharacteristic,
    addNumericSensorActorCharacteristicWithDistinctTransformation
} = require('./Numeric');

const CLIMATE_CONFIG = {
    waterLevelItem: "waterLevelItem",
    rotationSpeedItem: "rotationSpeedItem",
    currentHumidityItem: "currentHumidityItem",
    targetHumidityItem: "targetHumidityItem",
    currentTempItem: "currentTempItem",
    targetTempItem: "targetTempItem",
    heatingThresholdTempItem: "heatingThresholdTempItem",
    coolingThresholdTempItem: "coolingThresholdTempItem",
    dehumidifierThresholdItem: "dehumidifierThresholdItem",
    humidifierThresholdItem: "humidifierThresholdItem",
    tempUnit: "tempUnit", // 'Celsius' (default), 'Fahrenheit'
    minTemp: "minTemp",
    maxTemp: "maxTemp",
    minTempStep: "minTempStep",
    //edit
    minHeatThrTemp: "minHeatThrTemp",
    maxHeatThrTemp: "maxHeatThrTemp",
    minHeatThrTempStep: "minHeatThrTempStep",
    minCoolThrTemp: "minCoolThrTemp",
    maxCoolThrTemp: "maxCoolThrTemp",
    minCoolThrTempStep: "minCoolThrTempStep",
    //edit
    minFanSpeed: "minFanSpeed",
    maxFanSpeed: "maxFanSpeed",
    minFanStep: "minFanStep"
};

const DEFAULT_MIN_TEMP = -100;
const DEFAULT_MAX_TEMP = 200;
const DEFAULT_MIN_TEMP_STEP = 0.1;

const DEFAULT_MIN_FAN_SPEED = 0;
const DEFAULT_MAX_FAN_SPEED = 100;
const DEFAULT_MIN_FAN_STEP = 1;


function addWaterLevelCharacteristic(service, optional) {
    addNumericSensorCharacteristic.bind(this)(service, service.getCharacteristic(this.Characteristic.WaterLevel), {item: CLIMATE_CONFIG.waterLevelItem}, optional);
}

function addRotationSpeedCharacteristic(service, optional) {
    let thisMinSpeed = this._config[CLIMATE_CONFIG.minFanSpeed] !== undefined ? parseFloat(this._config[CLIMATE_CONFIG.minFanSpeed]) : DEFAULT_MIN_FAN_SPEED;
    let thisMaxSpeed = this._config[CLIMATE_CONFIG.maxFanSpeed] !== undefined ? parseFloat(this._config[CLIMATE_CONFIG.maxFanSpeed]) : DEFAULT_MAX_FAN_SPEED;
    let thisMinStep = this._config[CLIMATE_CONFIG.minFanStep] !== undefined ? parseFloat(this._config[CLIMATE_CONFIG.minFanStep]) : DEFAULT_MIN_FAN_STEP;

    let rotationSpeedCharacteristic = service.getCharacteristic(this.Characteristic.RotationSpeed);
    rotationSpeedCharacteristic.setProps({
        minValue: thisMinSpeed,
        maxValue: thisMaxSpeed,
        minTempStep: thisMinStep
    });

    this._log.debug(`Applied minValue ${thisMinSpeed}, maxValue ${thisMaxSpeed} and minStep ${thisMinStep} for fan speed`);

    addNumericSensorActorCharacteristic.bind(this)(service, rotationSpeedCharacteristic, {item: CLIMATE_CONFIG.rotationSpeedItem}, optional);
}

function addCurrentRelativeHumidityCharacteristic(service, optional) {
    addNumericSensorCharacteristic.bind(this)(service, service.getCharacteristic(this.Characteristic.CurrentRelativeHumidity), {item: CLIMATE_CONFIG.currentHumidityItem}, optional);
}

function addTargetRelativeHumidityCharacteristic(service, optional) {
    addNumericSensorActorCharacteristic.bind(this)(service, service.getCharacteristic(this.Characteristic.TargetRelativeHumidity), {item: CLIMATE_CONFIG.targetHumidityItem}, optional);
}

function addCurrentTemperatureCharacteristic(service, optional) {
    let thisMinTemp = this._config[CLIMATE_CONFIG.minTemp] !== undefined ? parseFloat(this._config[CLIMATE_CONFIG.minTemp]) : DEFAULT_MIN_TEMP;
    let thisMaxTemp = this._config[CLIMATE_CONFIG.maxTemp] !== undefined ? parseFloat(this._config[CLIMATE_CONFIG.maxTemp]) : DEFAULT_MAX_TEMP;
    let thisMinStep = this._config[CLIMATE_CONFIG.minTempStep] !== undefined ? parseFloat(this._config[CLIMATE_CONFIG.minTempStep]) : DEFAULT_MIN_TEMP_STEP;

    let transformation = this._config[CLIMATE_CONFIG.tempUnit] === "Fahrenheit" ? _convertFahrenheitToCelsius : parseFloat;

    let currentTemperatureCharacteristic = service.getCharacteristic(this.Characteristic.CurrentTemperature);
    currentTemperatureCharacteristic.setProps({
        minValue: thisMinTemp,
        maxValue: thisMaxTemp,
        minStep: thisMinStep
    });

    this._log.debug(`Applied minValue ${thisMinTemp}, maxValue ${thisMaxTemp} and minStep ${thisMinStep} for temp`);

    addNumericSensorCharacteristicWithTransformation.bind(this)(service,
        currentTemperatureCharacteristic,
        {item: CLIMATE_CONFIG.currentTempItem},
        transformation,
        optional
    );
}

function addTargetTemperatureCharacteristic(service, optional) {
    let thisMinTemp = this._config[CLIMATE_CONFIG.minTemp] !== undefined ? parseFloat(this._config[CLIMATE_CONFIG.minTemp]) : DEFAULT_MIN_TEMP;
    let thisMaxTemp = this._config[CLIMATE_CONFIG.maxTemp] !== undefined ? parseFloat(this._config[CLIMATE_CONFIG.maxTemp]) : DEFAULT_MAX_TEMP;
    let thisMinStep = this._config[CLIMATE_CONFIG.minTempStep] !== undefined ? parseFloat(this._config[CLIMATE_CONFIG.minTempStep]) : DEFAULT_MIN_TEMP_STEP;

    let getTransformation = this._config[CLIMATE_CONFIG.tempUnit] === "Fahrenheit" ? _convertFahrenheitToCelsius : parseFloat;
    let setTransformation = this._config[CLIMATE_CONFIG.tempUnit] === "Fahrenheit" ? _convertCelsiusToFahrenheit : parseFloat;

    let targetTemperatureCharacteristic = service.getCharacteristic(this.Characteristic.TargetTemperature);
    targetTemperatureCharacteristic.setProps({
        minValue: thisMinTemp,
        maxValue: thisMaxTemp,
        minStep: thisMinStep
    });
    addNumericSensorActorCharacteristicWithDistinctTransformation.bind(this)(service,
        targetTemperatureCharacteristic,
        {item: CLIMATE_CONFIG.targetTempItem},
        setTransformation,
        getTransformation,
        optional
    );
}

function _convertFahrenheitToCelsius(val) {
    return (((parseFloat(val)-32)*5)/9);
}

function _convertCelsiusToFahrenheit(val) {
    return (((parseFloat(val) * 9)/5) + 32);
}

//edit
function addCoolingThresholdCharacteristic(service, optional) {
    let thisMinTemp = this._config[CLIMATE_CONFIG.minCoolThrTemp] !== undefined ? parseFloat(this._config[CLIMATE_CONFIG.minCoolThrTemp]) : DEFAULT_MIN_TEMP;
    let thisMaxTemp = this._config[CLIMATE_CONFIG.maxCoolThrTemp] !== undefined ? parseFloat(this._config[CLIMATE_CONFIG.maxCoolThrTemp]) : DEFAULT_MAX_TEMP;
    let thisMinStep = this._config[CLIMATE_CONFIG.minCoolThrTempStep] !== undefined ? parseFloat(this._config[CLIMATE_CONFIG.minCoolThrTempStep]) : DEFAULT_MIN_TEMP_STEP;

    let getTransformation = this._config[CLIMATE_CONFIG.tempUnit] === "Fahrenheit" ? _convertFahrenheitToCelsius : parseFloat;
    let setTransformation = this._config[CLIMATE_CONFIG.tempUnit] === "Fahrenheit" ? _convertCelsiusToFahrenheit : parseFloat;

    let CoolingThresholdCharacteristic = service.getCharacteristic(this.Characteristic.CoolingThresholdTemperature);
    CoolingThresholdCharacteristic.setProps({
        minValue: thisMinTemp,
        maxValue: thisMaxTemp,
        minStep: thisMinStep
    });
        addNumericSensorActorCharacteristicWithDistinctTransformation.bind(this)(service,
        CoolingThresholdCharacteristic,
        {item: CLIMATE_CONFIG.coolingThresholdTempItem},
        setTransformation,
        getTransformation,
        optional
    );
}

function addHeatingThresholdCharacteristic(service, optional) {
    addNumericSensorActorCharacteristic.bind(this)(service, service.getCharacteristic(this.Characteristic.HeatingThresholdTemperature), {item: CLIMATE_CONFIG.heatingThresholdTempItem}, optional);
}

function addHeatingThresholdCharacteristic(service, optional) {
    let thisMinTemp = this._config[CLIMATE_CONFIG.minHeatThrTemp] !== undefined ? parseFloat(this._config[CLIMATE_CONFIG.minHeatThrTemp]) : DEFAULT_MIN_TEMP;
    let thisMaxTemp = this._config[CLIMATE_CONFIG.maxHeatThrTemp] !== undefined ? parseFloat(this._config[CLIMATE_CONFIG.maxHeatThrTemp]) : DEFAULT_MAX_TEMP;
    let thisMinStep = this._config[CLIMATE_CONFIG.minHeatThrTempStep] !== undefined ? parseFloat(this._config[CLIMATE_CONFIG.minHeatThrTempStep]) : DEFAULT_MIN_TEMP_STEP;

    let getTransformation = this._config[CLIMATE_CONFIG.tempUnit] === "Fahrenheit" ? _convertFahrenheitToCelsius : parseFloat;
    let setTransformation = this._config[CLIMATE_CONFIG.tempUnit] === "Fahrenheit" ? _convertCelsiusToFahrenheit : parseFloat;

    let HeatingThresholdCharacteristic = service.getCharacteristic(this.Characteristic.HeatingThresholdTemperature);
    HeatingThresholdCharacteristic.setProps({
        minValue: thisMinTemp,
        maxValue: thisMaxTemp,
        minStep: thisMinStep
    });
        addNumericSensorActorCharacteristicWithDistinctTransformation.bind(this)(service,
        HeatingThresholdCharacteristic,
        {item: CLIMATE_CONFIG.heatingThresholdTempItem},
        setTransformation,
        getTransformation,
        optional
    );
}
//edit

function addRelativeHumidityDehumidifierThresholdCharacteristic(service, optional) {
    addNumericSensorActorCharacteristic.bind(this)(service, service.getCharacteristic(this.Characteristic.RelativeHumidityDehumidifierThreshold), {item: CLIMATE_CONFIG.dehumidifierThresholdItem}, optional);
}

function addRelativeHumidityHumidifierThresholdCharacteristic(service, optional) {
    addNumericSensorActorCharacteristic.bind(this)(service, service.getCharacteristic(this.Characteristic.RelativeHumidityHumidifierThreshold), {item: CLIMATE_CONFIG.humidifierThresholdItem}, optional);
}

function addTemperatureDisplayUnitsCharacteristic(service) {
    switch (this._config[CLIMATE_CONFIG.tempUnit]) {
        default:
        case 'Celsius':
            this._tempUnit = this.Characteristic.TemperatureDisplayUnits.CELSIUS;
            break;
        case 'Fahrenheit':
            this._tempUnit = this.Characteristic.TemperatureDisplayUnits.FAHRENHEIT;
            break;
    }

    service.getCharacteristic(this.Characteristic.TemperatureDisplayUnits)
        .setValue(this._tempUnit);
}

module.exports = {
    addWaterLevelCharacteristic,
    addRotationSpeedCharacteristic,
    addCurrentRelativeHumidityCharacteristic,
    addCurrentTemperatureCharacteristic,
    addCoolingThresholdCharacteristic,
    addHeatingThresholdCharacteristic,
    addTemperatureDisplayUnitsCharacteristic,
    addTargetRelativeHumidityCharacteristic,
    addTargetTemperatureCharacteristic,
    addRelativeHumidityDehumidifierThresholdCharacteristic,
    addRelativeHumidityHumidifierThresholdCharacteristic
};

kanivaloss avatar Jan 20 '22 22:01 kanivaloss

I'm fighting with this problem for quite some time now, it only allows temp between 0 and 35 so the values must be hardcoded somewhere, recall there was also a typo for fan speed in Climate.js. Will give a try of your workaround, thanks!

maisun avatar Jan 28 '22 19:01 maisun

@kanivaloss could you please open a pull request with your proposed changes? happy to review and merge upstream!

steilerDev avatar Feb 10 '22 07:02 steilerDev

@maisun This is part of the default characteristics...

See here. I am not sure if we can overwrite those with arbitrary numbers or if there is another check on HK side....

steilerDev avatar Feb 10 '22 07:02 steilerDev

@maisun This is part of the default characteristics...

See here. I am not sure if we can overwrite those with arbitrary numbers or if there is another check on HK side.... @steilerDev, I can confirm @kanivaloss's fix works for me, tested with success. Also I'd like to point a typo in line 48: rotationSpeedCharacteristic.setProps({ minValue: thisMinSpeed, maxValue: thisMaxSpeed, minTempStep: thisMinStep //Should be minStep instead });

maisun avatar Feb 10 '22 07:02 maisun

@maisun @kanivaloss If this is confirmed to be working, please open a PR so I can merge it into a future release :) Thank you!

steilerDev avatar Feb 10 '22 08:02 steilerDev