Navigation

    Logo
    • Register
    • Login
    • Search
    • Recent
    • Tags
    • Unread
    • Categories
    • Unreplied
    • Popular
    • GitHub
    • Docu
    • Hilfe
    1. Home
    2. andrey99986

    NEWS

    • ioBroker@Smart Living Forum Solingen, 14.06. - Agenda added

    • ioBroker goes Matter ... Matter Adapter in Stable

    • Monatsrückblick - April 2025

    A
    • Profile
    • Following 1
    • Followers 0
    • Topics 19
    • Posts 214
    • Best 0
    • Groups 2

    andrey99986

    @andrey99986

    0
    Reputation
    90
    Profile views
    214
    Posts
    0
    Followers
    1
    Following
    Joined Last Online

    andrey99986 Follow
    Pro Starter

    Latest posts made by andrey99986

    • RE: Практическое применение ПЛК Beckhoff и ioBroker

      Удалось уместить проект flat практически без уменьшения функциональности в ПЛК BC9000:

      https://github.com/Andrey2509/SMARTHOME/blob/master/BC9000/flat-BC9000.pr6
      Перенос был осуществлён с целью резервирования - теперь при выходе из строя CX9010 я могу за 5 минут поставить вместо него BC9000 и УД продолжит своё функционирование без необходимости что-либо править на программном уровне.

      Проект dacha также перенесён, за исключением запроса исторических данных по месяцам со счётчика Меркурий 230 (не хватило памяти контроллера).

      Контроллер BC9000 стоит относительно не дорого на вторичном рынке (около 5 тыс. руб.), модули также не дорогие. Поэтому решения на данном контроллере вполне доступны.

      posted in Проекты (Витрина)
      A
      andrey99986
    • Реализация УД на ПЛК Beckhoff BC9000

      Ранее, в другой ветке форума была опубликована реализация УД на ПЛК Beckhoff CX9010/9000:
      https://forum.iobroker.net/topic/27402/практическое-применение-плк-beckhoff-и-iobroker

      Удалось уместить проект flat практически без уменьшения функциональности в ПЛК BC9000:

      https://github.com/Andrey2509/SMARTHOME/blob/master/BC9000/flat-BC9000.pr6
      Перенос был осуществлён с целью резервирования - теперь при выходе из строя CX9010 я могу за 5 минут поставить вместо него BC9000 и УД продолжит своё функционирование без необходимости что-либо править на программном уровне.

      Проект dacha также перенесён, за исключением запроса исторических данных по месяцам со счётчика Меркурий 230 (не хватило памяти контроллера).

      Контроллер BC9000 стоит относительно не дорого на вторичном рынке (около 5 тыс. руб.), модули также не дорогие. Поэтому решения на данном контроллере вполне доступны.

      posted in ioBroker основное
      A
      andrey99986
    • RE: [Neuer Adapter] LinkedDevices

      Please help me make a script for linking to a new source object.
      For example, there is a link:
      modbus.0.sensor1 -> linkeddevices.0.sensor1
      I need this link to be reassigned as follows:
      modbus.1.sensor1 -> linkeddevices.0.sensor1
      by some event when subscribing (function "on").

      posted in Tester
      A
      andrey99986
    • Передача показаний приборов учёта на web-сайт

      Задача : передавать данные по приборам учёта на сайты УК.

      Условие: на web-сайте не должно быть капчи.

      Решение:

      Установить chromium браузер. Chromium для debian 10 ставится командой:
      "apt-get install chromium chromium-l10n".

      В свойства драйвера javascript дописываем библиотеку "puppeteer".

      Алгоритм навигации и заполнения:

      Для навигации по сайту используем селекторы.
      Приоритет при навигации по сайту с помощью библиотеки puppeteer:

      1. Если элемент страницы содержит id, например 'id=sendCountersValues', используем его. Самый лучший вариант. При копипасте через десктопный браузер селектор будет выглядеть так: '#sendCountersValues'. Однако некоторые id - автогенерируемые, необходимо убедиться что он не меняется в новой сессии браузера или при новой передачи данных.
      2. Через копипаст селектора как показано на картинках step1_selector.png, step2_selector.png. Главное чтобы скрипт при работе с таким селектором не выдавал ошибок. Селектор будет например таким: '#authorization_form > div:nth-child(2) > div > input'.
      3. По атрибуту 'name='. Селектор будет например таким: 'input[name=login]'. Возможная проблема - когда несколько данных имеют одинаковый 'name='. Этот случай рассмотрен ниже.
      4. По классу, например элемент имеет класс 'btn-lg'. Селектор будет тогда таким: '.btn-lg'. Уникальность так же не гарантирована, в этом случае подход такой же как в п. 3.
      5. Навигация курсором мыши или клавиатурой (Tab). Тупо, но работает когда по другому не получается.

      Внимание!
      После каждого ошибочного запуска скрипта в памяти остаётся процесс "chromium". Проверка: " ps aux|grep chromium"
      Рекомендую убивать процессы командой "killall chromium"
      Иначе вся оперативная память забъётся и система будет тормозить и глючить до перезагрузки.

      Скрипт с комментариями:

      const puppeteer = require('puppeteer');
      var util = require('util')
      //Запускаем раз в месяц 16 числа в 8:40
      schedule("40 8 16 * *", function () {
          send_data();
      
      }); //schedule end
      
      
      async function send_data() {
      //Присвоение переменным скрипта данных приборов учёта
      const Bath_cold = getState('modbus.0.holdingRegisters.12328_Bathroom_stat_cold_water').val/100;
      const Bath_warm =  getState('modbus.0.holdingRegisters.12330_Bathroom_stat_warm_water').val/100 + 0.006;
      const Kitchen_cold = getState('modbus.0.holdingRegisters.12324_Kitchen_stat_cold_water').val/100;
      const Kitchen_warm =  getState('modbus.0.holdingRegisters.12326_Kitchen_stat_warm_water').val/100;
      
      //log('Bath_cold='+Bath_cold+', Bath_warm='+Bath_warm);
      //log('Kitchen_cold='+Kitchen_cold+', Kitchen_warm='+Kitchen_warm);
      
      //Проверка на допустимый диапазон данных
      if (Bath_cold >1 && Bath_cold <100000 && Bath_warm>1 && Bath_warm<100000  && Kitchen_cold >1 && Kitchen_cold <100000 && Kitchen_warm>1 && Kitchen_warm<100000)
      {
      
      
        const browser = await puppeteer.launch({
        //указываем путь к chromium браузеру.
        executablePath: '/usr/bin/chromium',
        //разрешение с которым будет работать chromium. Должно быть достаточным для отображения всей страницы, с которыми будет работать chromium. Увеличить при необходимости. Не имеет отношение к разрешению экрана.
        'defaultViewport' : { 'width' : 1920, 'height' : 1080 }
      });
        const page = await browser.newPage();
       //подключаем функцию отображения указателя мыши (может понадобиться в редких случаях) 
       await installMouseHelper(page);
        //Указываем главную страницу сайта
        await page.goto('https://lk.rkcgkh.ru/', { waitUntil: 'networkidle0' });
        
       //Смотрим картинку step1_selector.jpg, копипастим селектор. Команда на ожидание появление селектора.  
        await page.waitForSelector('#authorization_form > div:nth-child(2) > div > input');
       //Другой вариант - ждём появления элемента с заданными атрибутами. 
       await page.waitFor('input[name=login]');
      
       //Указываем свой login и пароль 
        await page.$eval('input[name=login]', el => el.value = 'MYEAMAIL@yandex.ru');
        await page.$eval('input[name=password]', el => el.value = 'MYPASSWORD');
        
      //Селектор для кнопки можно определить несколькими способами: скопипастить - см. step2_selector.jpg
       //const selector1 = "#authorization_form > div:nth-child(4) > div.col-auto > button";
       //или определить так.
       const selector1_alt = ('button[type=submit]');
       //ждём когда селектор кнопки загрузится
        await page.waitFor(selector1_alt);
        //Здесь происходит клик по кнопке
        await page.click(selector1_alt);
        //Сохраняем картинку чтобы увидеть что происходит. Это момент сразу после клика поэтому страница будет такая же как перед кликом. Чтобы увидеть результат клика надо принудительно задать ожидание(ненадёжно) или ожидать загрузки селектора новой страницы.
        await page.screenshot({path: '/tmp/screen0.png'});
        //Определяем селектор - пункт меню "Показания" . Картинки нет, но подход полностью аналогичен предыдущему клику. 
        const selector2 = "#stack-sidebar > ul > li:nth-child(3) > a";
      //Ожидаем загрузки селектора для подтверждения открытия нового содержимого.
       await page.waitFor(selector2);
       //Вот здесь мы только увидим новую страницу после клика.
        await page.screenshot({path: '/tmp/screen1.png'});
       //Клик на пункте "Показания"
        await page.click(selector2);
      
       // Определяем селектор - блок в котором содержатся поля ввода данных. Это может быть любой вышестоящий блок с наличием идентификатора (id = "... ") или селекторы полей ввода.
        const selector3 = '#sendCountersValues';
      //Ожидаем загрузки селектора для подтверждения открытия нового содержимого.
        await page.waitFor(selector3);
      //Сохраняем скриншот для целей отладки. Здесь будут пустые поля
        await page.screenshot({path: '/tmp/screen2.png'});
      
      //На картинке step3.png смотрим атрибуты полей ввода по которым будет определяться селектор.
      // Копипаст селектора в данном случае  не сработал, возможно из-за бага в библиотеке при экранировании квадратных кавычек "[", "]" 
      
      //Вводим данные
       await page.$eval('input[name="counters[139786_0][value]"]', (el, var_KC) => el.value = var_KC,Kitchen_cold);
       await page.$eval('input[name="counters[139787_0][value]"]', (el, var_BC) => el.value = var_BC,Bath_cold);
       await page.$eval('input[name="counters[139788_0][value]"]', (el, var_KW) => el.value = var_KW,Kitchen_warm);
       await page.$eval('input[name="counters[139789_0][value]"]', (el, var_BW) => el.value = var_BW,Bath_warm);
      //Здесь картинка уже будет содержать данные, так как функция ввода с подтверждением ввода. 
      await page.screenshot({path: '/tmp/screen3.png'});
      
      //Создаём клик на кнопку "Передать", см step4.png, копипастим селектор. 
       const selector4= '#sendCountersValues > div.row.row-widget-next.row-submit > div > input';
      //Ожидаем загрузки селектора
       await page.waitFor(selector4);
      //Клик на кнопке "Передать"
       await page.click(selector4);
      //Ждём 2 секунды, а лучше сделать ожидание селектора новой страницы.
       await page.waitForTimeout(2000);
      //Здесь будет скриншот об успешном приёме данных. 
       await page.screenshot({path: '/tmp/screen4.png'});
      
        await browser.close();
      
        sendTo('telegram.0', '/tmp/screen4.png', function (res) { 
                          log('Sent to telegram ' + res + ' users'); 
                        });
      
      }
      }
      
      
      
      
      async function installMouseHelper(page) {
        await page.evaluateOnNewDocument(() => {
          // Install mouse helper only for top-level frame.
          if (window !== window.parent)
            return;
          window.addEventListener('DOMContentLoaded', () => {
            const box = document.createElement('puppeteer-mouse-pointer');
            const styleElement = document.createElement('style');
            styleElement.innerHTML = `
              puppeteer-mouse-pointer {
                pointer-events: none;
                position: absolute;
                top: 0;
                z-index: 10000;
                left: 0;
                width: 20px;
                height: 20px;
                background: rgba(0,0,0,.4);
                border: 1px solid white;
                border-radius: 10px;
                margin: -10px 0 0 -10px;
                padding: 0;
                transition: background .2s, border-radius .2s, border-color .2s;
              }
              puppeteer-mouse-pointer.button-1 {
                transition: none;
                background: rgba(0,0,0,0.9);
              }
              puppeteer-mouse-pointer.button-2 {
                transition: none;
                border-color: rgba(0,0,255,0.9);
              }
              puppeteer-mouse-pointer.button-3 {
                transition: none;
                border-radius: 4px;
              }
              puppeteer-mouse-pointer.button-4 {
                transition: none;
                border-color: rgba(255,0,0,0.9);
              }
              puppeteer-mouse-pointer.button-5 {
                transition: none;
                border-color: rgba(0,255,0,0.9);
              }
            `;
            document.head.appendChild(styleElement);
            document.body.appendChild(box);
            document.addEventListener('mousemove', event => {
              box.style.left = event.pageX + 'px';
              box.style.top = event.pageY + 'px';
              updateButtons(event.buttons);
            }, true);
            document.addEventListener('mousedown', event => {
              updateButtons(event.buttons);
              box.classList.add('button-' + event.which);
            }, true);
            document.addEventListener('mouseup', event => {
              updateButtons(event.buttons);
              box.classList.remove('button-' + event.which);
            }, true);
            function updateButtons(buttons) {
              for (let i = 0; i < 5; i++)
                box.classList.toggle('button-' + i, buttons & (1 << i));
            }
          }, false);
        });
      };
      

      Рассмотрим вариант когда элемент не уникален.
      В моём случае это была таблица с полями ввода, которая через селекторы никак не хотела работать.
      Пример на картинке step5.png.
      Решение следующее:

      const inputs = await page.$$('input[type=text]');
      await inputs[0].type(String(T1));
      await inputs[1].type(String(T2));
      

      Так как у всех элементов input есть общий атрибут "type=text" - загоняем их в массив, и обращаемся к элементам массива.

      Другой проблемный вариант кнопка на картинке step6.png , селектор через копипаст не работает.
      Решение - использовать class элемента :

      const button = await page.$('.btn-lg');
      await button.click();
      

      И самый плохой вариант, когда через селекторы не получается. Здесь уже нужна функция installMouseHelper, которую я нашёл на просторах интернета.
      Просто позиционируем курсор (небольшой серый кружок) на нужный элемент и кликаем - картинка step7.png:

      await page.mouse.move(600,820);
      await page.mouse.click(600,820);
      

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

      await page.keyboard.press("Tab");
      await page.keyboard.press("Tab");
      await page.keyboard.press("Tab");
      await page.keyboard.type(String(T2));
      

      API библиотеки : puppeteer

      step1_selector.png step1_selector.png
      step2_selector.png step2_selector.png
      step3.png step3.png
      step4.png step4.png
      step5.png step5.png
      step6.png step6.png
      step7.png step7.png

      posted in ioBroker скрипты
      A
      andrey99986
    • Практическое применение ПЛК Beckhoff и ioBroker

      Практическое применение ПЛК Beckhoff CX9000/CX9010 и платформы Умного дома (УД) ioBroker в автоматизации квартиры и дачи

      https://sprut.ai/client/article/1718

      Вопросы можно задавать также здесь: https://t.me/iobroker

      posted in Проекты (Витрина)
      A
      andrey99986
    • RE: Скрипт для счетчика Меркурий 230

      Обновил версию на github для espeasy.

      Изменения:

      -замена опасных функций (с указателями на данные) на безопасные,

      -поддержка hardware serial (необходимо убрать галку использования serial самой espeasy),

      -статистика передаётся в 2-х топиках: по месяцам и по предыдущему дню,

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

      posted in ioBroker скрипты
      A
      andrey99986
    • RE: Автоматизация света и вытяжки в ванной по датчику движения и влажности (с использованием данных из sql)

      @Pooh:

      У меня выключенный вентилятор крутиться от естественного потока (некоторые вентиляторы имеют клапан, да…) `

      То что он крутится это не значит что пропускная способность канала не снизилась. А клапаны от ЕВ откроются только на сильном перепаде высот и в определённое время года. Если до крыши этажей меньше 4, а в доме теплей чем на улице менее 5 градусов - уверен что клапан даже не откроется.

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

      posted in ioBroker скрипты
      A
      andrey99986
    • RE: Автоматизация света и вытяжки в ванной по датчику движения и влажности (с использованием данных из sql)

      Тем кто ставит вентилятор в квартире в отверстие естественной вентиляции (ЕВ) имейте ввиду что выключенный вентилятор уменьшает тягу ЕВ в ~10 раз. Если у вас всего 2 таких отверстия одно на кухне, другое в ванной и в одно их них поставить вентилятор то можно сказать что вы в среднем ухудшили вентиляцию (за счёт вытяжки) в 2 раза для квартиры в целом. Для ванной вентиляция при выключенном ухудшится в ~10 раз.

      Это легко проверяется датчиками CO2. Чтобы проветрить квартиру придётся не просто приоткрывать окно на маленькую щель, а делать сквозное проветривание.Так как тяги 1 лишь кухонной вытяжки не хватает. А если и в кухонной вытяжке поставили только периодически работающий вентилятор - то вообще всё плохо будет.

      posted in ioBroker скрипты
      A
      andrey99986
    • RE: Скрипт для счетчика Меркурий 230

      @ssvvvv:

      Скажите получилось победить утечку памяти? `
      Та версия, которая на github (ссылка выше) - без утечки памяти.

      Проверяется просто - в espeasy ставится девайс "Generic - System Info ". Индикатор "Free RAM". далее штатно передаём через mqtt иоброкеру и сохраняем историю. У меня uptime уже 22 дня, память не уменьшается.

      Были короткие uptime до замены БП, esp(nodemcu) оказалась очень чувствительна и к самому БП, и к проводам подводящим питание.

      Сейчас БП и питание RS485 конвертора выставил ровно на 5.0 Вольт.

      Частота запросов 10 с - на ней не тестировал, у меня 60 сек.

      posted in ioBroker скрипты
      A
      andrey99986
    • RE: Скрипт для счетчика Меркурий 230

      @ssvvvv:

      В дополнение у меня Nodemcu V3 `

      Плагин автодисейблиться может по причине:

      1.В espeasy должен быть создан MQTT контроллер в соответствующей закладке (тестировал только тип Openhab).

      2. Не правильно указаны GPIO RX/TX или неправильно подключен к конвертору RS232/RS485.

      Я использую такой:

      https://ru.aliexpress.com/item/Single-C … 57602.html

      Напрямую к счётчику подключать нельзя!

      posted in ioBroker скрипты
      A
      andrey99986
    Community
    Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen
    The ioBroker Community 2014-2023
    logo