Перейти до публікації
Пошук в
  • Додатково...
Шукати результати, які містять...
Шукати результати в...

Практическая автоматизация дома на базе openhab

standov

Рекомендовані повідомлення

Про свести я надеюсь напишу тоже сюда пост, если коротко - да надо ) зато после этого все вообще получается по другому и удобнее.

Пс с новым годом )

Посилання на коментар
Поділитися на інших сайтах

  • 2 тижні потому...

хорошая тема, много инфы, буду еще детальней читать когда начну собирать умный дом 😃

сейчас собираюсь покупать некоторые устройства (уже есть нескольо сяоми устройств), вот думаю какой платформы брать следующие, желательно на али.
для начала буду с родным приложением использовать, а в будущем планирую на OH перейти

@standov и такой вопрос, можно ли подключить Tuya устройства (zigbee3) к OH ? в частности интересует датчики температуры, и диммер 0-10В aliexpress.ru/item/10000015907761.html

Посилання на коментар
Поділитися на інших сайтах

1 час назад, metall_version сказал:

хорошая тема, много инфы, буду еще детальней читать когда начну собирать умный дом 😃

сейчас собираюсь покупать некоторые устройства (уже есть нескольо сяоми устройств), вот думаю какой платформы брать следующие, желательно на али.
для начала буду с родным приложением использовать, а в будущем планирую на OH перейти

@standov и такой вопрос, можно ли подключить Tuya устройства (zigbee3) к OH ? в частности интересует датчики температуры, и диммер 0-10В aliexpress.ru/item/10000015907761.html

я конкретно современные Tuya не пробовал (ксяомишные из первых только юзал) но в случае с зигби все достаточно просто, если использовать zigbee2mqtt то там есть список гарантированно-поддерживаемых устройствwww.zigbee2mqtt.io/supported-devices/. Если устройство тут есть то вероятность того что родной бондинг опенхаба тоже его найдет достаточно высокая, НО я предпочитаю все-же zigbee2mqtt а его уже через mqtt заводить в опенхаб.
 

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

  • Лайк 1
Посилання на коментар
Поділитися на інших сайтах

  • 4 тижні потому...

Новый пост в серии, автоматизация увлажнения.
Задача - "умное" управление увлажнителями по помещениям с минимальным участием человека и максимальной гибкостью

Вводные

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

- второй "модный, молодежный" ксяомишный увлажнитель-мойка который с одной стороны умеет в полную автоматизации, с другой имеет один странный и загадочный баг, у него целевая уставка которую он пытается  поддерживать в авторежиме космические 70%, и никак не меняется.

Оба увлажнителя с одной стороны работают ок, с другой оба в авторежиме работают на *отстань*.

В обоих помещениях, где у установлены эти увлажнители, также настроен мониторинг влажности с помощью домашней метеостанции Netatmo, для данного поста считаем что это уже есть и работает.

По опыту применения увлажнителей пришел к тому что нужно иметь возможность как установить общую целевую влажность в доме так и по отдельным помещениям, это в первую очередь актуально для мелких детей у которых зимой при повышении влажности заметно легче решается вопрос с соплями.

Поскольку у меня мелкий спит в кабинете то там дополнительно настроена своя целевая влажность.

Подготовительные работы

Как я писал ранее, сторонник того что любая автоматизация в доме должна быть легко-отключаемой, мы не можем позволить скайнету захватывать наши дома!

Переключатель автоматизации увлажнения

Switch Home_HumidityAutomation "Керування зволожувачами" <hvac_humidity> (Home, gAutomation) ["Humidity", "Switch"] {description="Автоматичне керування наявними зволожувачами по окремим приміщенням"}

Далее добавляю в дом элементы для работы с общедомовой целевой влажностью

Group Home_Humidity "Вологість в будинку" <pipe> (Home)
    String    Home_Humidity_Mode           "Режим підтримки вологості в будинку [%s]"             <hvac_humidity>           (Home_Humidity) {stateDescription=""[
        options="MANUAL, AUTO, ECO"
    ]}           
    
    Number:Dimensionless      Home_Humidity_SetpointHumidity        "Бажана вологість у будинку [%.1f %unit%]"           <hvac_setpoint>        (Home_Humidity)        ["Setpoint", "Humidity"] {
        listWidget="oh-stepper-item"[
            min=10,
            max=70,
            step=5
        ]
    }

В интерфейсе управление включением автоматизации выглядит так

image.png.9ba788bb357ef7d1cf8c40246c380d0b.png

Целевая влажность общего дома управляется кастомным виджетом

image.thumb.png.f06f307de9c6a4a7a86abba8211408bd.png

Управление и мониторинг влажности в кабинете, где пока спит мелкий, дополнительно имеет свое управление влажностью

image.png.30b042e0fc55702973788e1e78162f9b.png

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

Group GF_Office_Humidifier "Зволожувач кабінету" <hvac_humidity> (GF_Office, gHVAC) ["HVAC"]
    // режим работы увлажнителя, должны быть опции ON и OFF, остальные по вкусу и в зависимости от возможностей железки
    String          GF_Office_Humidifier_Mode              "Режим зволожувача кабінету"            <hvac_humidity>              (GF_Office_Humidifier)    ["Switch", "Humidity"] {stateDescription=""[
        options="ON, AUTO, OFF"
    ]}

    // уровень воды в баке 0-100
    Number:Dimensionless        GF_Office_Humidifier_Waterlevel           "Рівень води в зволожувачі кабінету [%.1f %%]"             <hvac_humidity>           (GF_Office_Humidifier)  ["Measurement", "Water"] 

    // желаемая влажность в конкретном помещении, в кабинете у меня пока спит мелкий потому именно тут свой контроль есть
    Number:Dimensionless        GF_Office_Humidifier_SetpointHumidity           "Бажана вологість у кабінеті [%.1f %unit%]"             <hvac_humidity>           (GF_Office_Humidifier) ["Setpoint", "Humidity"] {
        listWidget="oh-stepper-item"[
            min=10,
            max=70,
            step=5
        ]
    }

    // мощность увлажнения, LOW, MEDIUM, HIGH
    String    GF_Office_Humidifier_Performance           "Потужність зволоження у кабінені [%.1f]"             <hvac_humidity>           (GF_Office_Humidifier) ["Control", "Humidity"]  {stateDescription=""[
        options="LOW, MEDIUM, HIGH"
    ]}


Проксирование ксяомишного увлажнителя в увлажнитель кабинета:

let proxy = require('openhab-proxy-pattern');

proxy.bind('GF_Office_Humidifier_Mode', 'MIIO_HUMIDIFIER_361899525_POWER')
    .update(function(value) {
        if (value === 'ON') {
            return 'AUTO';
        } else {
            return 'OFF';
        }
    })
    .forward(function(value) {
        if (value === 'AUTO') {
            return 'ON';
        } else if (value === 'ON') {
            return 'ON';
        } else {
            return 'OFF';
        } 
    });

proxy.bind('GF_Office_Humidifier_Waterlevel', 'MIIO_HUMIDIFIER_361899525_WATERLEVEL')
    .update()

proxy.bind('GF_Office_Humidifier_Performance', 'MIIO_HUMIDIFIER_361899525_MODE')
    .forward(function(value) {
        if (value == 'HIGH' ) return 3;
        else if (value == 'MEDIUM' ) return 2;
        else return 1;
    })
    .update(function(value) {
        if (value == 3) return 'HIGH';
        else if (value == 2) return 'MEDIUM';
        else if (value == 1) return 'LOW';

        return undefined;
    })


А теперь самая магия с пояснениями в коде

Humidification.js:

// правило для расчета целевой влажности глобальной
// в авто-режиме когда все дома зимой 30%, летом 40%
// если никого нет дома или установлен еко-режим то 25%
rules.JSRule({
    name: 'Home humidifier setpoint',
    description: "",
    triggers: [
        triggers.GenericCronTrigger("0 0/5 * * * ?"), // every 5 minutes
        triggers.ItemStateChangeTrigger('Home_Humidity_Mode')
    ],
    execute: e => {
        const d = new Date();
        const is_away = (items.getItem('Home_ModeAway').state == 'OPEN');
        const is_winter = (d.getMonth() < 3) || (d.getMonth() > 9); // nov - mar
         

        if (items.getItem('Home_Humidity_Mode').state === 'AUTO') {
            if (is_away) {
                items.getItem('Home_Humidity_SetpointHumidity').sendCommand(25); // 
            } else {
                items.getItem('Home_Humidity_SetpointHumidity').sendCommand(is_winter ? 30 : 40);
            }
        } else if (items.getItem('Home_Humidity_Mode').state === 'ECO') {
            items.getItem('Home_Humidity_SetpointHumidity').sendCommand(25);
        }
    }
});

// описательная структура связей увлажнитель- комнаты
// level[обязательное] - элемент указывающий текущую влажность в помещении
// mode[обязательное] - элемент который управляет увлажнителем, должет уметь минимум ON и OFF
// setpoint - элемент который устанавливает целевую температуру помещении, если не указан то используется общедомовой
// waterlevel - элемент контролирующий заполнение увлажнтеля водой, пока не используется но по плану уведомление "закончилась вода в ..."
// performance - элемент контролирующий мощность увлажнителя, если используется должен уметь LOW, MEDIUM, HIGH
const humidifiers = {
    GF_GuestRoom_Humidity: {
        level: 'GF_GuestRoom_Humidity',
        mode: 'GF_GuestRoom_Humidifier_Mode',
    }, 
    GF_Office_Humidifier: {
        level: 'GF_Office_Humidity',
        setpoint: 'GF_Office_Humidifier_SetpointHumidity',
        mode: 'GF_Office_Humidifier_Mode',
        waterlevel: 'GF_Office_Humidifier_Waterlevel',
        performance: 'GF_Office_Humidifier_Performance'
    }
};

// для каждой связки (комнаты) делаем правило которое вызывается при изменении любых элементов из связки
// а также режима дома (away, vacation, daytime)
for (const group in humidifiers) {

    let data = humidifiers[group];

    let t = [
        triggers.ItemStateChangeTrigger('Home_DayTime'),
        triggers.ItemStateChangeTrigger('Home_ModeAway'),
        triggers.ItemStateChangeTrigger('Home_HumidityAutomation'),
        triggers.ItemStateChangeTrigger(data.level),
        triggers.ItemStateChangeTrigger(data.mode)
    ];

    if ('waterlevel' in data) {
        t.push(triggers.ItemStateChangeTrigger(data.waterlevel));
    }
    if ('performance' in data) {
        t.push(triggers.ItemStateChangeTrigger(data.performance));
    }
    if ('setpoint' in data) {
        t.push(triggers.ItemStateChangeTrigger(data.setpoint));
    } else {
        t.push(triggers.ItemStateChangeTrigger('Home_Humidity_SetpointHumidity'));
    }
    

    rules.JSRule({
        name: group,
        description: "Humidification",
        triggers: t,
        execute: e => {
            const is_automated = (items.getItem('Home_HumidityAutomation').state === 'ON');
            const is_away = (items.getItem('Home_ModeAway').state == 'OPEN');
            const is_vacation = (items.getItem('Home_ModeVacation').state == 'ON');
            const is_bedtime = (items.getItem('Home_DayTime').state == 'BED');


            if (is_automated) { // если автоматизация увлажнения включена глобальной галочкой
                if (is_away && is_vacation) { 
                    // если режим отпуска то включаем увлажнение на максималку независимо ни от чего
                    // задача - опустошить контейнер шоб не заванивалось
                    console.log('turn ON to max during vacation to dry and off');

                    items.getItem(data.mode).sendCommand('ON');
                    if ('performance' in data) {
                        items.getItem(data.performance).sendCommand('HIGH');
                    }
                } else {
                    // auto
                    let current = parseFloat(items.getItem(data.level).state);
                    let setpoint = parseFloat(items.getItem('Home_Humidity_SetpointHumidity').state);

                    if ('setpoint' in data) {

                        setpoint = parseFloat(items.getItem(data.setpoint).state);
                        // если целевой item комнатный то в режиме когда нет никого дома понижаем его для экономии
                        // общедомовой item уже учитывает эту поправку
                        if (is_away) setpoint = setpoint / 1.3
                    }

                    // контролируем уставку и текущую влажность помещения с гистерезисом 
                    if (current < setpoint / 1.2) {
                        // если увлажнитель поддерживает управление мощностью
                        // то когда все спят ставим в минимальный режим шоб не шумело
                        if ('performance' in data) {
                            items.getItem(data.performance).sendCommand((is_bedtime) ? 'LOW' : 'MEDIUM');
                        }
                        // включаем
                        items.getItem(data.mode).sendCommand('ON');
                    } else if (current > setpoint) { {
                        // влажность и так высокая, выключаем
                        items.getItem(data.mode).sendCommand('OFF');
                    }
                }
            } else {
                console.log('Humidification IS NOT AUTOMATED!');
            }          
        }
      });

}

 

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

Змінено користувачем standov
  • Лайк 2
  • Дякую 1
Посилання на коментар
Поділитися на інших сайтах

мне кажется, целевая 30% зимой - это мало. Стараюсь 40 держать в спальнях, в среднем получается 35% по дому.

Посилання на коментар
Поділитися на інших сайтах

6 минут назад, shneider_vova сказал:

мне кажется, целевая 30% зимой - это мало. Стараюсь 40 держать в спальнях, в среднем получается 35% по дому.

возможно, как будет больше помещений подкорректирую. сейчас у меня на общей 30 а в комнате где мелкий 35 и оно на текущей вентиляции вытягивает, 40 сейчас не вытянет, бо вентиляция работает в кривом (фактически избыточном) режиме.

АПД ну вернее вот прямо сейчас думаю вытянет но когда более зимняя погода то нет, а 30-35 все-же вполне вариант нормы, для зимы так точно

Змінено користувачем standov
Посилання на коментар
Поділитися на інших сайтах

1 час назад, standov сказал:

возможно, как будет больше помещений подкорректирую. сейчас у меня на общей 30 а в комнате где мелкий 35 и оно на текущей вентиляции вытягивает, 40 сейчас не вытянет, бо вентиляция работает в кривом (фактически избыточном) режиме.

АПД ну вернее вот прямо сейчас думаю вытянет но когда более зимняя погода то нет, а 30-35 все-же вполне вариант нормы, для зимы так точно

а сколько испаряете за сутки, что не вытянет? при -10, да, и у меня 40 не будет никак

Посилання на коментар
Поділитися на інших сайтах

3 минуты назад, shneider_vova сказал:

а сколько испаряете за сутки, что не вытянет? при -10, да, и у меня 40 не будет никак

в комнате где 35 держу испаряется 4 литровый бак часов за 12-15, там где 30 там сложнее сказать - не засекал 

  • Лайк 1
Посилання на коментар
Поділитися на інших сайтах

1 минуту назад, standov сказал:

в комнате где 35 держу испаряется 4 литровый бак часов за 12-15, там где 30 там сложнее сказать - не засекал 

а воздухообмен там сколько? вроде действительно выглядит избыточно.

 

 

Посилання на коментар
Поділитися на інших сайтах

Только что, shneider_vova сказал:

а воздухообмен там сколько? вроде действительно выглядит избыточно.

 

 

воздухообмен по моим прикидкам около 80-100 кубов в этой комнате

  • Лайк 1
Посилання на коментар
Поділитися на інших сайтах

Почему-то забыл график результирующий, как выглядит поддержание влажности в реальности. Тут важно понимать что влажность снимается не датчиком увлажнителя (который привирает из-за близкого соседства) а датчиком именно комнатным, отдельным в другом месте и при этом активно работает принудительная вентиляция

image.thumb.png.5f146569e4d6ccba39a4622e9aefbe81.png

  • Лайк 2
Посилання на коментар
Поділитися на інших сайтах

Очень интересная тема для чтения. Предстоит нечто подобное, но в будущем.
В общем - подпишусь.

Посилання на коментар
Поділитися на інших сайтах

Практически окончательно решил переместить все уведомления в телеграм-бот, для удобной работы в JS написал простенький враппер

www.npmjs.com/package/openhab-telegram (примеры в README)

Позволяет как отправлять сообщения, так и делать диалоги (в тч вложенные) и команды для бота, оказалось удивительно-удобно

const telegram = require('openhab-telegram');

const bot = telegram.bot("telegram:telegramBot:*****");

bot.onCommand('info', b => {
    let message = "💧\n";
    for (const group in humidifiers) {

        let data = humidifiers[group];


        //message += "" + items.getItem(data.level).label + ' - <b>' + items.getItem(data.level).state + "</b>\n";
        if ('waterlevel' in data) {
            message += "" + items.getItem(data.waterlevel).label + ' - <b>' + items.getItem(data.waterlevel).state + "</b>\n";
        }
    }

    return message;
});

 

if (items.getItem(data.mode).sendCommandIfDifferent('ON')) {
	if ('waterlevel' in data) {

		let level = parseInt(items.getItem(data.waterlevel).state);
		if (level < 10) {
			bot.alert(items.getItem(data.waterlevel).label + ' - %d', level);
		}
	}
}

image.png.ec3ab753a94c2356fa8d84c46a664a14.png

Змінено користувачем standov
Посилання на коментар
Поділитися на інших сайтах

1 час назад, outdoor24 сказал:

@standov, підкажіть будь ласка, де ви shelly брали - в когось з місцевих чи з алі?

в офіційному шопі shop.shelly.cloud/

  • Лайк 1
Посилання на коментар
Поділитися на інших сайтах

  • 7 місяців потому...

Із лютого всі ми стали трошки іншими, але я абсолютно впевнений - для досягнення результату, як глобального так і локального всі мають робити те шо вміють та не впадати у відчай, я буду потроху відроджувати тему та свій медіум.

Цього разу хочу розповісти про штуку, яку ніде більше не бачив і яку придумав та реалізував сам. Теза, якою можна охарактеризувати все подальше -  контроль над автоматизацією.

Як я писав раніше - я вважаю шо вся магія автоматизації має бути легко відключаєма, бо завжди може виникнути ситуація за якої шось десь пішло не так і ваш будинок "зійшов з глузду". Сценарій коли скайнет  захоче вам врубити опалення на всі гроші бо якийсь датчик помер чи банально якась помилка в алгоритмах - досить реалістична і станеться не раз і не два. Так, безумовно завжди можна вимкнути залізку з опенхабом із розетки, але в цьому випадку ви вимкнете і всю іншу логіку, яка може працювати без проблем роками, да і взагалі це не шлях самурая.

В якийсь момент я вирішив шо проблему контролю над автоматизацією треба робити системно і максимально просто, щоби сама логіка контролю не створювала проблем.

Вимоги яки сформулював:

  1. Механізм має бути простим та прозорим
  2. Він має максимально-просто натягуватися як на існуючий так і на майбутній функционал
  3. Має мати максимально-просте керування

Вирішив шо максимально просте що можна придумати це вимикач "робити магію / не робити магію", оскільки магії в автоматизації багато то перемикачів має бути декілька, на кожну ділянку автоматизації, далі ці вимикачі можна зібрати на одну сторінку інтерфейсу де будуть тільки вони, що максимально спростить маніпуляції.

Якщо ці всі "перемикачі" забрати в одну вертикальну группу то можна їх автоматично додавати на сторінку без додаткових рухів. Це все довгий час так і існувало, але згодом я в якійсь програмі смартхоуму наткнувся на дуже зручну штуку - щось вимикати можна не на постійно а на якийсь проміжок часу, щоб згодом воно само увімкнулося без участі користувача. Мені це так сподобалося шо я вирішив додати це і собі, зрозуміло шо простими вимикачами це вже не розрулити, але хотілося нічого не переписувати особливо в існуючій автоматизації.

Далі просто, без води, як я це зробив і як воно працює.

Заводимо спеціальну вертикальну не семантичну групу і в цій группі створюємо стільки *стрінгових* айтемів скільки нам треба під керування різніми ділянками автоматизації:

Automation.items

Group gAutomation "Автоматизація [%d]" <status>
  String Automation_Humidification "Керування зволоженням" <hvac_humidity> (Home, gAutomation) ["Humidity", "Switch"] {description="Автоматичне керування наявними зволожувачами по окремим приміщенням"}
  String Automation_EcoMode "Керування енергозбереженням" <ecohouse> (Home, gAutomation) ["Presence", "Switch"] {description="Автоматичне керування енергоспоживанням задля економії"}
  String Automation_HotWaterRecirculation "Автокерування наcосом рециркуляції"  <ecohouse> (Home, gAutomation) ["Water", "Switch"] {description="Автоматичне керування рециркуляцією задля економії"}

Тут з цікавого те шо я для атемів придумав description опцію, яку використаю далі

Сценарій автоматичного перетворення цих *стрінгових* айтемів в спеціальні перемикачі на декілька положень

scriptLoaded = function () {
    // для всіх айтемів в групі навішую автоматично варіанти перемикання, це сам опенхаб показує як перемиках на декілька позицій
    items.getItem('gAutomation').members.forEach(function(item) {

        try {
            metadata.addValue(item.name, 'stateDescription', "", {
                'options': 'ON=Увімкнено,OFF=Вимкнено,1HOFF=Вимкнено на 1 годину, 12HOFF=Вимкнено на 12 годин, 24OFF=Вимкнено на добу'
            });
            metadata.addValue(item.name, 'commandDescription', "", {
                'options': 'ON=Увімкнено,OFF=Вимкнено,1HOFF=Вимкнено на 1 годину, 12HOFF=Вимкнено на 12 годин, 24OFF=Вимкнено на добу'
            });
        } catch (e) {
            // нажаль метод upsert у js бібліотеці 3.4 виявився кривим і доводиться через addValue та try/catch
        }
    });
}

Сценарій який при зміні положення будь якого перемикача зберігає дату зміни, насправді це костиль через те що існуюча бібліотека JS чомусь не дає доступу до дати *зміни* значення (є тільки оновлення, а оновлення може бути і на старе значення)

rules.JSRule({
    name: "Track automation time",
    description: "Set meta auto timer",
    triggers: [triggers.GroupStateChangeTrigger('gAutomation')],
    execute: (event) => {
        let t = time.ZonedDateTime.now().toString();
        items.getItem(event.itemName).upsertMetadataValue('updated', `${t}`);
        items.getItem(event.itemName).upsertMetadataValue('automation', '');
    },
    id: `automation_times`
  });

Сценарій який робить ту саму магію яку я підгледів в якомусь смартхоумі, а саме котролюємо коли треба перемикач повернути в положення "увімкнуто"

rules.JSRule({
    name: "Track automation iterval",
    description: "Set back auto timer",
    triggers: [triggers.GenericCronTrigger("0 0/1 * * * ?")],
    execute: (event) => {
        items.getItem('gAutomation').members.forEach(function(item) {
            let minutes = {
                '1HOFF': 60,
                '12HOFF': 12*60,
                '24OFF': 24*60,
            };

            // раз в хвиилину перевіряємо всі айтеми в групі автоматизації
            // якщо у айтема стен "тимчасовий" і якщо він не мінявся певний час то переводимо в стан ON
			// янакше додатково айтему виставляюмо в мета-дані час в який він теоретично має перемкнутися (лоск)
            if (item.state in minutes) {
                let t = time.ZonedDateTime.now().minusMinutes(minutes[item.state]);
                let elapsed = '';
                
                try {
                    let updated = time.toZDT(item.getMetadataValue('updated'));
                    elapsed = updated.format(time.DateTimeFormatter.ofPattern('H:m'));
                } catch (e) {
                    elapsed = '-';
                }
                if (!item.history.changedSince(t)) {
                    item.postUpdate('ON');
                }
                item.upsertMetadataValue('automation', `${elapsed}`);
            } else {
                item.upsertMetadataValue('automation', '');
            }
        });
    },
    id: `automation_intervals`
  });

Далі як виглядає код сторінки на яку автоматично виводятся всі перемикачі та як ця сторінка виглядає в браузері та телефоні

config:
  label: Автоматизація
  sidebar: true
blocks:
  - component: oh-block
    config:
      style:
        padding: 0
    slots:
      default:
        - component: oh-grid-row
          config: {}
          slots:
            default:
              - component: oh-grid-col
                config:
                  large: "50"
                  xlarge: "50"
                  xsmall: "100"
                slots:
                  default:
                    - component: oh-repeater
                      config:
                        fetchMetadata: description, automation
                        for: item
                        fragment: true
                        groupItem: gAutomation
                        sourceType: itemsInGroup
                      slots:
                        default:
                          - component: f7-card
                            slots:
                              default:
                                - component: f7-card-header
                                  config:
                                    class3:
                                      - no-border
                                    color: red
                                  slots:
                                    default:
                                      - component: Label
                                        config:
                                          text: =loop.item.label
                                      - component: oh-link
                                        config:
                                          action: options
                                          actionItem: =loop.item.name
                                          badge: '=loop.item.metadata ? loop.item.metadata.automation.value : ""'
                                          color: '=(loop.item.state == "ON") ? "green" : "gray"'
                                          item: =loop.item.name
                                          style:
                                            border: 1px solid var(--f7-theme-color)
                                            border-radius: var(--f7-card-border-radius)
                                            padding: 5px 10px
                                          text: =items[loop.item.name].displayState
                                - component: f7-card-content
                                  config:
                                    style3:
                                      min-height: 64px
                                  slots:
                                    default:
                                      - component: oh-icon
                                        config:
                                          icon: =items[loop.item.name].icon
                                          style:
                                            filter: '=(themeOptions.dark == "dark") ? "invert(70%)" : "invert(30%)"'
                                            float: left
                                          width: 48
                                      - component: Label
                                        config:
                                          padding-left: 75px
                                          style:
                                            float3: none
                                          text: '=loop.item.metadata ? loop.item.metadata.description.value : ""'
masonry: []
grid: []
canvas: []

 

image.thumb.png.8dc5fc62a0876142a5428a227e08f116.png

image.thumb.png.0d6b53494e44bad2b9e17a659157e01e.png

Найголовніше, раді чого це все затівалося - як це використовувати в сценаріях:

if (items.getItem('Automation_EcoMode').state == 'ON') {
  // тут будь яка магія, яка може зламатися
} else {
  // нічого не робимо
}

Всім нам перемоги найскорішої із найменшою кількістю жертв. Слава Україні. 

  

Змінено користувачем standov
  • Лайк 3
Посилання на коментар
Поділитися на інших сайтах

Для того щоб автоматично щось повернути до увімкнутого стану якщо було вимкнуто є у айтемов параметр expired. Правда там не можна буде обирати на скільки вимкнути, але як часто це потрібно?

Посилання на коментар
Поділитися на інших сайтах

В 07.10.2022 в 23:45, k-master сказал:

Для того щоб автоматично щось повернути до увімкнутого стану якщо було вимкнуто є у айтемов параметр expired. Правда там не можна буде обирати на скільки вимкнути, але як часто це потрібно?

про це десь було на початку теми, я активно використовую expire але для того шоб розуміти шо шось поламалось, тобто якшо десь залізка перестала слати дані то відповідний айтем скидається в UNDEF а не залишається в останньому стані.
Для бізнес-логіки expire не використовую бо стараюся все тримати в одному місці (сценаріях), але це більше вкусовщина.

UPD. зрозумів про шо ви, це теоретично можна зробити і через expire, але саме в постановці як була задача - це все одно буде динамічне правило на JS і фактично ті-ж яйці в профіль.

Написав огляд-інтеграцію на реле @InSAn в опенхаб. Реле дійсно кльове, буду впроваджувати Використання modbus в openhab 3 на прикладі українського розумного реле ION CS-8 | by Stas Dovgodko | Oct, 2022 | Medium

Змінено користувачем standov
  • Лайк 2
  • Дякую 1
Посилання на коментар
Поділитися на інших сайтах

14 годин тому, standov сказав:

Написав огляд-інтеграцію на реле @InSAn в опенхаб. Реле дійсно кльове, буду впроваджувати Використання modbus в openhab 3 на прикладі українського розумного реле ION CS-8 | by Stas Dovgodko | Oct, 2022 | Medium

Стабільно працює? Я модбас в OH3 використовую тільки для моніторінгу лічильника електроенергії і він постійно відвалюється. Правда так як усе у докерах, то в мене не serial, а модбас через tcp/ip шлюз.

Посилання на коментар
Поділитися на інших сайтах

3 минуты назад, k-master сказал:

Стабільно працює? Я модбас в OH3 використовую тільки для моніторінгу лічильника електроенергії і він постійно відвалюється. Правда так як усе у докерах, то в мене не serial, а модбас через tcp/ip шлюз.

в мене на модбасі вже роки два 2 залізки китайські, жодних нарікань при тому що я забив на термінуючі резистори і лінії метрів по 5 без екрану, але serial так.

  • Лайк 1
Посилання на коментар
Поділитися на інших сайтах

  • 2 місяці потому...
  • 3 тижні потому...

Трошки актуальної автоматизації.
Вводні:
гібридний сонячний інвертор Voltronic Axpert King 2 + батарейка до нього

Проблема:
досить крива родна апа яка шле дані в китайське облако, звідки їх можна подивитися, з того шо мені 100% потрібно то поточний заряд батарейки, бо зараз дуже актуальна інформація, чи не настав час витягати генератор. Апа з одного боку працює, з іншого через раз + дружині користуватися дуже не зручно.

Не дивлячись на те шо інвертор має вайфай на борту, використовує він його, схоже, лише для облака. Бо ніяких відкритих портів не знайшлося, гугл мовчить як партизан. Але в інеті повно інструкцій як зняти з його порта всі необхідні дані, інструкції різної красноокості тому я цього разу вирішив зробити трошки інакше - я купив готове рішення під інвертор, яке крутится на малині і досить виглядає привабливим. А головне має mqtt брокер на борту. Проект тут solar-assistant.io, жодного відношення не маю, пишу про то шо знайшов.

Отже, купив я дистрибутів під малину в них на сайті, прошив малину, втикнув в інвертор через microUsb. Завелося майже одразу, виглядає досить привабливо, але то не наш путь. Включаємо в налаштуваннях mqtt брокер та погнали :)

Things

Bridge mqtt:broker:solar "Solar" @ "MQTT" [ host="192.168.10.60", secure=false, username="путін" password="***ло", retainMessages=false, qos=2, enableDiscovery=false,clientID="openhab34" ]
{
    Thing topic SolarAssistant_Inverter_1 "SolarAssistant Inverter 1"  @ "SolarAssistant"  {
    Channels:
        Type number : grid-voltage "Grid Voltage" [ 
            stateTopic="solar_assistant/inverter_1/grid_voltage/state",
            unit="V"          
        ]
        Type number : grid-power "Grid Power" [ 
            stateTopic="solar_assistant/inverter_1/grid_power/state",
            unit="W"          
        ]
        Type number : battery-voltage "Battery Voltage" [ 
            stateTopic="solar_assistant/inverter_1/battery_voltage/state",
            unit="V"          
        ]
    }

    Thing topic SolarAssistant_Total "SolarAssistant Total"  @ "SolarAssistant"  {
    Channels:
        Type number : battery-soc "Battery SOC" [ 
            stateTopic="solar_assistant/total/battery_state_of_charge/state",
            unit="%"          
        ]
    }
}

"Залізні" Items

Number:Dimensionless SA_TOTAL_BATTERYSOC "Battery [%.0f %]" {channel="mqtt:topic:solar:SolarAssistant_Total:battery-soc", expire="1m"}
Number:ElectricPotential SA_INVERTER1_GRIDVOLTAGE "Grid Voltage [%.0f V]" {channel="mqtt:topic:solar:SolarAssistant_Inverter_1:grid-voltage", expire="1m"}
Number:Power SA_INVERTER1_GRIDPOWER "Grid Power [%.0f W]" {channel="mqtt:topic:solar:SolarAssistant_Inverter_1:grid-power", expire="1m"}
Number:ElectricPotential SA_INVERTER1_BATTERYVOLTAGE "Battery Voltage [%.0f V]" {channel="mqtt:topic:solar:SolarAssistant_Inverter_1:battery-voltage", expire="1m"}

Проксі

Group ElectricityInput "Ввод електрики" <electricity> (Home, gElectricity) ["Equipment"]
    Number:ElectricPotential ElectricityInput_VA "Напруга від міста A [%.0f %unit%]"   <measurement> (ElectricityInput, gElectricityVoltage) ["Measurement", "Voltage"]
    Number:Power ElectricityInput_PA "Споживання від міста A [%.0f W]"   <measurement> (ElectricityInput, gElectricityPower) ["Measurement", "Power"]
    
    
    Group ElectricityInput_Inverter "Інвертер" <solar_energy> (ElectricityInput) ["Inverter"]
        Group ElectricityInput_InverterBattery "Батарея" <battery> (ElectricityInput_Inverter) ["Battery"]
            Number:ElectricPotential InverterBattery_Voltage "Напруга батареї [%.1f %unit%]"   <measurement> (ElectricityInput_InverterBattery) ["Measurement", "Voltage"]
            Number:Dimensionless InverterBattery_SOC "Стан батареї [%.0f %]"   <measurement> (ElectricityInput_InverterBattery) ["Measurement", "Level"]

 

Проксі правила

let proxy = require('openhab-proxy-pattern');

const v = function(value) {
    if (typeof value == 'string') {
        const v = parseInt(value);
        return isNaN(v) ? undefined : `${v} V`;
    } else return 0;
};

const p = function(value) {
    if (typeof value == 'string') {
        const p = parseInt(value);
        return isNaN(p) ? undefined : `${p} W`;
    } else return 0;
};

['A'].forEach(function(phase) 
{
    proxy.bind(`ElectricityInput_V${phase}`, `SA_INVERTER1_GRIDVOLTAGE`, 15).update(v);

    proxy.bind(`ElectricityInput_P${phase}`, `SA_INVERTER1_GRIDPOWER`, 60).update(p);
    //proxy.bind(`ElectricityInput_PF${phase}`, `Shelly_EM3_2_${phase}PF`, 60).update(pf);
});

proxy.bind('InverterBattery_Voltage', 'SA_INVERTER1_BATTERYVOLTAGE', 15).update();
proxy.bind('InverterBattery_SOC', 'SA_TOTAL_BATTERYSOC', 15).update();

Правила для телеграм-бота

const bot = require('openhab-telegram').bot("telegram:telegramBot:dovgodko");
const alerts = require('openhab-alerts');

bot
.onCommand('info', function(t) {  
    return '/energy Енергія' + "\n/forecast Прогноз погоди";
});

bot
.onCommand('energy', function(t) {
    const battery = items.getItem('InverterBattery_SOC').state;
    
    let message = '';
    message += `Заряд батареї - <b>${battery}</b>`;

    return message;
});

['Alert_ElectricityLost'].forEach(function(contact) {
    alerts.contact(contact).on(function (alerts, e) {
        const battery = items.getItem('InverterBattery_SOC').state;

        bot.alert(e.message + `, заряд аккумулятора ${battery}`);
    }, function (alerts, e) {
        const battery = items.getItem('InverterBattery_SOC').state;

        bot.alert(e.message + `, заряд аккумулятора ${battery}`);
    });
});

В результаті, в домашньому телеграм-боті з'явилась інформація про поточний заряд батареї, плюс коли електрика зникає або вмикається - бот каже поточний стан батареї
image.png.96d11f5579cf72eb71d27ed3a82a2b08.png

А в графані моніторинг додатковий
image.thumb.png.7053b1cf570da48bf3b499ec12a0dc4c.png

 

Змінено користувачем standov
  • Лайк 5
Посилання на коментар
Поділитися на інших сайтах

В 16.10.2022 в 13:25, k-master сказал:

модбас через tcp/ip шлюз

Який саме шлюз використовуєте?

Посилання на коментар
Поділитися на інших сайтах

4 часа назад, InSAn сказал:

Який саме шлюз використовуєте?

Я замов отакий a.aliexpress.com/_EwnaYXT але ще не маю відгуку, подивимося бо заводити через серіал дуже не зручно

  • Лайк 1
Посилання на коментар
Поділитися на інших сайтах

19 годин тому, standov сказав:

Отже, купив я дистрибутів під малину в них на сайті, прошив малину, втикнув в інвертор через microUsb. Завелося майже одразу, виглядає досить привабливо, але то не наш путь. Включаємо в налаштуваннях mqtt брокер та погнали :)

Я просто накидав java апу котра опитує періодично інвертер та складає все в influx та mqtt. Бо усі ті додаткові малини коли вже стоїть сервер з докерами графаной та інфлюксом це оверхед. - maxx-ukoo/deye-modbus2mqtt. Правда коли пофікшу усі баги у tcp2modbus шлюзі навіть без цього можна буде обійтись, нехай опенхаб сам все опитує.

  • Лайк 2
Посилання на коментар
Поділитися на інших сайтах

Створіть акаунт або увійдіть у нього для коментування

Ви маєте бути користувачем, щоб залишити коментар

Створити акаунт

Зареєструйтеся для отримання акаунта. Це просто!

Зареєструвати акаунт

Увійти

Вже зареєстровані? Увійдіть тут.

Увійти зараз
×
×
  • Створити...