Подключение к эл.котлу


#1

Всем привет, имеем WirenBoard5, датчик температуры, и котел Protherm 9, как мне кажется что они должны подключаться к друг другу по сухим контактам, и WirenBoard теоретически должен начать им управлять по неким сценариям. Вопрос, готов ли кто нибудь из форумчан взяться за написание сценариев для котла, и какова цена вопроса.


#2

Вы сценарий работы опишите, чтобы понятнее было, что вам нужно. Вот мой скрипт, но в нем все очень хитро и сложно: управление насосами, возможность греть каждый этаж дома как по-отдельности (опираясь на датчики на каждом из этаже), так и все этажи вместе (по датчику на первом этаже).

    defineAlias('Pump_1', 'wb-mr14_32/K2');
    defineAlias('Pump_2', 'wb-mr14_32/K1');
    defineAlias('Pump_Basement', 'wb-mr14_32/K3');
    defineAlias('Pump_Boiler', 'wb-mr14_32/K4');
    defineAlias('Boiler', 'wb-mr14_32/K8');

    var TOUT_THRESHOULD = 30;
    var TEMP_THRESHOULD = 24;
    var HYSTERESIS_UP = 0;
    var HYSTERESIS_DOWN = 0.3;

    var GLOBALMAP = {
        'Floor 1 Temperature': {
            relay: 'K2',
            thermo: 'Floor_1'
        },
        'Floor 2 Temperature': {
            relay: 'K1',
            thermo: 'Floor_2'
        },
        'Basement Temperature': {
            relay: 'K3',
            thermo: 'Basement'
        }
    };

    defineVirtualDevice('thermostat', {
        title: 'Thermostat', //
        cells: {
            'Floor_1' : {
                type : 'range',
                value : 24,
                max : 30
            },
            'Floor 1 Temperature': {
                type: 'temperature',
                value: ''
            },
            'Floor_2' : {
                type : 'range',
                value : 20,
                max : 30,
            },
            'Floor 2 Temperature': {
                type: 'temperature',
                value: ''
            },
            'Basement' : {
                type : 'range',
                value : 22,
                max : 30,
            },
            'Basement Temperature': {
                type: 'temperature',
                value: ''
            },
            'Garret Temperature': {
                type: 'temperature',
                value: ''
            },
            'Outside Temperature': {
                type: 'temperature',
                value: ''
            },
            'Boiler Out Temperature': {
                type: 'temperature',
                value: ''
            },
            'Bath House Temperature': {
                type: 'temperature',
                value: ''
            },      
            'Pressure': {
                type: 'text',
                value: ''
            },      
            'Enabled': {
                type: 'switch',
                value: true
            },
            'Simple': {
                type: 'switch',
                value: true
            }
        }
    });

    defineRule('dl_manage_pumps_by_temp', {
    //  whenChanged: ['thermostat/Floor 1', 'thermostat/Floor 2', 'thermostat/Basement'], // debug
        whenChanged: ['thermostat/Floor 1 Temperature', 'thermostat/Floor 2 Temperature', 'thermostat/Basement Temperature'], // production
        then: function (newValue, devName, cellName) {
      
            if (!dev['thermostat']['Enabled']) {
                return;
            }

            if (dev['thermostat']['Simple']) {
                managePumpSimple();
            } else {
                var thermo = dev['thermostat'][GLOBALMAP[cellName]['thermo']]; // production
                managePumps(newValue, thermo, cellName);        
            }
        }
    });

    defineRule('dl_manage_pumps_by_thermo', {
        whenChanged: ['thermostat/Floor_1', 'thermostat/Floor_2', 'thermostat/Basement'],
        then: function (newValue, devName, cellName) {
     
            if (!dev['thermostat']['Enabled']) {
                return;
            }

            var map = {
                'Floor_1': 'Floor 1 Temperature',
                'Floor_2': 'Floor 2 Temperature',
                'Basement': 'Basement Temperature'
            };

            if (dev['thermostat']['Simple']) {        
                if (cellName == 'Floor_1') {
                    managePumpSimple();
                }            
            } else {
                var temp = dev['thermostat'][map[cellName]];
                managePumps(temp, newValue, map[cellName]);
            }
        }
    });

    defineRule('dl_set_temperature', {
        whenChanged: [
          'wb-w1/28-0014175e3eff',
          'wb-w1/28-00141743b2ff',
          'wb-w1/28-00141737fdff',
          'wb-w1/28-001416f342ff',
          'wb-w1/28-001417357bff',
          'wb-w1/28-001416e9e7ff',
          'wb-w1/28-0014175dd1ff'
        ],
        then: function (newValue, devName, cellName) {
            var map = {
                '28-0014175e3eff': 'Floor 1 Temperature',
                '28-00141743b2ff': 'Floor 2 Temperature',
                '28-00141737fdff': 'Basement Temperature',
                '28-001416f342ff': 'Garret Temperature',
                '28-001417357bff': 'Outside Temperature',
                '28-001416e9e7ff': 'Boiler Out Temperature',
                '28-0014175dd1ff': 'Bath House Temperature'          
            };
            dev.thermostat[map[cellName]] = newValue;
        }
    });

    defineRule('dl_set_pressure', {
        whenChanged: [
    		'wb-adc/A2'
        ],
        then: function (newValue, devName, cellName) {
          	var coefficient = 0.8;
          	var shift = 0.5;
            dev.thermostat['Pressure'] = (coefficient * newValue + shift).toFixed(1);
        }
    });

    defineRule('dl_check_boiler_pump', {
        when: function() {
            return Boiler == 1 && Pump_Boiler == 0;
        },
        then: function (newValue, devName, cellName) {
            Pump_Boiler = 1;
        }
    });


    defineRule('dl_low_pressure', {
        whenChanged: 'thermostat/Pressure',
        then: function (newValue, devName, cellName) {
            if (!dev['thermostat']['Enabled']) {
                return;
            }
    		var low_threshould = 1;
          	if (newValue < low_threshould) {
    			dev['thermostat']['Enabled'] = 0;
            }
        }
    });

    defineRule('dl_boiler_in_temperature', {
    //  whenChanged: 'tout/temp', // debug
        whenChanged: 'thermostat/Boiler Out Temperature', // production
        then: function (newValue, devName, cellName) {
            if (!dev['thermostat']['Enabled']) {
                return;
            }
            if ( Boiler == 0 && newValue < TOUT_THRESHOULD ) {
                Pump_1 = 0;
                Pump_2 = 0;      
                Pump_Basement = 0;      
                Pump_Boiler = 0;
            }
        }
    });

    defineRule("dl_heater_shutdown", {
      whenChanged: "thermostat/Enabled",
      then: function (newValue, devName, cellName) {
    	if (newValue == false) {
          	switchBoiler(false);
          	Pump_1 = 0;
          	Pump_2 = 0;
            Pump_Basement = 0;
          	Pump_Boiler = 0;
        }
      }
    });

    function pumpsEnabled()
    {
        var c = 0;

        if (Pump_1 == 1) {
            c++;
        }
        if (Pump_2 == 1) {
            c++;
        }
        if (Pump_Basement == 1) {
            c++;
        }
        return c;
    }

    function switchBoiler(enable)
    {
        if (enable && Boiler == 0) {
            Boiler = 1;
            Pump_Boiler = 1;
        } else if (!enable && Boiler == 1) {
            Boiler = 0;    
        }
    }

    function pumpValueByTemp(cellName, value)
    {
        var relay = GLOBALMAP[cellName]['relay'];

        if (value === undefined) {
            return dev['wb-mr14_32'][relay];
        } else {
            dev['wb-mr14_32'][relay] = value;
        }
    }

    function managePumps(temp, thermo, tempCell)
    {    
        if (temp < thermo - HYSTERESIS_DOWN && pumpValueByTemp(tempCell) == 0) {
            pumpValueByTemp(tempCell, 1);
            switchBoiler(true);
        } else if (temp > thermo + HYSTERESIS_UP && pumpValueByTemp(tempCell) == 1) {
            if (pumpsEnabled() == 1) {
                switchBoiler(false);
            } else {
                pumpValueByTemp(tempCell, 0);
            }
        }
    }

    function managePumpSimple()
    {
        var tempCell = 'Floor 1 Temperature';
        var temp = dev['thermostat'][tempCell];
        var thermo = dev['thermostat']['Floor_1'];
        
        if (temp < thermo - HYSTERESIS_DOWN && pumpValueByTemp(tempCell) == 0) {
            pumpValueByTemp(tempCell, 1);
            pumpValueByTemp('Floor 2 Temperature', 1);
            pumpValueByTemp('Basement Temperature', 1);
            switchBoiler(true);
        } else if (temp > thermo + HYSTERESIS_UP && pumpValueByTemp(tempCell) == 1) {
            switchBoiler(false);
        }  
    }

#3

Всем еще раз привет, может кто поделиться своим опытом управления электрическим котлом?
Первое, что хотелось бы понять по какому интерфейсу они вообще между собой должны связаться? как физически их связать?
Задача, поддерживать определенную температуру, в помещение на основании датчика температуры подключенному к wirenboard.


#4

На любом котле есть колодка для подключения внешнего термостата. Там 2 контакта, по умолчанию стоит перемычка (замкнуто). Убираете перемычку, подключаете управляемое реле и управляете из правил.


#5

Да, самый простой вариант - вместо термостата.

Вообще у разных котлов есть разные интерфейсы, по которым они умеют общаться с внешним миром.

Например, OpenTherm, используемый в Baxi народ вроде освоил.


#6

С колодокой теперь понятно. Тоесть эти два провода я подключаю, wirenboard, там же вроде есть выход с реле? Может у кого есть пример правил, по которым это реле замыкает Котел. И на самом котле, что должно быть выставлено, температура на максимум или что?


#7

У WB5 нет выхода с реле. Нужен релейный модуль.

Саму температуру выставляете с некоторым запасом и, вероятно, все равно придется при сильных перепадах менять температуру котла.


#8

Спасибо. А какое тогда нужно реле?


#9

Может кто-то здесь на форуме за вознаграждение написать правила для этого реле?


#10

Например, такое. Если нужно просто одно реле.
https://contactless.ru/wiki/index.php/Модуль_релейных_выходов_WBE-DO-R6C-1


#11
Может кто-то здесь на форуме за вознаграждение написать правила для этого реле?

Я могу выложить свой скрипт для теплого пола. Там все максимально тупо. Думаю, что для котла разница только в константах, если нет планов замутить ПИД-регулятор.


#12

Есть пример реализации?

Я видел только для немецких котлов с eBUS - https://docs.openhab.org/addons/bindings/ebus1/readme.html


#13

Мне вроде попадались проекты самопальной реализации OpenTherm с подключением к Baxi. Судя по тому, что производитель Зонта смог управлять котлом по OpenTherm - это явно возможно.


#15

Если не сложно, киньте пожалуйста получившийся скрипт.


#16
function floorHeater(control, name, temperature_control, relay_control) {
  defineVirtualDevice(control, {
      title: name,
      cells: {
        on: {
            type: "switch",
            value: false,
            readonly: false
        },
        heater: {
            type: "switch",
            value: false,
            readonly: true
        },
        target: {
            type: "range",
            value: 32,
            readonly: false
        },
        temperature: {
            type: "temperature",
            value: false
        }
      }
  });

  defineRule(control+"_temperature", {
    whenChanged: temperature_control,
    then: function (newValue, devName, cellName)  {
      dev[control]["temperature"] = newValue;
    
      if (newValue>38){
        dev[control]['heater'] = 0; 
        dev[control]['on'] = 0; 
        dev['wb-mr11_196'][relay_control] = 0;
      } else if (dev[control]["on"]) {
	    log(temperature_control+"="+newValue+" target="+dev[control]["target"]);
        if (newValue> dev[control]["target"] && dev[control]['heater']) {
          dev[control]['heater'] = 0;
        } else if (newValue<dev[control]["target"]-1 && !dev[control]['heater']) {
          dev[control]['heater'] = 1;
        }
      } else if (dev[control]['heater']) {
        dev[control]['heater'] = 0;
      }
    }
  });

  defineRule(control+"_heater", {
    whenChanged: control+"/heater",
    then: function (newValue, devName, cellName)  {
      dev['wb-mr11_196'][relay_control] = newValue;
    }
  });

  defineRule(control+"_on", {
    whenChanged: control+"/on",
    then: function (newValue, devName, cellName)  {
      log(control+"_on ->"+newValue)
      if (newValue)
      {
        if (dev[control]["temperature"]<dev[control]["target"]-1){
          dev[control]['heater'] = 0;
		}          
      } else {
      	dev[control]['heater'] = 0;
      }
    }
  });
  
  defineRule(control+"_off", 
  {
    when: cron("0 30 23 * *"),
    then: function () 
    {
        dev[control]['heater'] = 0; 
        dev[control]['on'] = 0; 
        dev['wb-mr11_196'][relay_control] = 0;
    }
  });
};


floorHeater("floor_bathroom", "Теплый пол, ванна",   "wb-w1/28-000004673645", "K9");


#17

90% логики внутри

Идея тупая:

  • если нагреватель включен и температура выше порога - выключаем
  • если нагреватель выключен и температура ниже порога - включаем

Внутри функции только из-за того, что у меня несколько теплых полов несколько. Т.к. котел у вас скорее всего один - можно сразу все декларировать безо всякой функции. Ну и я бы добавил датчик температуры теплоносителя, хотя бы просто “понаблюдать”

Ну и крон вам скорее всего не нужен, у меня он сделан для того, чтобы ночью пол гарантированно выключился.


#18

Понял, спасибо, буду заказывать реле и пробовать.


Яндекс.Метрика