Navigation

    Logo
    • Register
    • Login
    • Search
    • Recent
    • Tags
    • Unread
    • Categories
    • Unreplied
    • Popular
    • GitHub
    • Docu
    • Hilfe
    1. Home
    2. Русский
    3. ioBroker
    4. Скрипты
    5. ioBroker скрипты
    6. Скрипт для датчика CO2 MH-Z14 (MH-Z19)

    NEWS

    • 15. 05. Wartungsarbeiten am ioBroker Forum

    • Monatsrückblick - April 2025

    • Minor js-controller 7.0.7 Update in latest repo

    Скрипт для датчика CO2 MH-Z14 (MH-Z19)

    This topic has been deleted. Only users with topic management privileges can see it.
    • A
      andrey99986 last edited by

      Датчик:

      https://ru.aliexpress.com/item/Free-shi … 6141ebe467

      Адаптер:

      https://ru.aliexpress.com/item/FT232RL- ... 0.0.DBxfZO

      
      var device_port = '/dev/ttyUSB2';
      var buflen = 64;
      var sleep_time = 200; // Sleep time between request and wait for response.
      var SerialPort = require('serialport');
      var ByteLength = SerialPort.parsers.ByteLength;
      var ppm;
      
      var cmd_init = new Buffer ([0xFF, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79]);
      var cmd_set_zero = new Buffer ([0xFF, 0x01, 0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78]);
      
      function toHexString(byteArray) {
        return Array.from(byteArray, function(byte) {
          return ('0' + (byte & 0xFF).toString(16)).slice(-2);
        }).join('');
      }
      
      function co2_gd(cmd,buflen,callback)
      {
      
          var port = new SerialPort(device_port,{
          baudrate: 9600,
          dataBits: 8,
          parity: 'none'
          });
          const parser = port.pipe(new ByteLength({length: buflen}));
          port.pipe(parser);
          port.write(cmd);
          setTimeout(readport, sleep_time);
          function readport () {
              parser.on ('data', function (result) { 
                     ppm = null;
                     var CRC_calc=0;
                      var b2 = parseInt(toHexString(result.slice(3,4)),16);
                      var b3 = parseInt(toHexString(result.slice(5,6)),16);
                      var b4 = parseInt(toHexString(result.slice(7,8)),16);
                      var b5 = parseInt(toHexString(result.slice(9,10)),16);
                      var b6 = parseInt(toHexString(result.slice(11,12)),16);
                      var b7 = parseInt(toHexString(result.slice(13,14)),16);
                      var b8 = parseInt(toHexString(result.slice(15,16)),16);
                      var CRC_get = parseInt(toHexString(result.slice(17,18)),16);
                      CRC_calc = (255 - (b2 + b3 + b4 + b5 + b6 + b7 + b8) % 256) + 1;
                      if (CRC_get != CRC_calc)
                          {
                          console.log ('CRC ERROR');
                          console.log ('result='+JSON.stringify(result));
                          console.log('b='+b2+' '+b3+' '+b4+' '+b5+' '+b6+' '+b7+' '+b8 );    
                          console.log('CRC_get='+(CRC_get));
                          console.log('CRC_calc='+(CRC_calc));
                          }
                      else
                          {
                          //console.log ('CRC CO2 is  OK');
                          //console.log ('result='+JSON.stringify(result));
                          //console.log('b='+b2+' '+b3+' '+b4+' '+b5+' '+b6+' '+b7+' '+b8 );
                          //console.log('CRC_get='+(CRC_get));
                          //console.log('CRC_calc='+(CRC_calc));  
                          var Hibyte = toHexString(result.slice(5,6));
                          var Lowbyte = toHexString(result.slice(7,8));
                          ppm = parseInt(Hibyte,16)*256+parseInt(Lowbyte,16);
                          //console.log('Hibyte='+Hibyte);
                          //console.log('Lowbyte='+Hibyte);
                          //console.log('ppm='+ppm);
                          if (ppm> 5000 )
                              {
                                  console.log ('CRC OK');
                                  console.log('Hibyte='+Hibyte);
                                  console.log('Lowbyte='+Hibyte);
                                  console.log('ppm='+ppm);
                                  console.log ('result='+JSON.stringify(result));
                                  console.log('b='+b2+' '+b3+' '+b4+' '+b5+' '+b6+' '+b7+' '+b8 );
                                  console.log('CRC_get='+(CRC_get));
                                  console.log('CRC_calc='+(CRC_calc));   
                                  ppm = null;
                              }
      
                          }
                      if (callback && typeof(callback) === "function") {
                      callback(ppm);
                      } 
      
              }); //parser.on
              port.pause();
              port.close();
              return (ppm);
          }
      
      }  //end function co2_gd
      
      //co2_gd(cmd_set_zero,18, function(data) {} ); //Set CO2 level as zero  (400 ppm)
      
      schedule("* * * * *", function () {
          co2_gd(cmd_init,18, function(data) { 
              //console.log('CO2 ppm='+data);
              setState("javascript.0.CO2_1f_uart",data);
          });
      });
      
      
      1 Reply Last reply Reply Quote 0
      • A
        artko last edited by

        Не работает.

        8:10:37.273 [info] javascript.0 Start javascript script.js.common.co2_mh_z19

        18:10:37.274 [info] javascript.0 script.js.common.co2_mh_z19: registered 0 subscriptions and 1 schedule

        18:11:00.281 [info] javascript.0 script.js.common.co2_mh_z19: request={"type":"Buffer","data":[255,1,134,0,0,0,0,0,121]}

        18:11:00.508 [info] javascript.0 script.js.common.co2_mh_z19: –-----------------

        18:11:00.509 [info] javascript.0 script.js.common.co2_mh_z19: CRC ERROR

        18:11:00.510 [info] javascript.0 script.js.common.co2_mh_z19: result={"type":"Buffer","data":[255,255,134,2,142,86,134,2,142,86,4,4,58,58,137,137,205,205]}

        18:11:00.510 [info] javascript.0 script.js.common.co2_mh_z19: b=2 86 2 86 4 58 137

        18:11:00.510 [info] javascript.0 script.js.common.co2_mh_z19: CRC_get=205

        18:11:00.511 [info] javascript.0 script.js.common.co2_mh_z19: CRC_calc=137

        Добавлял отладочный вывод запросов - такое впечатление, что отсылается команда чтения два раза и потом в буфере приемном все перемешано, вот и лажа.

        1 Reply Last reply Reply Quote 0
        • A
          artko last edited by

          А никому не приходилось бороться со странными зависами при setTimeout в скриптах?

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

            console.log('wait response');
                      setTimeout(readport, 200);
                      function readport() {
                                                  console.log('readport enter');   
          
          

          в логе вижу первый вывод в консоль - и все, глухой вис. в top висит процесс iobroker.javascript с 100% загрузкой, драйвер javascript в панели тоже останавливается. Приходится вручную процесс убивать.

          Иногда по непонятной причине - проходит, результат получается нормально.

          1 Reply Last reply Reply Quote 0
          • A
            andrey99986 last edited by

            @artko:

            Не работает.

            CRC ERROR

            18:11:00.510 [info] javascript.0 script.js.common.co2_mh_z19: result={"type":"Buffer","data":[255,255,134,2,142,86,134,2,142,86,4,4,58,58,137,137,205,205]}

            Добавлял отладочный вывод запросов - такое впечатление, что отсылается команда чтения два раза и потом в буфере приемном все перемешано, вот и лажа. `

            Дело в том что мне попадались 2 типа USB-Uart адаптера.

            В первом случае ответы дублируются побайтно, а во втором - ответ дублируется целиком.

            При чём у разных адаптеров разный % CRC Error.

            В вашем случае побайтный дубль (как у меня) и видно - что идёт сбой ответа - не все байты попарно одинаковы.

            Длина кабеля?

            Уверены что нет просадки напряжения на самом датчике в моменты ИК-свечения (ток вроде 300мА)?

            Какой у вас адаптер?

            В первые пару минут - CRC error это нормально.

            Попробуйте другой адаптер.

            У меня на таком FTDI_FT232R_USB_UART_AH05SK6S CRC ошибок менее ~3 %

            P.S.Мой скрипт написан для MH-Z14, на MH-Z19 ещё не проверял. Скоро проверю, сам датчик уже есть. Судя по документации логика абсолютно одинаковая.

            1 Reply Last reply Reply Quote 0
            • A
              andrey99986 last edited by

              @artko:

              А никому не приходилось бороться со странными зависами при setTimeout в скриптах?

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

                console.log('wait response');
                          setTimeout(readport, 200);
                          function readport() {
                                                      console.log('readport enter');   
              
              

              в логе вижу первый вывод в консоль - и все, глухой вис. в top висит процесс iobroker.javascript с 100% загрузкой, драйвер javascript в панели тоже останавливается. Приходится вручную процесс убивать.

              Иногда по непонятной причине - проходит, результат получается нормально. `
              Какая OS?

              Сколько свободной памяти показывает iobroker?

              1 Reply Last reply Reply Quote 0
              • A
                artko last edited by

                @andrey99986:

                Дело в том что мне попадались 2 типа USB-Uart адаптера.

                В первом случае ответы дублируются побайтно, а во втором - ответ дублируется целиком.

                При чём у разных адаптеров разный % CRC Error.

                В вашем случае побайтный дубль (как у меня) и видно - что идёт сбой ответа - не все байты попарно одинаковы.

                Длина кабеля?

                Уверены что нет просадки напряжения на самом датчике в моменты ИК-свечения (ток вроде 300мА)?

                Какой у вас адаптер?

                В первые пару минут - CRC error это нормально.

                Попробуйте другой адаптер.

                У меня на таком FTDI_FT232R_USB_UART_AH05SK6S CRC ошибок менее ~3 %

                P.S.Мой скрипт написан для MH-Z14, на MH-Z19 ещё не проверял. Скоро проверю, сам датчик уже есть. Судя по документации логика абсолютно одинаковая. `

                адаптер прямо в порту торчит. чип CP2102. датчик - проводочки сантиметров пять. Просадку не смотрел. Два разных адаптера (одинаковых, впрочем, по чипу и схеме).

                Скрипт на питоне - работает как из пушки. Ни одной ошибки.

                import MySQLdb
                import string
                import time
                import serial
                
                from datetime import datetime
                
                ser = serial.Serial('/dev/ttyUSB0',
                                      baudrate=9600,
                                      bytesize=serial.EIGHTBITS,
                                      parity=serial.PARITY_NONE,
                                      stopbits=serial.STOPBITS_ONE,
                                      timeout=1.0)
                result=ser.write("\xff\x01\x86\x00\x00\x00\x00\x00\x79")
                s=ser.read(9)
                if s[0] == "\xff" and s[1] == "\x86":
                  co2 = ord(s[2])*256 + ord(s[3])
                
                print "co2=", co2
                
                ts = time.time()
                ts1 = int(ts * 1000)
                print "ts=", ts1
                
                db = MySQLdb.connect(host="localhost", user="xxxx", passwd="xxxxx", db="iobroker", charset="utf8")
                cursor = db.cursor()
                sql = """insert iobroker.ts_number(id, ts, val, ack, _from, q) values (12,%(ts)s,%(val)s,0,2,0) """ %{"ts":ts1, "val":co2}
                print "sql=", sql
                cursor.execute(sql)
                db.commit()
                db.close()
                
                
                1 Reply Last reply Reply Quote 0
                • A
                  artko last edited by

                  @andrey99986:

                  Какая OS?

                  Сколько свободной памяти показывает iobroker? `

                  Ubuntu 16.04LTS.

                  Всего RAM - Используется: 325 Мб / Свободно: 176 Мб (9%) [Сервер: atom-nb - 9 процессов]

                  %Cpu(s): 8,0 us, 2,0 sy, 0,0 ni, 87,0 id, 3,0 wa, 0,0 hi, 0,0 si, 0,0 st

                  КиБ Mem : 2050484 total, 179628 free, 520800 used, 1350056 buff/cache

                  КиБ Swap: 8269820 total, 8203072 free, 66748 used. 1233352 avail Mem

                  1 Reply Last reply Reply Quote 0
                  • A
                    andrey99986 last edited by

                    @artko:

                    @andrey99986:

                    Какая OS?

                    Сколько свободной памяти показывает iobroker? `

                    Ubuntu 16.04LTS.

                    Всего RAM - Используется: 325 Мб / Свободно: 176 Мб (9%) [Сервер: atom-nb - 9 процессов]

                    %Cpu(s): 8,0 us, 2,0 sy, 0,0 ni, 87,0 id, 3,0 wa, 0,0 hi, 0,0 si, 0,0 st

                    КиБ Mem : 2050484 total, 179628 free, 520800 used, 1350056 buff/cache

                    КиБ Swap: 8269820 total, 8203072 free, 66748 used. 1233352 avail Mem `

                    У меня драйвер javascript при работе с ком-портами периодически самоперегружается, поэтому я скрипты работающие с ком-портами запускаю в дополнительной инстанции, чтобы сбой не повлиял на работу других скриптов. Причина где то в недрах библиотеки serialport nodejs. По идее надо дебажить и создавать issue на https://github.com/node-serialport/node … ort/issues

                    1 Reply Last reply Reply Quote 0
                    • A
                      andrey99986 last edited by

                      @artko:

                      адаптер прямо в порту торчит. чип CP2102. датчик - проводочки сантиметров пять. Просадку не смотрел. Два разных адаптера (одинаковых, впрочем, по чипу и схеме).

                      Скрипт на питоне - работает как из пушки. Ни одной ошибки. `

                      Попробуй поменять в коде на````
                      var buflen = 9;

                      Ещё вероятно причина в драйвере serialport. Видно же что ответ ненормальный идёт. Сделайте дебаг вывод ответа питона и сравните с nodejs.
                      
                      С питоном также дублированы байты ответа?
                      
                      Когда работает с портом iobroker (nodejs) - другие скрипты на уровне OS (питон) с этим портом не работают?
                      1 Reply Last reply Reply Quote 0
                      • A
                        artko last edited by

                        12:25:19.724 [info] javascript.0 script.js.common.Скрипт1: registered 0 subscriptions and 1 schedule

                        12:26:00.729 [error] javascript.0 at co2_gd (script.js.common.Скрипт1:20:16)

                        12:26:00.730 [error] javascript.0 at Object. (script.js.common.Скрипт1:93:5)

                        20 var port = new SerialPort(device_port,{

                        93 co2_gd(cmd_init,18, function(data) {

                        с питоном ничего не дублируется, с терминалкой тоже все ок. никаких других скриптов кроме этого вообще нет. питон на время экспериментов остановил.

                        похоже, что-то в недрах nodejs.serialport очень странно работает.

                        1 Reply Last reply Reply Quote 0
                        • A
                          andrey99986 last edited by

                          @artko:

                          с питоном ничего не дублируется, с терминалкой тоже все ок. никаких других скриптов кроме этого вообще нет. питон на время экспериментов остановил.

                          похоже, что-то в недрах nodejs.serialport очень странно работает. `

                          Посмотреть кто занял порт:

                           fuser /dev/ttyUSB1
                          

                          Иногда javascript driver надо перезапустить чтобы порт освободить.

                          Это не помогло?

                          var buflen = 9;
                          
                          1 Reply Last reply Reply Quote 0
                          • A
                            artko last edited by

                            @andrey99986:

                            Посмотреть кто занял порт:

                             fuser /dev/ttyUSB1
                            

                            Иногда javascript driver надо перезапустить чтобы порт освободить. `

                            никто не занимает, ну и проверяю в процессах - уже вижу, если висит io.javascript c 100% загрузкой ядра - то ой. почему-то вешается именно при ожидании данных.

                            сделал себе вот такой вариант скрипта для проверки по этапам:

                            `createState('CO2_UART');
                            
                            var device_port = '/dev/ttyUSB0';
                            var buflen = 64;
                            var sleep_time = 200; // Sleep time between request and wait for response.
                            var SerialPort = require('serialport');
                            var ByteLength = SerialPort.parsers.ByteLength;
                            var ppm;
                            
                            var cmd_init = new Buffer ([0xFF, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79]);
                            var cmd_set_zero = new Buffer ([0xFF, 0x01, 0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78]);
                            //var cmd_abc_off = new Buffer ([0xFF, 0x01, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86]);
                            //var cmd_abc_on= new Buffer ([0xFF, 0x01, 0x79, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xE6]);
                            
                            function co2_gd(cmd,buflen,callback)
                            {
                            
                                var port = new SerialPort(device_port,{
                                baudRate: 9600,
                                dataBits: 8,
                                parity: 'none',
                                autoOpen: false
                                });
                            
                                port.open(function (err) {
                                    if (err) {
                                        return console.log('Error opening port: ', err.message);
                                    }
                                    console.log('port opened');
                                    console.log ('request='+JSON.stringify(cmd));
                            
                                    const parser = port.pipe(new ByteLength({length: buflen}));
                                    port.pipe(parser);
                            
                                    port.write(cmd, function(err) {
                                        if (err) {
                                            return console.log('Error on write: ', err.message);
                                        }
                                        console.log('message written');
                                        const parser = port.pipe(new ByteLength({length: buflen}));
                                        port.pipe(parser);
                            
                                        console.log('wait response');
                            
                                        setTimeout(readport, 200);
                                        function readport() {
                                                                    console.log('readport enter');      
                                                                    parser.on ('data', function (result) { 
                                                                    console.log ('result='+JSON.stringify(result));
                                                                    var i = 0;
                                                                    while (i < 18)
                                                                    {
                                              if (result[i] == result[i+1])
                                              {
                                                  i += 2;
                                              }
                                              else
                                              {
                                                  if ((i + 2) < 18)
                                                  {
                                                      if (result[i] == result[i+2])
                                                      {
                                                          console.log ('fix data at position ' + i);
                                                          result[i+2] = result[i+1];
                                                          result[i+1] = result[i];
                                                          i += 2;
                                                      }
                                                  }
                                              }
                                             console.log('fix cycle ' + i);
                                            }
                            
                                                                    ppm = null;
                                                                    var CRC_calc=0;
                                                                    var CRC_get = result[16];
                                                                    CRC_calc = (255 - (result[2] + result[4] + result[6] + result[8] + result[10] + result[12] + result[14]) % 256) + 1;
                                                                    if (CRC_get != CRC_calc)
                                                                    {
                                                console.log ('CRC ERROR');
                                                console.log('CRC_get='+(CRC_get));
                                                console.log('CRC_calc='+(CRC_calc));
                                                }
                                                                    else
                                                                    {
                                                        ppm = result[4] * 256 + result[6];
                                                        console.log('ppm='+ppm);
                                                        if (ppm> 5000 )
                                                        {
                                                            console.log ('CRC OK');
                                                            console.log('ppm='+ppm);
                                                            console.log('CRC_get='+(CRC_get));
                                                            console.log('CRC_calc='+(CRC_calc));   
                                                            ppm = null;
                                                        }
                                                }
                                                                    if (callback && typeof(callback) === "function") {
                                                                        callback(ppm);
                                                                    } 
                                                                    port.pause();
                                                                    port.close();
                                                                    return (ppm);
                                                                })
                                        }
                                        });
                                });
                            
                            }  //end function co2_gd
                            
                            //co2_gd(cmd_set_zero,18, function(data) {} ); //Set CO2 level as zero  (400 ppm)
                            
                            schedule("*/15 * * * * *", function () {
                                console.log('co2 request');
                                co2_gd(cmd_init,18, function(data) { 
                                    //console.log('CO2 ppm='+data);
                                    setState("CO2_UART",data);
                                });
                            });` 
                            
                            ~~[quote]~~
                            Это не помогло?
                            `~~[code]~~var buflen = 9;[/code]` `  ` 
                            
                            неа, в таком виде как скрипт из первого сообщения - вообще не хочет работать. с ошибками.[/i][/i][/i]
                            
                            1 Reply Last reply Reply Quote 0
                            • A
                              andrey99986 last edited by

                              @artko:

                              Скрипт на питоне - работает как из пушки. Ни одной ошибки. `
                              Что-то не видно проверки CRC на питоне. Понятно что без проверки ошибок нет 🙂

                              1 Reply Last reply Reply Quote 0
                              • A
                                artko last edited by

                                @andrey99986:

                                @artko:

                                Скрипт на питоне - работает как из пушки. Ни одной ошибки. Что-то не видно проверки CRC на питоне. Понятно что без проверки ошибок нет :)

                                то был первый вариант 🙂 питон принимает строго нужное количество байт, crc совпадает 🙂

                                1 Reply Last reply Reply Quote 0
                                • A
                                  andrey99986 last edited by

                                  @artko:

                                  то был первый вариант 🙂 питон принимает строго нужное количество байт, crc совпадает 🙂 `
                                  CRC вычисляется в именно в строгом количестве байт, смотрите даташит на датчик. В вашем коде на питоне проверки CRC нет.

                                  1 Reply Last reply Reply Quote 0
                                  • A
                                    artko last edited by

                                    @andrey99986:

                                    @artko:

                                    то был первый вариант 🙂 питон принимает строго нужное количество байт, crc совпадает 🙂 CRC вычисляется в именно в строгом количестве байт, смотрите даташит на датчик. В вашем коде на питоне проверки CRC нет.

                                    я же написал, то был первый вариант….

                                    import MySQLdb
                                    import string
                                    import time
                                    import serial
                                    
                                    from datetime import datetime
                                    
                                    ser = serial.Serial('/dev/ttyUSB0',
                                                          baudrate=9600,
                                                          bytesize=serial.EIGHTBITS,
                                                          parity=serial.PARITY_NONE,
                                                          stopbits=serial.STOPBITS_ONE,
                                                          timeout=1.0)
                                    result=ser.write("\xff\x01\x86\x00\x00\x00\x00\x00\x79")
                                    s=ser.read(9)
                                    
                                    str = ""
                                    for ch in s:
                                    	str += hex(ord(ch))+ " "
                                    print str
                                    crc_get = ord(s[8])
                                    crc_calc = (255 - (ord(s[1]) + ord(s[2]) + ord(s[3]) + ord(s[4]) + ord(s[5]) + ord(s[6]) + ord(s[7]))) % 256 + 1
                                    print "crc calc=" + hex(crc_calc) + " crc get=" + hex(crc_calc)
                                    if s[0] == "\xff" and s[1] == "\x86" and crc_calc == crc_get:
                                       co2 = ord(s[2])*256 + ord(s[3])  
                                       print "crc ok"
                                    else:
                                       co2 = 0
                                       print "crc error"
                                    print "co2=", co2
                                    
                                    ts = time.time()
                                    ts1 = int(ts * 1000)
                                    print "ts=", ts1
                                    
                                    db = MySQLdb.connect(host="localhost", user="xxxxxxx", passwd="xxxxxxx", db="iobroker", charset="utf8")
                                    cursor = db.cursor()
                                    sql = """insert iobroker.ts_number(id, ts, val, ack, _from, q) values (12,%(ts)s,%(val)s,0,2,0) """ %{"ts":ts1, "val":co2}
                                    print "sql=", sql
                                    cursor.execute(sql)
                                    db.commit()
                                    db.close()
                                    
                                    

                                    вывод исполнения

                                    0xff 0x86 0x1 0xca 0x57 0x40 0x28 0x58 0x98

                                    crc calc=0x98 crc get=0x98

                                    crc ok

                                    co2= 458

                                    ts= 1514450008318

                                    sql= insert iobroker.ts_number(id, ts, val, ack, _from, q) values (12,1514450008318,458,0,2,0)

                                    1 Reply Last reply Reply Quote 0
                                    • First post
                                      Last post

                                    Support us

                                    ioBroker
                                    Community Adapters
                                    Donate

                                    573
                                    Online

                                    31.6k
                                    Users

                                    79.4k
                                    Topics

                                    1.3m
                                    Posts

                                    2
                                    16
                                    2765
                                    Loading More Posts
                                    • Oldest to Newest
                                    • Newest to Oldest
                                    • Most Votes
                                    Reply
                                    • Reply as topic
                                    Log in to reply
                                    Community
                                    Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen
                                    The ioBroker Community 2014-2023
                                    logo