Считывание показаний через MBUS и передача через MQTT Landis+Gyr Ultraheat UH50

Парни них хелп!
Удалось подключить к WB свой счетчик тепла (через такой адаптер RS485 to MBUS https://a.aliexpress.com/_uuHbAP )

Скомпилировал эту библиотеку rSCADA - Raditex control systems

Получил такой ответ на запрос:

root@wirenboard-ATZ522DE:~# mbus-serial-request-data /dev/ttyRS485-2 -d
<MBusData>

    <SlaveInformation>
        <Id>68924134</Id>
        <Manufacturer>LUG</Manufacturer>
        <Version>4</Version>
        <ProductName>Landis &amp; Gyr Ultraheat UH50</ProductName>
        <Medium>Heat: Outlet</Medium>
        <AccessNumber>0</AccessNumber>
        <Status>00</Status>
        <Signature>0000</Signature>
    </SlaveInformation>

    <DataRecord id="0">
        <Function>Instantaneous value</Function>
        <Unit>Actuality Duration (seconds)</Unit>
        <Value>4</Value>
        <Timestamp>2021-02-08T18:34:01</Timestamp>
    </DataRecord>

    <DataRecord id="1">
        <Function>Instantaneous value</Function>
        <Unit>Averaging Duration (seconds)</Unit>
        <Value>4</Value>
        <Timestamp>2021-02-08T18:34:01</Timestamp>
    </DataRecord>

    <DataRecord id="2">
        <Function>Instantaneous value</Function>
        <Unit>Energy (MJ)</Unit>
        <Value>34732</Value>
        <Timestamp>2021-02-08T18:34:01</Timestamp>
    </DataRecord>

    <DataRecord id="3">
        <Function>Instantaneous value</Function>
        <Unit>Volume (1e-2  m^3)</Unit>
        <Value>198075</Value>
        <Timestamp>2021-02-08T18:34:01</Timestamp>
    </DataRecord>

    <DataRecord id="4">
        <Function>Instantaneous value</Function>
        <Unit>Power (100 W)</Unit>
        <Value>34</Value>
        <Timestamp>2021-02-08T18:34:01</Timestamp>
    </DataRecord>

    <DataRecord id="5">
        <Function>Instantaneous value</Function>
        <Unit>Volume flow (m m^3/h)</Unit>
        <Value>192</Value>
        <Timestamp>2021-02-08T18:34:01</Timestamp>
    </DataRecord>

    <DataRecord id="6">
        <Function>Instantaneous value</Function>
        <Unit>Flow temperature (deg C)</Unit>
        <Value>64</Value>
        <Timestamp>2021-02-08T18:34:01</Timestamp>
    </DataRecord>

    <DataRecord id="7">
        <Function>Instantaneous value</Function>
        <Unit>Return temperature (deg C)</Unit>
        <Value>49</Value>
        <Timestamp>2021-02-08T18:34:01</Timestamp>
    </DataRecord>

    <DataRecord id="8">
        <Function>Instantaneous value</Function>
        <Unit>Temperature Difference (1e-1  deg C)</Unit>
        <Value>155</Value>
        <Timestamp>2021-02-08T18:34:01</Timestamp>
    </DataRecord>

    <DataRecord id="9">
        <Function>Instantaneous value</Function>
        <Unit>Volume (1e-2  m^3)</Unit>
        <Value>180958</Value>
        <Timestamp>2021-02-08T18:34:01</Timestamp>
    </DataRecord>

    <DataRecord id="10">
        <Function>Instantaneous value</Function>
        <Unit>Energy (MJ)</Unit>
        <Value>32051</Value>
        <Timestamp>2021-02-08T18:34:01</Timestamp>
    </DataRecord>

    <DataRecord id="11">
        <Function>Instantaneous value</Function>
        <Unit>Fabrication number</Unit>
        <Value>68924134</Value>
        <Timestamp>2021-02-08T18:34:01</Timestamp>
    </DataRecord>

    <DataRecord id="12">
        <Function>Instantaneous value</Function>
        <Unit>Averaging Duration (minutes)</Unit>
        <Value>60</Value>
        <Timestamp>2021-02-08T18:34:01</Timestamp>
    </DataRecord>

    <DataRecord id="13">
        <Function>Maximum value</Function>
        <Unit>Power (100 W)</Unit>
        <Value>62</Value>
        <Timestamp>2021-02-08T18:34:01</Timestamp>
    </DataRecord>

    <DataRecord id="14">
        <Function>Maximum value</Function>
        <Unit>Power (100 W)</Unit>
        <Value>62</Value>
        <Timestamp>2021-02-08T18:34:01</Timestamp>
    </DataRecord>

    <DataRecord id="15">
        <Function>Maximum value</Function>
        <Unit>Volume flow (m m^3/h)</Unit>
        <Value>264</Value>
        <Timestamp>2021-02-08T18:34:01</Timestamp>
    </DataRecord>

    <DataRecord id="16">
        <Function>Maximum value</Function>
        <Unit>Flow temperature (deg C)</Unit>
        <Value>149</Value>
        <Timestamp>2021-02-08T18:34:01</Timestamp>
    </DataRecord>

    <DataRecord id="17">
        <Function>Maximum value</Function>
        <Unit>Return temperature (deg C)</Unit>
        <Value>74</Value>
        <Timestamp>2021-02-08T18:34:01</Timestamp>
    </DataRecord>

    <DataRecord id="18">
        <Function>Instantaneous value</Function>
        <Unit>On time (hours)</Unit>
        <Value>37367</Value>
        <Timestamp>2021-02-08T18:34:01</Timestamp>
    </DataRecord>

    <DataRecord id="19">
        <Function>Value during error state</Function>
        <Unit>On time (hours)</Unit>
        <Value>9522</Value>
        <Timestamp>2021-02-08T18:34:01</Timestamp>
    </DataRecord>

    <DataRecord id="20">
        <Function>Value during error state</Function>
        <Unit>On time (hours)</Unit>
        <Value>9522</Value>
        <Timestamp>2021-02-08T18:34:01</Timestamp>
    </DataRecord>

    <DataRecord id="21">
        <Function>Instantaneous value</Function>
        <Unit>Time Point (date)</Unit>
        <Value>2000-01-01</Value>
        <Timestamp>2021-02-08T18:34:01</Timestamp>
    </DataRecord>

    <DataRecord id="22">
        <Function>Instantaneous value</Function>
        <Unit>Energy (kWh)</Unit>
        <Value>0</Value>
        <Timestamp>2021-02-08T18:34:01</Timestamp>
    </DataRecord>

    <DataRecord id="23">
        <Function>Instantaneous value</Function>
        <Unit>Energy (kWh)</Unit>
        <Value>0</Value>
        <Timestamp>2021-02-08T18:34:01</Timestamp>
    </DataRecord>

    <DataRecord id="24">
        <Function>Instantaneous value</Function>
        <Unit>Energy (kWh)</Unit>
        <Value>0</Value>
        <Timestamp>2021-02-08T18:34:01</Timestamp>
    </DataRecord>

    <DataRecord id="25">
        <Function>Instantaneous value</Function>
        <Unit>Energy (kWh)</Unit>
        <Value>0</Value>
        <Timestamp>2021-02-08T18:34:01</Timestamp>
    </DataRecord>

    <DataRecord id="26">
        <Function>Instantaneous value</Function>
        <Unit>Energy (kWh)</Unit>
        <Value>0</Value>
        <Timestamp>2021-02-08T18:34:01</Timestamp>
    </DataRecord>

    <DataRecord id="27">
        <Function>Instantaneous value</Function>
        <Unit>Energy (kWh)</Unit>
        <Value>0</Value>
        <Timestamp>2021-02-08T18:34:01</Timestamp>
    </DataRecord>

    <DataRecord id="28">
        <Function>Maximum value</Function>
        <Unit>Flow temperature (deg C)</Unit>
        <Value>75</Value>
        <Timestamp>2021-02-08T18:34:01</Timestamp>
    </DataRecord>

    <DataRecord id="29">
        <Function>Maximum value</Function>
        <Unit>Return temperature (deg C)</Unit>
        <Value>74</Value>
        <Timestamp>2021-02-08T18:34:01</Timestamp>
    </DataRecord>

    <DataRecord id="30">
        <Function>Maximum value</Function>
        <Unit>Volume flow (m m^3/h)</Unit>
        <Value>192</Value>
        <Timestamp>2021-02-08T18:34:01</Timestamp>
    </DataRecord>

    <DataRecord id="31">
        <Function>Maximum value</Function>
        <Unit>Power (100 W)</Unit>
        <Value>47</Value>
        <Timestamp>2021-02-08T18:34:01</Timestamp>
    </DataRecord>

    <DataRecord id="32">
        <Function>Value during error state</Function>
        <Unit>On time (hours)</Unit>
        <Value>9522</Value>
        <Timestamp>2021-02-08T18:34:01</Timestamp>
    </DataRecord>

    <DataRecord id="33">
        <Function>Instantaneous value</Function>
        <Unit>Energy (MJ)</Unit>
        <Value>34199</Value>
        <Timestamp>2021-02-08T18:34:01</Timestamp>
    </DataRecord>

    <DataRecord id="34">
        <Function>Instantaneous value</Function>
        <Unit>Energy (kWh)</Unit>
        <Value>0</Value>
        <Timestamp>2021-02-08T18:34:01</Timestamp>
    </DataRecord>

    <DataRecord id="35">
        <Function>Instantaneous value</Function>
        <Unit>Energy (kWh)</Unit>
        <Value>0</Value>
        <Timestamp>2021-02-08T18:34:01</Timestamp>
    </DataRecord>

    <DataRecord id="36">
        <Function>Instantaneous value</Function>
        <Unit>Energy (kWh)</Unit>
        <Value>0</Value>
        <Timestamp>2021-02-08T18:34:01</Timestamp>
    </DataRecord>

    <DataRecord id="37">
        <Function>Instantaneous value</Function>
        <Unit>Volume (1e-2  m^3)</Unit>
        <Value>194644</Value>
        <Timestamp>2021-02-08T18:34:01</Timestamp>
    </DataRecord>

    <DataRecord id="38">
        <Function>Instantaneous value</Function>
        <Unit>Time Point (time &amp; date)</Unit>
        <Value>2021-02-08T16:09:00</Value>
        <Timestamp>2021-02-08T18:34:01</Timestamp>
    </DataRecord>

    <DataRecord id="39">
        <Function>Manufacturer specific</Function>
        <Value>21 04 00 10 A0</Value>
        <Timestamp>2021-02-08T18:34:01</Timestamp>
    </DataRecord>

</MBusData>

Из этого массива мне нужны только эти:

 <DataRecord id="2">
        <Function>Instantaneous value</Function>
        <Unit>Energy (MJ)</Unit>
        <Value>34732</Value>
        <Timestamp>2021-02-08T18:34:01</Timestamp>
    </DataRecord>

<DataRecord id="4">
        <Function>Instantaneous value</Function>
        <Unit>Power (100 W)</Unit>
        <Value>34</Value>
        <Timestamp>2021-02-08T18:34:01</Timestamp>
    </DataRecord>

    <DataRecord id="5">
        <Function>Instantaneous value</Function>
        <Unit>Volume flow (m m^3/h)</Unit>
        <Value>192</Value>
        <Timestamp>2021-02-08T18:34:01</Timestamp>
    </DataRecord>

    <DataRecord id="6">
        <Function>Instantaneous value</Function>
        <Unit>Flow temperature (deg C)</Unit>
        <Value>64</Value>
        <Timestamp>2021-02-08T18:34:01</Timestamp>
    </DataRecord>

    <DataRecord id="7">
        <Function>Instantaneous value</Function>
        <Unit>Return temperature (deg C)</Unit>
        <Value>49</Value>
        <Timestamp>2021-02-08T18:34:01</Timestamp>
    </DataRecord>

    <DataRecord id="8">
        <Function>Instantaneous value</Function>
        <Unit>Temperature Difference (1e-1  deg C)</Unit>
        <Value>155</Value>
        <Timestamp>2021-02-08T18:34:01</Timestamp>
    </DataRecord>

  <DataRecord id="11">
        <Function>Instantaneous value</Function>
        <Unit>Fabrication number</Unit>
        <Value>68924134</Value>
        <Timestamp>2021-02-08T18:34:01</Timestamp>
    </DataRecord>

Как из этого всего можно сделать счетчик в GUI WB аналогичный вашему?

https://wirenboard.com/wiki/images/7/71/WB-MAP3H_webui_devices.png

Тут надо с одной стороны создать в MQTT “структуру” под данные. Делается это например виртуальным устройством wb-rules. И из того же скрипта запускать скомпилированную программ, парсить ее вывод и записывать в поля. Что подсказать?

А что за счётчик тепла у вас?

Так получается? Или в чем-нибудь помочь?

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

Вот такой

Именно такого - нет, но могу написать “шаблон” скрипта, который можно использовать.

1 лайк

Я был бы вам категорично признателен и готов сделать донат в удобной вам форме )

Донат - не надо, общим делом заняты :wink:
Но сегодня не успеваю. Завтра напишу.

1 лайк

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

//02_15_test_02.js
 
defineVirtualDevice("mbus", {
  title: "Mbus OUT", //
  cells: {
    Energy : {
        type : "text",
        value : "",
        readonly: false,
    },
    Power : {
        type : "text",
        value : "",
        readonly: false,
    },
  }
});


//var oParser = new DOMParser();



log.info ("START 02_15_test_02.js")
// Запуск shell-команды с захватом вывода
    runShellCommand("ls /etc", //сюда и записываем "mbus-serial-request-data /dev/ttyRS485-2 -d"
        {
      captureOutput: true, //Захватывать stdout
      captureErrorOutput: true, //Захватывать stderr (если нужно)
      exitCallback: function (exitCode, capturedOutput, capturedErrorOutput) //Функция, в которую попадает вывод
            {
                log("cmd output: " + capturedOutput); //строка полностью
                capturedArray = capturedOutput.split("\n"); //Разбиваем полученную строку по символу переноса строки.
                capturedArray.forEach(function(item, index){ //Для каждой строки
                  var tmpstring = item.trim(); //порежем пробелы
                  switch(tmpstring) {
                    case "<Unit>Energy (MJ)</Unit>": //Одно из условий
                      dev["mbus"]["Energy"] = capturedArray[index+1] //Выводим СЛЕДУЮЩУЮ строку в поле. ну и обработать как надо, если надо.
                    case "<Unit>Power (100 W)</Unit>": //Одно из условий
                      //log.info("index", index)
                      dev["mbus"]["Power"] = capturedArray[index+1] //ну и обработать как надо
                      //log.info(capturedArray[index+1])
                  }
                })
                log("cmd Erroroutput: " + capturedErrorOutput); //Если нужен вывод  stderr
            }
         })

Вот пример как раз нужного. Упаковать запуск внешнего приложения и парсинг в функцию - и вызывать по таймеру.

1 лайк

Все получилось, но пришлось обратится к товарищу который явно больше разбирается в программировании чем я )))

Meter.js
var MBUS_SERIAL = '/usr/local/bin/mbus-serial-request-data'
var XMLLINTER = '/usr/bin/xmlstarlet'
var DEVICE = '/dev/ttyRS485-2'

var METRICS = {
    2: {
        name: 'Energy',
        multiplier: 0.000239,
    },
    4: {
        name: 'CurrentPower',
        multiplier: 100
    },
    5: {
        name: 'VolumeFlow',
        multiplier: 0.001
    },
    6: {
        name: 'FlowTemperature',
        multiplier: 1
    },
    7: {
        name: 'ReturnTemperature',
        multiplier: 1
    },
    8: {
        name: 'TemperatureDifference',
        multiplier: 0.1
    },
    11: {
        name: 'FabricationNumber',
        multiplier: 1
    }
}

defineVirtualDevice("ultraheat", {
    title: "Ultraheat T550 (UH50)",
    cells: {
        Energy: {
            type: "heat_energy",
            value: 0
        },
        CurrentPower: {
            type: "power",
            value: 0
        },
        VolumeFlow: {
            type: "water_flow",
            value: 0
        },
        FlowTemperature: {
            type: "temperature",
            value: 0
        },
        ReturnTemperature: {
            type: "temperature",
            value: 0
        },
        FabricationNumber: {
            type: "value",
            value: 0
        },
        TemperatureDifference: {
            type: "temperature",
            value: 0
        }
    }
});

defineRule('ultraheat_cron', {
    when: cron('@every 600s'), // interval
    then: function () {
        var mbusCmd = MBUS_SERIAL + " " + DEVICE + " -d | " + XMLLINTER + " sel -T -t -v '/MBusData/DataRecord/Value' -n";
     runShellCommand(mbusCmd, {
            captureOutput: true,
            exitCallback: function (exitCode, capturedOutput) {
                // log.info('ultraheat: var captureOutput: ' + capturedOutput);

                capturedArray = capturedOutput.split("\n");
                for (var id in METRICS) {
                    var metricName = METRICS[id]['name'];
                    var metricValue = capturedArray[id];
                    dev.ultraheat[metricName] = Number(metricValue) * METRICS[id]['multiplier'];
                    // log.info('ultraheat: var captureOutput metric[' + metricName + ']: ' + metricValue);
                }
            }
        });
    }
});

1 лайк

Товарищу - респект, очень элегантно распарсил вывод, решение намного красивее чем у меня.

1 лайк

Получил вот такой адаптер MBUS - USB
Подправил в конфиге - все работает!

Покупал здесь:

1 лайк

Отлично!
И, если можно - выложите сюда же инструкции по сбрке самого софта.