В связи с выходом крупного обновления 5.9.х, приглашаем вас принять участие в вебинаре 09.06.2022 в 15:00. Участвовать

Плагин MegaD



  • @regabriel, не получилось у меня получить значение CNT с помощью плагина MegaD, но гораздо быстрее и легче получилось с помощью плагина http):
    http_get_cnt-key.png



  • @Alex_Jet
    У меня все получилось. Есть такой файлик в плагине CHANGELOG.md
    Так вот там описано как получать данные.

    #### 2. Добавлена функция-обработчик для pluginCommand
    
     При отправке команды плагину из сценария (любые запросы, которые принимает MegaD) ответ от контроллера можно получить и обработать прямо в сценарии 
    
       Например, было можно отправить команду из сценария:
      
       ```this.pluginCommand({unit:'megad1', command:{url:'/sec/?cmd=7:1', onResponse:[{id:"7",value:1}]});```
    
       Здесь отправляем запрос на включение выхода 7. 
    
       onResponse задает массив - какие каналы (и соответственно связанные с ними устройства) нужно установить после получения положительного ответа от MegaD 
      
      Теперь добавлена возможность отправлять запросы и анализировать ответ на уровне сценария
      Таким образом можем, например,  читать состояния портов внутри сценария
    
      ```this.pluginCommand({unit:'megad1', command:{url:'/sec/?pt=7&cmd=get', onResponse:'raw'}}, 'getResponse');```
      
      onResponse:'raw' означает, что нужно вернуть сценарию ответ контроллера напрямую 
      Второй параметр - имя функции обработчика
      
      Ответ придет, если контроллер доступен и вернул статус 200, иначе ответа не будет, функция-обработчик не сработает, а сценарий останется активным.
      Чтобы сценарий завершился, предусмотрен выход по таймауту.
    
        script({
          start() {
            // Передать запрос на megad1, ответ без обработки пусть придет в сценарий (onResponse:'raw')
            this.pluginCommand({unit:'megad1', command:{url:'/sec/?pt=7&cmd=get', onResponse:'raw'}}, 'getResponse');
            // Взвести таймер на случай, если ответа от контроллера нет
            this.startTimer('T1', 3, 'onTimeout');
          },
        
          getResponse(body) {
            // body 
            this.log('getResponse body= '+body);
            this.exit();
         },
        
          onTimeout() {
            this.log('Истек таймаут, ответ от megad1 не получен');
            this.exit();
          }
        });
    
    

    А @intrapro ошибся в строке
    this.pluginCommand({unit:'megad3', command:'/sec/?pt=0&cmd=get'}, 'onGetResponse');
    },
    нехватает onResponse:'raw'

    ну а дальше обработка полученных данных в скрипте, думаю все не сложно



  • @regabriel, действительно, ошибочка вышла 😢



  • @regabriel, это тоже решение, однако сценарий в таком случае будет всегда в работе? Или вы его чем-то будете запускать?



  • @Alex_Jet
    Делаю сценарий мульти и в зависимости от типов счетчиков, ставлю разное расписание(каждые 5-60 сек). Так же запуск его(их) при перезагрузке контроллера.



  • Доброго времени суток. Подскажите пожалуйста как значение передаваемое в канале MegaD перевести из 16-тиричного значения в десятичное?



  • Пользователь @sergeyygr написал в Плагин MegaD:

    Доброго времени суток. Подскажите пожалуйста как значение передаваемое в канале MegaD перевести из 16-тиричного значения в десятичное?

    Добрый вечер, в javascript можно по разному

    parseInt(value,16)  // value = 'ff' =>  255
    

    Другой вариант: перед значением поставить '0x'

    parseInt(value)  // value = '0xff' =>  255
    // Первый вариант здесь тоже работает
    parseInt(value,16)  // value = '0xff' =>  255
    

    Но в плагине MegaD уже есть преобразование в число и формула может не сработать. В каком случае в канале приходят 16-ричные значения?



  • @intrapro
    Подключаю PZEM-016



  • Пользователь @intrapro написал в Плагин MegaD:

    Пользователь @sergeyygr написал в Плагин MegaD:

    Доброго времени суток. Подскажите пожалуйста как значение передаваемое в канале MegaD перевести из 16-тиричного значения в десятичное?

    Добрый вечер, в javascript можно по разному

    parseInt(value,16)  // value = 'ff' =>  255
    

    Другой вариант: перед значением поставить '0x'

    parseInt(value)  // value = '0xff' =>  255
    // Первый вариант здесь тоже работает
    parseInt(value,16)  // value = '0xff' =>  255
    

    Но в плагине MegaD уже есть преобразование в число и формула может не сработать. В каком случае в канале приходят 16-ричные значения?

    После запроса http://192.168.1.151/sec/?uart_tx=010400030002&mode=rs485
    в отладчике вот что
    Watt.PNG

    Вероятно нужен сценарий
    Скрипт:
    <?php
    while (true)
    {
    $res = file_get_contents("http://192.168.1.151/sec/?uart_tx=010400030002&mode=rs485");
    usleep(100000);
    $res = file_get_contents("http://192.168.1.151/sec/?uart_rx=1&mode=rs485");
    if ( $res != 'CRC Error' )
    {
    $data = explode("|", $res);
    $power = number_format(hexdec($data[3].$data[4]) / 10000, 4);
    echo " Мощность: ".$power."кВт";
    }
    else
    echo "Ошибка CRC";

    sleep(1);
    

    }

    Выдает
    1.PNG

    А как будет выглядеть сценарий по скрипту?



  • @sergeyygr Если нужно два запроса передавать с интервалом 100 мсек, лучше сделать сниппет прямо на устройстве:

    module.exports = callback => {
      const http = require('http');
    
      http.get('http://192.168.1.151/sec/?uart_tx=010400030002&mode=rs485');
      setTimeout(nextReq, 100); // 100 ms
    
      function nextReq() {
        http.get('http://192.168.1.151/sec/?uart_rx=1&mode=rs485', res => {
    
          let rawData = '';
          res.on('data', chunk => {
            rawData += chunk;
          });
    
          res.on('end', () => {
            const data = rawData;
            if (data.includes('CRC Error')) {
              callback('CRC Error'); // Контроллер вернул ошибку CRC
              return;
            }
    
            // 01|03|02|08|a1 - в таком виде ожидается ответ
             const arr = data.split("|");
            if (arr && arr.length > 4) {
              const val = parseInt(arr[3]+arr[4], 16);
              callback(null, val/10000);  
            } else {
              callback('Не удалось извлечь значение из строки: '+ data); // Данные получены, но парсинг неудачен
            }
          });
        });
      }
    };
    
    

    Период опроса (запуска сниппета) настраивается также на устройстве



  • Можно конечно и сценарий использовать

    const power = Device("SensorA", "Power"); 
    script({
      start() {
        this.pluginCommand({unit:'megad1', command:{url:'/sec/?uart_tx=010400030002&mode=rs485'}});
    
        // Следующий запрос через 100 мсек
        this.startTimer('T1', 0.1, 'getNext');
        // Взвести таймер на случай, если ответа от контроллера нет
        this.startTimer('T2', 2, 'onTimeout');
      },
    
      getNext() {
        // Передать запрос на megad1, ответ без обработки придет в сценарий (onResponse:'raw')
        this.pluginCommand({unit:'megad1', command:{url:'/sec/?pt=7&cmd=get', onResponse:'raw'}}, 'getResponse');
      },
    
      getResponse(body) {
        this.log('getResponse body= '+body);
       
        if (body.includes('CRC Error')) {
          this.log('CRC Error'); // Контроллер вернул ошибку CRC
          this.exit();
        }
    
        // 01|03|02|08|a1 - в таком виде ожидается ответ
        const arr = body.split("|");
        if (arr && arr.length > 4) {
          const val = parseInt(arr[3]+arr[4], 16);
          this.assign(power,"value",val/10000 );
        } else {
          this.log('Не удалось извлечь значение из строки: '+ body); // Данные получены, но парсинг неудачен
        }
      
        this.exit();
     },
    
      onTimeout() {
        this.log('Истек таймаут, ответ от megad не получен');
        this.exit();
      }
    });
    


  • Пользователь @intrapro написал в Плагин MegaD:

    @sergeyygr Если нужно два запроса передавать с интервалом 100 мсек, лучше сделать сниппет прямо на устройстве:

    Период опроса (запуска сниппета) настраивается также на устройстве

    Спасибо, получилось!
    Однако не получается считывать несколько показаний.
    Счетчик выдает несколько параметров, а именно:
    http://192.168.1.151/sec/?uart_tx=010400000001&mode=rs485
    http://192.168.1.151/sec/?uart_rx=1&mode=rs485 /Напряжение
    http://192.168.1.151/sec/?uart_tx=010400030002&mode=rs485
    http://192.168.1.151/sec/?uart_rx=1&mode=rs485 /Мощность
    http://192.168.1.151/sec/?uart_tx=010400050002&mode=rs485
    http://192.168.1.151/sec/?uart_rx=1&mode=rs485 /Накопленная электроэнергия (кВт/час)
    http://192.168.1.151/sec/?uart_tx=010400070001&mode=rs485
    http://192.168.1.151/sec/?uart_rx=1&mode=rs485 /Частота сети
    http://192.168.1.151/sec/?uart_tx=010400080001&mode=rs485
    http://192.168.1.151/sec/?uart_rx=1&mode=rs485 /Коэффициент мощности
    http://192.168.1.151/sec/?uart_tx=010400010002&mode=rs485
    http://192.168.1.151/sec/?uart_rx=1&mode=rs485 /Сила тока
    И в связи стем, что запрос на вывод показаний для всех переключений на параметр один и тот-же происходит конфликт, показания замирают. Как быть?
    Использую инструкции отсюда: https://ab-log.ru/smart-house/ethernet/megad-rs485



  • Пользователь @sergeyygr написал в Плагин MegaD:

    Спасибо, получилось!
    Однако не получается считывать несколько показаний.
    Счетчик выдает несколько параметров, а именно:
    http://192.168.1.151/sec/?uart_tx=010400000001&mode=rs485
    http://192.168.1.151/sec/?uart_rx=1&mode=rs485 /Напряжение
    http://192.168.1.151/sec/?uart_tx=010400030002&mode=rs485
    http://192.168.1.151/sec/?uart_rx=1&mode=rs485 /Мощность
    http://192.168.1.151/sec/?uart_tx=010400050002&mode=rs485
    http://192.168.1.151/sec/?uart_rx=1&mode=rs485 /Накопленная электроэнергия (кВт/час)
    http://192.168.1.151/sec/?uart_tx=010400070001&mode=rs485
    http://192.168.1.151/sec/?uart_rx=1&mode=rs485 /Частота сети
    http://192.168.1.151/sec/?uart_tx=010400080001&mode=rs485
    http://192.168.1.151/sec/?uart_rx=1&mode=rs485 /Коэффициент мощности
    http://192.168.1.151/sec/?uart_tx=010400010002&mode=rs485
    http://192.168.1.151/sec/?uart_rx=1&mode=rs485 /Сила тока
    И в связи стем, что запрос на вывод показаний для всех переключений на параметр один и тот-же происходит конфликт, показания замирают. Как быть?
    Использую инструкции отсюда: https://ab-log.ru/smart-house/ethernet/megad-rs485

    Можно сценарий сделать. Который будет запущен на старте сервера и будет последовательно опрашивать с каким-то интервалом.
    Примерно так, но надо тестировать

    
    // Здесь все датчики - для примера два первых:
    const voltage = Device("SensorA", "Voltage"); 
    const power = Device("SensorA", "Power"); 
    
    script({
      boot() {  
        return true; // Сценарий будет запускаться на старте и всегда будет активным
      },
    
      step:0,  
    
      start() {
        this.step = 1;
        this.getTx();
      },
    
      getTx() {
       let url;
       switch (this.step) {
         case 1: // Напряжение - voltage
          url = '/sec/?uart_tx=010400000001&mode=rs485';
          break;
    
         case 2: // Мощность - power
          url = '/sec/?uart_tx=010400030002&mode=rs485';
          break;
          // ...  
       }
    
       // Отправить запрос на контроллер
       this.pluginCommand({unit:'megad1', command:{url}});
    
       // запрос Rx через 100 мсек 
       this.startTimer('T1', 0.1, 'getRx');
    
       // Запрос следующего параметра через 1 сек
       this.startTimer('T2', 1, 'nextParam');
      },
    
      getRx() {
        // Передать запрос на megad1, ответ придет в сценарий (onResponse:'raw')
       // БЫЛО С ОПЕЧАТКОЙ   this.pluginCommand({unit:'megad1', command:{url:'/sec/uart_rx=1&mode=rs485', onResponse:'raw'}}, 'getResponse');
       this.pluginCommand({unit:'megad1', command:{url:'/sec/?uart_rx=1&mode=rs485', onResponse:'raw'}}, 'getResponse');
      },
    
      getResponse(body) {
        // body 
        // this.log('getResponse body= '+body+' step='+this.step);
       
        if (body.includes('CRC Error')) {
          this.log('CRC Error'); // Контроллер вернул ошибку CRC - здесь нужно что-то решать, пока просто выход
          this.exit();
        }
    
        // 01|03|02|08|a1 - в таком виде ожидается ответ
        const arr = body.split("|");
        if (arr && arr.length > 4) {
          this.assignValue(arr);  
        } else {
          this.log('Не удалось извлечь значение из строки: '+ body); // Данные получены, но парсинг неудачен
          this.exit();
        }
      },
    
      assignValue(arr) {
        const val = parseInt(arr[3]+arr[4], 16); // Если парсинг разный - перенести в case 
        switch (this.step) {
          case 1: 
            this.assign(voltage,"value", val );
            return;
          case 2: 
            this.assign(power,"value", val/10000 );
            return;
          // ...
        }
      },
    
      nextParam() {
       this.step = this.step < 7 ? this.step+1 : 1;
       this.getTx();
      }
    });
    
    

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



  • Можно сценарий сделать. Который будет запущен на старте сервера и будет последовательно опрашивать с каким-то интервалом.
    Примерно так, но надо тестировать

    Не работает. В отладчике "37 Now is NOT active."



  • Пользователь @sergeyygr написал в Плагин MegaD:

    Не работает. В отладчике "37 Now is NOT active."

    Нужно посмотреть, нет ли ошибки в таблице Рабочие сценарии.
    Если нет - смотреть отладчик при запуске.

    Предлагаю для простоты сценарий превратить из мультисценария в обычный:

    • запуск для устройств убрать

    • прописать ваши названия устройств вместо SensorA:

      const voltage = Device("VOLT1", "Voltage");
      const power = Device("POWER1", "Power");

    • сохранить, обновить таблицу - теперь это обычный сценарий

    • Запустить отладчик для сценария. Окно пока будет пустое

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

    Теперь в отладчике (в первой вкладке) будет трассировка прохождения сценария (либо в таблице в столбце Ошибка будет сообщение об ошибке, если сценарий не смог запуститься)



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



  • Пользователь @intrapro написал в Плагин MegaD:

    Пользователь @sergeyygr написал в Плагин MegaD:

    Не работает. В отладчике "37 Now is NOT active."

    Нужно посмотреть, нет ли ошибки в таблице Рабочие сценарии.
    Если нет - смотреть отладчик при запуске.

    Предлагаю для простоты сценарий превратить из мультисценария в обычный:

    • запуск для устройств убрать

    • прописать ваши названия устройств вместо SensorA:

      const voltage = Device("VOLT1", "Voltage");
      const power = Device("POWER1", "Power");

    • сохранить, обновить таблицу - теперь это обычный сценарий

    • Запустить отладчик для сценария. Окно пока будет пустое

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

    Теперь в отладчике (в первой вкладке) будет трассировка прохождения сценария (либо в таблице в столбце Ошибка будет сообщение об ошибке, если сценарий не смог запуститься)

    Попробовал. Сценарий не запускается. Сообщений об ошибках нет. В отладчике нажимал пуск, кнопка пуска становилась неактивной (серой), после запуска сценария из меню "рабочие сценарии" кнопка запуска сценария опять становится активной (белой).
    Вот весь сценарий:
    /**

    • @name Сценарий считывания показаний датчика PZEM
    • @desc Считывает показания датчиков PZEM
    • @version 4
      */
      // Здесь все датчики - для примера два первых:
      const volt = Device("PZEM_Volt");
      const Watt = Device("PZEM_Watt");
      const Hz = Device("PZEM_Hz");
      const cos = Device("PZEM_cos");
      const kWh = Device("PZEM_kWh");
      const Amper = Device("PZEM_Amper");

    script({
    boot() {
    return true; // Сценарий будет запускаться на старте и всегда будет активным
    },

    step:0,

    start() {
    this.step = 1;
    this.getTx();
    },

    getTx() {
    let url;
    switch (this.step) {
    case 1: // Напряжение - volt
    url = '/sec/?uart_tx=010400000001&mode=rs485';
    break;
    case 2: // Мощность - kW
    url = '/sec/?uart_tx=010400030002&mode=rs485';
    break;
    case 3: // Частота - Hz
    url = '/sec/?uart_tx=010400070001&mode=rs485';
    break;
    case 4: // Коэффициент - cof
    url = '/sec/?uart_tx=010400080001&mode=rs485';
    break;
    case 5: // Мощность накопленная - kWh
    url = '/sec/?uart_tx=010400050002&mode=rs485';
    break;
    case 6: // Сила тока - Amp
    url = '/sec/?uart_tx=010400010002&mode=rs485';
    break;
    // ...
    }

    // Отправить запрос на контроллер
    this.pluginCommand({unit:'megad1', command:{url}});

    // запрос Rx через 100 мсек
    this.startTimer('T1', 0.1, 'getRx');

    // Запрос следующего параметра через 1 сек
    this.startTimer('T2', 1, 'nextParam');
    },

    getRx() {
    // Передать запрос на megad1, ответ придет в сценарий (onResponse:'raw')
    this.pluginCommand({unit:'megad1', command:{url:'/sec/uart_rx=1&mode=rs485', onResponse:'raw'}}, 'getResponse');
    },

    getResponse(body) {
    //body
    //this.log('getResponse body= '+body+' step='+this.step);

    if (body.includes('CRC Error')) {
      this.log('CRC Error'); // Контроллер вернул ошибку CRC - здесь нужно что-то решать, пока просто выход
      this.exit();
    }
    
    // 01|03|02|08|a1 - в таком виде ожидается ответ
    const arr = body.split("|");
    if (arr && arr.length > 4) {
      this.assignValue(arr);  
    } else {
      this.log('Не удалось извлечь значение из строки: '+ body); // Данные получены, но парсинг неудачен
      this.exit();
    }
    

    },

    assignValue(arr) {
    const val = parseInt(arr[3]+arr[4], 16); // Если парсинг разный - перенести в case
    switch (this.step) {
    case 1:
    this.assign(volt,"value", val/10 );
    return;
    case 2:
    this.assign(Watt,"value", val/1000 );
    return;
    case 3:
    this.assign(Hz,"value", val/10 );
    return;
    case 4:
    this.assign(cos,"value", val/10 );
    return;
    case 5:
    this.assign(kWh,"value", val/10 );
    return;
    case 6:
    this.assign(Amper,"value", val/10 );
    return;
    // ...
    }
    },

    nextParam() {
    this.step = this.step < 7 ? this.step+1 : 1;
    this.getTx();
    }
    });



  • @sergeyygr, посмотрите, в Рабочих сценариях для этого сценария есть что-то в графах: Число запусков, Последний запуск, Последний останов

    WorkScene.png



  • Пользователь @intrapro написал в Плагин MegaD:

    @sergeyygr, посмотрите, в Рабочих сценариях для этого сценария есть что-то в графах: Число запусков, Последний запуск, Последний останов

    WorkScene.png

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



  • @sergeyygr а останова нет? То есть сценарий уже работает в цикле. Можно раскомментировать эту строку и смотреть в журнале

    this.log('getResponse body= '+body+' step='+this.step);
    

    Можно еще в getTx добавить логирование

    this.log('getTx step='+this.step);
    

    ! После редактирования сценарий остановится и сам не запустится, его надо запустить


Log in to reply