ioBroker / AdapterRequests

This Place is used to track the status of new Adapter-Requests.
249 stars 36 forks source link

Uponor Heizungssteuerung / Fussbodenheizung #313

Open poweruser0815 opened 4 years ago

poweruser0815 commented 4 years ago

Hallo, hat jemand die Möglichkeit Uponor Komponenten anzusteuern ?

Apollon77 commented 4 years ago

Hast DU mehr Details? Links? APIs? Andere Libraries oder Integrationen?

gromet commented 4 years ago

Für Uponor smart wave Konmponenten gibt es was. Um einige Links zu nennen mit Api (in Python)

POST /api {"jsonrpc":"2.0","id":6358,"method":"readactivealarms","params":{}}

siehe Links für Details

https://fuerles.de/index.php/it-welt/9-smarthome/7-uponor-fussbodenheizung-smatrix-wave-plus https://github.com/dave-code-ruiz/uhomeuponor https://github.com/almirdelkic/uhome

gromet commented 4 years ago

Habe ein Script für Uponor Smatrix R-208 Schnittelle geschrieben um die Theromstate auszulesen

var request = require('request');

class uponor {
    constructor (ip) {
        this.constants = {
            STATUS_OK: 'OK',
            STATUS_ERROR_BATTERY: 'Battery error',
            STATUS_ERROR_VALVE: 'Valve position error',
            STATUS_ERROR_GENERAL: 'General system error',
            STATUS_ERROR_AIR_SENSOR: 'Air sensor error',
            STATUS_ERROR_EXT_SENSOR: 'External sensor error',
            STATUS_ERROR_RH_SENSOR: 'Humidity sensor error',
            STATUS_ERROR_RF_SENSOR: 'RF sensor error',
            STATUS_ERROR_TAMPER: 'Tamper error',
            STATUS_ERROR_TOO_HIGH_TEMP: 'API error',
            TOO_HIGH_TEMP_LIMIT: 4508,
            TOO_LOW_HUMIDITY_LIMIT: 0,
        };
            // datenpunkte erstellen für uponor
        this.data_path = '0_userdata.0.uponor';
        if (!getObject(`${this.data_path}.ip`)){
            this.erstelleDatenpunkt(`${this.data_path}.ip`, {"type":"string", "read": true, "write": true, "def": ''}, ip);
            this.erstelleDatenpunkt(`${this.data_path}.path`, {"type":"string", "read": true, "write": true, "def": ''}, 'JNAP');
            this.erstelleDatenpunkt(`${this.data_path}.jnap_action`, {"type":"string", "read": true, "write": true, "def": ''}, 'http://phyn.com/jnap/uponorsky/GetAttributes');

        }
        this.url = 'http://' + getState(`${this.data_path}.ip`).val + '/' + getState(`${this.data_path}.path`).val + '/';
        this.x_jnap_action = getState(`${this.data_path}.jnap_action`).val;
        this._data = [];
    }

    /**
    * erstellt Datenpunkte und setzt das angegeben value
    */
    function this.erstelleDatenpunkt(id, common, value) {
        if(!getObject(id)) {
            let obj = {
                type: 'state',
                common: common
            };
            setObject(id, obj, function (err) {
                if (err) {
                    log('Fehler beim Datenpunk erstellen: ' + err);
                } else {
                    setTimeout(function() {
                        setState(id, (typeof value !== 'undefined' ? value : obj.common.def));
                    }, 500)
                }
            });
        }
    }

    /** Holt basis infos aus uponor */
    async getData (data = {}) {
        return new Promise((resolve,reject) => {
            request.post(this.url, {
                    json: data,
                    headers: {
                        'x-jnap-action': this.x_jnap_action
                    }
                }, (error, res, body) => {
                if (error) {
                    log(error);
                    return false;
                }
                if(res.statusCode === 200){
                    if(res.body.result === this.constants.STATUS_OK){
                        //console.log(res.body.output);
                        const result = {};
                        for(let item of res.body.output.vars)
                        {
                            result[item.waspVarName] = item.waspVarValue
                        }
                        this._data = result;
                        resolve(result);
                    }
                    else{
                        log(`Uponor getData - Fehlerhafte Anfrage`);
                       reject(false);
                    }
                }
                else{
                    log(`Uponor getData request ist schief gegangen. ${error}`);
                    reject(false);
                }
            })
        });
    }

    /**
     * @description durchsucht nach aktiven thermostaten
     * @return array<string>
     */
    get_active_thermostats () {
        const active = [];
        for(let c = 1; c < 6; c++){
            let key = `sys_controller_${c}_presence`;
            if(this._data.hasOwnProperty(key) && this._data[key] != "1"){
                continue
            }
            for(let i = 1; i < 14; i++){
                let thermo = `C${c}_thermostat_${i}_presence`;
                if(this._data.hasOwnProperty(thermo) && this._data[thermo] == "1"){
                    active.push(`C${c}_T${i}`);
                }
            }
        }
        return active;
    }

    /**
     * @description heizt das Thermostat ?
     * @param thermostat string
     * @return boolean
     */
    is_heating_active (thermostat) {
        let  key = `${thermostat}_stat_cb_actuator`;
        if(this._data.hasOwnProperty(key)){
            return this._data[key] == "1";
        }
        return false;
    }

    intToTemp (temp) {
        //return Math.round((parseInt(temp) -320) / 18.1);
        let t = ((parseInt(temp) -320) / 18.1);
        console.log(t);
        return t.toFixed(1);
    }

    /**
     * @description Temperatur des Thermostat
     * @param thermostat string
     * @return floor
     */
    get_temperature (thermostat) {
        let  key = `${thermostat}_room_temperature`;
        if(this._data.hasOwnProperty(key) && parseInt(this._data[key]) <= this.constants.TOO_HIGH_TEMP_LIMIT){
            //return Math.round((parseInt(this._data[key]) -320) / 18.1);
            return this.intToTemp(this._data[key]);
        }
        return 0;
    }

    /**
     * @description Minimal-Temperatur des Thermostat
     * @param thermostat string
     * @return floor
     */
    get_min_limit (thermostat) {
        let  key = `${thermostat}_minimum_setpoint`;
        if(this._data.hasOwnProperty(key)){
            return this.intToTemp(this._data[key]);
        }
        return 0;
    }

    /**
     * @description Maximal-Temperatur des Thermostat
     * @param thermostat string
     * @return floor
     */
    get_max_limit (thermostat) {
        let  key = `${thermostat}_maximum_setpoint`;
        if(this._data.hasOwnProperty(key)){
            return this.intToTemp(this._data[key]);
        }
        return 0;
    }

    /**
     * @description Luftfeuchtigkeit des Thermostat
     * @param thermostat string
     * @return floor
     */
    get_humidity (thermostat) {
        let  key = `${thermostat}_rh`;
        if(this._data.hasOwnProperty(key) && parseInt(this._data[key]) >= this.constants.TOO_LOW_HUMIDITY_LIMIT){
            return parseInt(this._data[key]);
        }
        return 0;
    }

    /**
     * @description Standort/Raumname des Thermostat
     * @param thermostat string
     * @return string
     */
    get_room_name (thermostat) {
        let  key = `cust_${thermostat}_name`;
        if(this._data.hasOwnProperty(key)){
            return this._data[key];
        }
        return '';
    }

    /**
     * @description Status des Thermostat
     * @param thermostat string
     * @return string
     */
    get_status (thermostat) {
        let  key = `${thermostat}_na_stat_battery_errorme`;
        if(this._data.hasOwnProperty(key) && this._data[key] == "1"){
            return this.constants.STATUS_ERROR_BATTERY;
        }
        key = `${thermostat}_stat_valve_position_err`;
        if(this._data.hasOwnProperty(key) && this._data[key] == "1"){
            return this.constants.STATUS_ERROR_VALVE;
        }

        // var = thermostat[0:3] + 'stat_general_system_alarm'
        // STATUS_ERROR_GENERAL

        key = `${thermostat}_stat_air_sensor_error`;
        if(this._data.hasOwnProperty(key) && this._data[key] == "1"){
            return this.constants.STATUS_ERROR_AIR_SENSOR;
        }
        key = `${thermostat}_stat_external_sensor_err`;
        if(this._data.hasOwnProperty(key) && this._data[key] == "1"){
            return this.constants.STATUS_ERROR_EXT_SENSOR;
        }
        key = `${thermostat}_stat_rh_sensor_error`;
        if(this._data.hasOwnProperty(key) && this._data[key] == "1"){
            return this.constants.STATUS_ERROR_RH_SENSOR;
        }
        key = `${thermostat}_stat_rf_error`;
        if(this._data.hasOwnProperty(key) && this._data[key] == "1"){
            return this.constants.STATUS_ERROR_RF_SENSOR;
        }
        key = `${thermostat}_stat_tamper_alarm`;
        if(this._data.hasOwnProperty(key) && this._data[key] == "1"){
            return this.constants.STATUS_ERROR_TAMPER;
        }
        key = `${thermostat}_room_temperature`;
        if(this._data.hasOwnProperty(key) && parseInt(this._data[key]) > this.constants.TOO_HIGH_TEMP_LIMIT){
            return this.constants.STATUS_ERROR_TOO_HIGH_TEMP;
        }
        return this.constants.STATUS_OK;
    }

    /**
     * @description Schreibt Thermostat Daten in iobroker Datenpunkte
     * @param active_thermostat array<string>
     */
    write_to_iobroker (active_thermostat) {
        for(let i = 0; i < active_thermostat.length; i++){

            let key = `${this.data_path}.thermostate.${active_thermostat[i]}`;
            let temperature = this.get_temperature(active_thermostat[i]);
            let min_limit = this.get_min_limit(active_thermostat[i]);
            let max_limit = this.get_max_limit(active_thermostat[i]);
            let humidity = this.get_humidity(active_thermostat[i]);
            let room = this.get_room_name(active_thermostat[i]);
            let status = this.get_status(active_thermostat[i]);

            if (!getObject(`${key}.temperature`)){
                this.erstelleDatenpunkt(`${key}.temperature`, {type: 'string', read: true, write: true, def: ''}, temperature);
                this.erstelleDatenpunkt(`${key}.min_temp`, {type: 'string', read: true, write: true, def: ''}, min_limit);
                this.erstelleDatenpunkt(`${key}.max_temp`, {type: 'string', read: true, write: true, def: ''}, max_limit);
                this.erstelleDatenpunkt(`${key}.humidity`, {type: 'number', read: true, write: true, def: ''}, humidity);
                this.erstelleDatenpunkt(`${key}.room`, {type: 'string', read: true, write: true, def: ''}, room);
                this.erstelleDatenpunkt(`${key}.status`, {type: 'string', read: true, write: true, def: ''}, status);
            }
            else{
                setState(`${key}.temperature`,temperature);
                setState(`${key}.min_temp`,min_limit);
                setState(`${key}.max_temp`,max_limit);
                setState(`${key}.humidity`,humidity);
                setState(`${key}.room`,room);
                setState(`${key}.status`,status);
            }
        }
    }

}

// um alle Datenpunkte bei Script-Start anzulegen
(async function(){
        const heizung = new uponor('<IP-ADRESS-SMATRIX-R-208>');
        await heizung.getData();
        const active = heizung.get_active_thermostats();
        heizung.write_to_iobroker(active);

})()

// Aktualisierung der Datenpunkte
schedule('*/59 * * * *', function(){
    (async function(){
        const heizung = new uponor('<IP-ADRESS-SMATRIX-R-208>');
        await heizung.getData();
        const active = heizung.get_active_thermostats();
        heizung.write_to_iobroker(active);

    })()
});
DutchmanNL commented 4 years ago

es betrifft in der basis ne reguliere JSON abfrage, die kan man sehr leicht (sehe dicovergy, WLED, TADO usw) in einem adapter unterbringen.

Weiter docu zur hardware was man stehen kan waehre darin hilfreich, zum bauen braucht man die device oder nen Zugang zum testen (beides habe ich z.b. nicht)

hanny1979 commented 3 years ago

Hallo zusammen Ich hätte das Equipment vollständig da. Aber zu wenig Ahnung um einen Adapter zu schreiben. Falls jemand der es kann möchte bin ich bereit mit zu helfen.