Skip to content
  • Home
  • Aktuell
  • Tags
  • 0 Ungelesen 0
  • Kategorien
  • Unreplied
  • Beliebt
  • GitHub
  • Docu
  • Hilfe
Skins
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Standard: (Kein Skin)
  • Kein Skin
Einklappen
ioBroker Logo

Community Forum

donate donate
  1. ioBroker Community Home
  2. Русский
  3. ioBroker
  4. Скрипты
  5. ioBroker скрипты
  6. Построение графиков ChartJS на сервере и отправка картинки в телеграм

NEWS

  • Neuer Blogbeitrag: Monatsrückblick - Dezember 2025 🎄
    BluefoxB
    Bluefox
    10
    1
    320

  • Weihnachtsangebot 2025! 🎄
    BluefoxB
    Bluefox
    24
    1
    1.5k

  • UPDATE 31.10.: Amazon Alexa - ioBroker Skill läuft aus ?
    apollon77A
    apollon77
    48
    3
    9.5k

Построение графиков ChartJS на сервере и отправка картинки в телеграм

Geplant Angeheftet Gesperrt Verschoben ioBroker скрипты
22 Beiträge 4 Kommentatoren 7.4k Aufrufe 1 Watching
  • Älteste zuerst
  • Neuste zuerst
  • Meiste Stimmen
Antworten
  • In einem neuen Thema antworten
Anmelden zum Antworten
Dieses Thema wurde gelöscht. Nur Nutzer mit entsprechenden Rechten können es sehen.
  • goofykG Offline
    goofykG Offline
    goofyk
    schrieb am zuletzt editiert von
    #13

    Какая версия Nodejs?

    1 Antwort Letzte Antwort
    1
    • T Offline
      T Offline
      TechElCo
      schrieb am zuletzt editiert von
      #14

      Хистори.0… Не знаю, как вставить картинку :( Ноде 8.12.0

      Щас код такой:

      `'use strict';
      const ChartjsNode = require('chartjs-node');
      
      /*** Вспомогательные функции (взяты из js-controller) ***/
      
      /**
       * Puts all values from an `arguments` object into an array, starting at the given index
       * @param {IArguments} argsObj An `arguments` object as passed to a function
       * @param {number} [startIndex=0] The optional index to start taking the arguments from
       */
      function sliceArgs(argsObj, startIndex) {
          if (startIndex === null) startIndex = 0;
          const ret = [];
          for (let i = startIndex; i < argsObj.length; i++) {
              ret.push(argsObj[i]);
          }
          return ret;
      }
      
      /**
       * Promisifies a function which does not provide an error as the first argument in its callback
       * @param {Function} fn The function to promisify
       * @param {any} [context] (optional) The context (value of `this` to bind the function to)
       * @param {string[]} [returnArgNames] (optional) If the callback contains multiple arguments, 
       * you can combine them into one object by passing the names as an array. 
       * Otherwise the Promise will resolve with an array
       * @returns {(...args: any[]) => Promise<any>}
       */
      function promisifyNoError(fn, context, returnArgNames) {
          return function () {
              const args = sliceArgs(arguments);
              context = context || this;
              return new Promise(function (resolve, reject) {
                  fn.apply(context, args.concat([
                      function (result) {
                          // decide on how we want to return the callback arguments
                          switch (arguments.length) {
                              case 0: // no arguments were given
                                  return resolve(); // Promise <void>case 1: // a single value (result) was returned
                                  return resolve(result);
                              default: // multiple values should be returned
                                  /** @type {{} | any[]} */
                                  let ret;
                                  const extraArgs = sliceArgs(arguments, 0);
                                  if (returnArgNames && returnArgNames.length === extraArgs.length) {
                                      // we can build an object
                                      ret = {};
                                      for (let i = 0; i < returnArgNames.length; i++) {
                                          ret[returnArgNames[i]] = extraArgs[i];
                                      }
                                  } else {
                                      // we return the raw array
                                      ret = extraArgs;
                                  }
                                  return resolve(ret);
                          }
                      }
                  ]));
              });
          };
      }
      
      /**
       * функция sendTo как Promise, чтобы удобно было строить цепочки
      */
      var sendToPromise = promisifyNoError(sendTo);
      
      // константы для цветов
      const chartColors = {
          black: 'rgb(0, 0, 0)',
      	red: 'rgb(255, 99, 132)',
      	orange: 'rgb(255, 159, 64)',
      	yellow: 'rgb(255, 205, 86)',
      	green: 'rgb(75, 220, 150)',
      	blue: 'rgb(54, 162, 235)',
      	purple: 'rgb(153, 102, 255)',
      	grey: 'rgb(201, 203, 207)'
      };
      
      /**
       * функция рисования и сохранения картинки в файл
       *  параметры:
       *  @param config - конфигурация графика для рисования
       *  @param filename - имя файла для сохранения
       *  результат:
       *  @param Promise - успешное сохранение файла
       */
      
      function doDraw(config, filename) {
          // создадим полотно с размером 640x480 пикселей
          var chartNode = new ChartjsNode(640, 480);
          return chartNode.drawChart(config)
              .then(() => {
                  // запишем результат в файл
                  return chartNode.writeImageToFile('image/png', filename);
              });
      }
      
      /**
       * функция подготовки параметров для ChartJS.
       *  результат:
       *  @param Promise - успешная подготовка параметров
       */
      
      function prepareDraw0(hours){
          // вычислим интервал времени, за который надо получить данные
          const end = new Date().getTime(),
                start = end - 3600000*(hours || 1); // 1 = час назад
      
          // переменная, куда сохраним данные
          var пример;
          // создадим Promise сборки данных и конфигурации
          return new Promise((resolve, reject)=>{resolve()})
              // здесь могут быть много шагов сбора данных, прежде чем перейти к графику
              .then(()=>{
                  return sendToPromise('history.0', 'getHistory', {
                          id: 'mqtt.0.Borovoe1.bmet',
                          options: {
                              start: start,
                              end: end,
                              aggregate: 'onchange'
                      }
                  })
                  .then((result) => {
                      // записываем результат в переменную 'пример'
                      пример = result.result;
                  });
              })
      
         // финальный шаг - создаем конфигурацию графиков
              .then(()=>{
                  const chartJsOptions = {
                      // тип графика - линейный
                      type: 'line',
          			data: {
          			    // список наборов данных
          				datasets: [
          			    {
          			        // заголовок ряда 
          					label: 'проба',
          					// цвет
          					backgroundColor: chartColors.green,
          					borderColor: chartColors.green,
          					// размер точек
          					pointRadius: 3,
          					// ширина линии графика
          					borderWidth: 3,
          					// достанем данные из переменной 'пример' и оставим только значение и время изменения
          					data: пример.map((item) => {
          					    return {y: item.val, t: new Date(item.ts)}
          					}),
          					// заливка графика - нет
          					fill: false,
          			    }
          				]
          			},
          			options: {
          				// настройка легенды
          				legend: {
          				    labels: {
          				        // размер шрифта
          				        fontSize: 24,
          				    },
          				},
          				// оси координат
          				scales: {
          				    // оси X
          					xAxes: [{
          					    // тип - временная ось
          					    type: 'time',  
          						display: true,
          						// метка оси
          						scaleLabel: {
          							display: true,
          							labelString: 'Время'
          						},
          					}],
          					// оси Y
          					yAxes: [{
          					    // тип - линейная
          					    type: 'linear',
          						display: true,
          						// метка оси
          						scaleLabel: {
          							display: true,
          							labelString: 'Температура'
          						},
          					}]
          				}
          			}
      			};
      			return chartJsOptions;
              });
      }
      
      /**
       * функция отправки графика в телеграм
       * @param user - какому юзеру слать. если пусто - всем
       * @param chat_id - 
       * @param message_id - в каком чате и какое сообщение заменить при обновлении
       * @param hours - количество часов, за которые получить данные
       */
      
      //**************************************************************************************
      function sendGraph0(user, chat_id, message_id, hours){
          // имя файла, в который положим картинку с графиком
          const filename = '/tmp/graph0.png';
          hours = hours || 1;
          // выполним подготовку данных 
          prepareDraw0(hours)
              // на след шаге нарисуем
              .then((result) => {
                  // рисуем картинку по полученным данным и конфигурации
                  return doDraw(result, filename);
              })
             .then(() => {
                  // удалим предыдущее сообщение
                  if (message_id && chat_id) {
                      sendTo('telegram.0', {
                          user: user,
                          deleteMessage: {
                              options: {
                                  chat_id: chat_id, 
                                  message_id: message_id
                              }
                          }
                      });
                  }
              })
              .then(()=>{
                  // теперь отправим сообщение в телеграм
                  sendTo('telegram.0', {
                      user: user, 
                      text: filename, 
                      caption: 'Температура в курятниках ('+hours+'ч)',
                      reply_markup: {
                          inline_keyboard: [
                              [
                                  { text: '🔄', callback_data: 'graph_'+hours},
                                  { text: '1 ч', callback_data: 'graph_1' },
                                  { text: '2 ч', callback_data: 'graph_2' },
                                  { text: '4 ч', callback_data: 'graph_4' },
                                  { text: '12 ч', callback_data: 'graph_12' },
                                  { text: '24 ч', callback_data: 'graph_24' },
                              ]
                          ]
                      }
                  });
              });
      }
      
      // будем слушать телеграм и ждать команды на построение графика
      on({id: "telegram.0.communicate.request", ack: false, change: 'any'}, function (obj) {
          var v;
          var msg = obj.state.val;
          var command = obj.state.val.substring(obj.state.val.indexOf(']')+1);
          var user = obj.state.val.substring(obj.state.val.indexOf('[')+1,obj.state.val.indexOf(']'));
          var chat_id = getState("telegram.0.communicate.requestChatId").val;
          var message_id = getState("telegram.0.communicate.requestMessageId").val;
      
          // команда для графика - demo
          if (command.startsWith('demo')) {
              const hours = parseInt(command.split('_')[1]);
              sendGraph0(user, chat_id, message_id, hours);
          }
      });</void></any>`[/i][/i]
      
      1 Antwort Letzte Antwort
      0
      • goofykG Offline
        goofykG Offline
        goofyk
        schrieb am zuletzt editiert von
        #15

        Попробуй вот такую функцию, вместо той, что в скрипте

        function sendToPromise(adaper, cmd, params) {
            return new Promise((resolve, reject)=>{
                sendTo(adaper, cmd, params, (result) => {
                    resolve(result);
                });
            });
        }
        
        

        Обновил скрипт в первом посте, убрал оттуда вспомогательные функции и вставил эту функцию.

        1 Antwort Letzte Antwort
        1
        • T Offline
          T Offline
          TechElCo
          schrieb am zuletzt editiert von
          #16

          Так сработало, но до этого на месте этой функции было:

          /**
           * функция sendTo как Promise, чтобы удобно было строить цепочки
          */
          var sendToPromise = promisifyNoError(sendTo);
          

          Я думал, что тут что-то криво скопировалось…

          1 Antwort Letzte Antwort
          0
          • goofykG Offline
            goofykG Offline
            goofyk
            schrieb am zuletzt editiert von
            #17

            Уфф, разобрались.

            1 Antwort Letzte Antwort
            1
            • T Offline
              T Offline
              TechElCo
              schrieb am zuletzt editiert von
              #18

              Я, честно говоря, пока не разобрался 8-) Но мне ещё надо покурить много, а сегодня я урывками, на ходу, то с работы, то из дома пробовал код менять. Вечерком по изучаю, спасибо за помощь ;) Но вообще, у меня пока отдаёт картинку только за час, один раз, как то случайно отдал за 24 часа… Вот с таким логом : ` > telegram.0 2018-10-17 15:03:36.149 error Cannot send deleteMessage [chatId - 289938044]: Error: ETELEGRAM: 400 Bad Request: message can't be deleted

              javascript.1 2018-10-17 15:03:35.561 debug sendTo "send" to system.adapter.telegram.0 from system.adapter.javascript.1

              javascript.1 2018-10-17 15:03:35.560 info script.js.test.Скрипт3: sendTo(adapter=telegram.0, cmd=[object Object], msg=undefined)

              javascript.1 2018-10-17 15:03:35.559 debug sendTo "send" to system.adapter.telegram.0 from system.adapter.javascript.1

              javascript.1 2018-10-17 15:03:35.558 info script.js.test.Скрипт3: sendTo(adapter=telegram.0, cmd=[object Object], msg=undefined)

              javascript.1 2018-10-17 15:03:35.254 debug sendTo "getHistory" to system.adapter.history.0 from system.adapter.javascript.1

              javascript.1 2018-10-17 15:03:35.253 info script.js.test.Скрипт3: sendTo(adapter=history.0, cmd=getHistory, msg={"id":"mqtt.0.Borovoe1.bmet","options":{"start":1539774215252,"end":1539777815252,"aggregate":"onchange"}})

              javascript.1 2018-10-17 15:03:35.251 info script.js.test.Скрипт3: getState(id=telegram.0.communicate.requestMessageId, timerId=0) => {"val":19327,"ack":false,"ts":1539777815225,"q":0,"from":"system.adapter.telegram.0","lc":1539777815225}

              javascript.1 2018-10-17 15:03:35.249 info script.js.test.Скрипт3: getState(id=telegram.0.communicate.requestChatId, timerId=0) => {"val":289938044,"ack":false,"ts":1539777815213,"q":0,"from":"system.adapter.telegram.0","lc":1538911049076}

              telegram.0 2018-10-17 15:03:31.405 error Cannot send deleteMessage [chatId - 289938044]: Error: ETELEGRAM: 400 Bad Request: message can't be deleted `

              1 Antwort Letzte Antwort
              0
              • T Offline
                T Offline
                TechElCo
                schrieb am zuletzt editiert von
                #19

                @goofyk:

                Попробуй вот такую функцию, вместо той, что в скрипте

                function sendToPromise(adaper, cmd, params) {
                    return new Promise((resolve, reject)=>{
                        sendTo(adaper, cmd, params, (result) => {
                            resolve(result);
                        });
                    });
                }
                
                

                Обновил скрипт в первом посте, убрал оттуда вспомогательные функции и вставил эту функцию. `

                Поменял adaper на adapter, стало лучше )

                1 Antwort Letzte Antwort
                0
                • goofykG Offline
                  goofykG Offline
                  goofyk
                  schrieb am zuletzt editiert von
                  #20

                  @TechElCo:

                  Поменял adaper на adapter, стало лучше ) `

                  :)) Спасибо

                  1 Antwort Letzte Antwort
                  0
                  • S Offline
                    S Offline
                    Sergey777
                    schrieb am zuletzt editiert von
                    #21

                    А можно так, чтоб не на сервере графики строились? А как обычно, в браузере. Но как chartJS тогда совместить с histori драйвером?

                    1 Antwort Letzte Antwort
                    0
                    • goofykG goofyk

                      Расскажу, как можно получить график в виде картинки, например для отправки в Telegram

                      В ioBroker есть стандартный способ построения графиков - Flot-драйвер. Этот драйвер работает в паре с Web-драйвером и отображает результат в браузере. Но для того чтобы получить созданный график на сервере (в скрипте) в виде картинки нужен дополнительный драйвер PhantomJS, который делает “скриншот” страницы (на которой у нас нарисуется Flot-график).

                      Но я расскажу об альтернативном способе построения графиков на сервере в скрипте.

                      Есть такая библиотека Chart.js http://www.chartjs.org/ которая позволяет рисовать приятные на вид графики в браузере (примеры http://www.chartjs.org/samples/latest/).

                      Для рисования она использует “холст” (канва, canvas) браузера. Поэтому, чтобы рисовать с помощью этой библиотеки на сервере, нужно использовать “серверный” вариант “холста” и DOM-объекты. Это и делает пакет chartjs-node (https://github.com/vmpowerio/chartjs-node).

                      Основной зависимостью для этого пакета является пакет canvas (https://github.com/Automattic/node-canvas), который следует установить глобально (или в папку iobroker). Важно установить все зависимости для той платформы, куда вы ставите https://github.com/Automattic/node-canvas#compiling .

                      После этого можно в настройках драйвера javascript добавить модули chart.js, chartjs-node. Они должны установиться корректно, без ошибок. Иначе - разбираться с ошибками и решать их.

                      А дальше, можно написать скрипт.

                      Ниже приведен скрипт для примера, т.к. в нем включено использование драйвера History и используются конкретные имена состояний.

                      Внимание! В скрипте есть сложные для новичков конструкции - Promise. Это удобные способ не писать функции с callback, а делать цепочки шагов. Так, например, это удобно делать для получения данных из истории состояний.

                      Скрипт подписывается на 2 команды, приходящие через Телеграм:

                      demo - строит график на готовых тестовых данных (чтобы проверить, что код вообще работает). Вызываются функции sendGraph0, prepareDraw0, doDraw.
                      3371__________________2018-10-16_16-08-30.png

                      graph - строит график на данных из истории состояний. Вызываются функции sendGraph1, prepareDraw1, doDraw.
                      3371__________________2018-10-16_16-47-02.png

                      
                      'use strict';
                      const ChartjsNode = require('chartjs-node');
                      
                      /**
                       * функция sendTo как Promise, чтобы удобно было строить цепочки
                       */
                      
                      function sendToPromise(adapter, cmd, params) {
                          return new Promise((resolve, reject) => {
                              sendTo(adapter, cmd, params, (result) => {
                                  resolve(result);
                              });
                          });
                      }
                      
                      // константы для цветов
                      const chartColors = {
                          black: 'rgb(0, 0, 0)',
                      	red: 'rgb(255, 99, 132)',
                      	orange: 'rgb(255, 159, 64)',
                      	yellow: 'rgb(255, 205, 86)',
                      	green: 'rgb(75, 192, 192)',
                      	blue: 'rgb(54, 162, 235)',
                      	purple: 'rgb(153, 102, 255)',
                      	grey: 'rgb(201, 203, 207)'
                      };
                      
                      /**
                       * функция рисования и сохранения картинки в файл
                       *  параметры:
                       *  @param config - конфигурация графика для рисования
                       *  @param filename - имя файла для сохранения
                       *  результат:
                       *  @param Promise - успешное сохранение файла
                       */
                      
                      function doDraw(config, filename) {
                          // создадим полотно с размером 640x480 пикселей
                          var chartNode = new ChartjsNode(640, 480);
                          return chartNode.drawChart(config)
                              .then(() => {
                                  // запишем результат в файл
                                  return chartNode.writeImageToFile('image/png', filename);
                              });
                      }
                      
                      /**
                       * функция подготовки параметров для ChartJS.
                       *  результат:
                       *  @param Promise - успешная подготовка параметров
                       */
                      
                      function prepareDraw0(){
                          // переменная, куда сохраним данные
                          var пример;
                          // создадим Promise сборки данных и конфигурации
                          return new Promise((resolve, reject)=>{resolve()})
                              // здесь могут быть много шагов сбора данных, прежде чем перейти к графику
                              .then(()=>{
                                  // произвольные данные, похожие на те, что хранятся в истории
                                  пример = [
                                      {"val":3,"ack":1,"ts":1539063874301},
                                      {"val":5,"ack":1,"ts":1539063884299},
                                      {"val":5.3,"ack":1,"ts":1539063894299},
                                      {"val":3.39,"ack":1,"ts":1539063904301},
                                      {"val":5.6,"ack":1,"ts":1539063914300},
                                      {"val":-1.3,"ack":1,"ts":1539063924300},
                                      {"val":-6.3,"ack":1,"ts":1539063934302},
                                      {"val":1.23,"ack":1,"ts":1539063944301},
                                  ];
                              })
                              // финальный шаг - создаем конфигурацию графиков
                              .then(()=>{
                                  const chartJsOptions = {
                                      // тип графика - линейный
                                      type: 'line',
                          			data: {
                          			    // список наборов данных
                          				datasets: [
                          			    {
                          			        // заголовок ряда 
                          					label: 'тест',
                          					// цвет
                          					backgroundColor: chartColors.black,
                          					borderColor: chartColors.black,
                          					// размер точек
                          					pointRadius: 3,
                          					// ширина линии графика
                          					borderWidth: 3,
                          					// достанем данные из переменной 'пример' и оставим только значение и время изменения
                          					data: пример.map((item) => {
                          					    return {y: item.val, t: new Date(item.ts)}
                          					}),
                          					// заливка графика - нет
                          					fill: false,
                          			    }
                          				]
                          			},
                          			options: {
                          				// настройка легенды
                          				legend: {
                          				    labels: {
                          				        // размер шрифта
                          				        fontSize: 20,
                          				    },
                          				},
                          				// оси координат
                          				scales: {
                          				    // оси X
                          					xAxes: [{
                          					    // тип - временная ось
                          					    type: 'time',  
                          						display: true,
                          						// метка оси
                          						scaleLabel: {
                          							display: true,
                          							labelString: 'Время'
                          						},
                          					}],
                          					// оси Y
                          					yAxes: [{
                          					    // тип - линейная
                          					    type: 'linear',
                          						display: true,
                          						// метка оси
                          						scaleLabel: {
                          							display: true,
                          							labelString: 'Температура'
                          						},
                          					}]
                          				}
                          			}
                      			};
                      			return chartJsOptions;
                              });
                      }
                      
                      /**
                       * функция подготовки параметров для ChartJS.
                       * собирает данные из истории и складывает их в переменные, 
                       * чтобы потом включить в ряды.
                       * 
                       *  параметры:
                       *  @param hours - количество часов, за которые получить данные
                       *  результат:
                       *  @param Promise - успешная подготовка параметров
                       */
                      
                      function prepareDraw1(hours){
                          // вычислим интервал времени, за который надо получить данные
                          const end = new Date().getTime(),
                                start = end - 3600000*(hours || 1); // 1 = час назад
                      
                          // зададим переменные, в которые будем складывать результаты запроса
                          // исторических данных
                          var улица, куры2, куры1, куры2свет, куры2вент;
                      
                          // создадим Promise сборки данных и конфигурации
                          return new Promise((resolve, reject)=>{resolve()})
                              // на этом шаге собираем историю по 'mqtt.0.ESP_Easy.Улица.Temperature'
                              .then(() => {
                                  return sendToPromise('history.0', 'getHistory', {
                                          id: 'mqtt.0.ESP_Easy.Улица.Temperature',
                                          options: {
                                              start: start,
                                              end: end,
                                              aggregate: 'onchange'
                                          }
                                      }
                                  ).then((result) => {
                                      // записываем результат в переменную 'улица'
                                      улица = result.result;
                                  });
                              })
                              // на этом шаге собираем историю по 'sonoff.0.chicken2.DS18B20_Temperature'
                              .then(() => {
                                  return sendToPromise('history.0', 'getHistory', {
                                      id: 'sonoff.0.chicken2.DS18B20_Temperature',
                                      options: {
                                          start: start,
                                          end: end,
                                          aggregate: 'onchange'
                                      }
                                  }).then((result)=>{
                                      // записываем результат в переменную 'куры2'
                                      куры2 = result.result;
                                  });
                              })
                              .then(() => {
                                  return sendToPromise('history.0', 'getHistory', {
                                      id: 'sonoff.0.sonoff_chicken_vent.DS18B20_Temperature',
                                      options: {
                                          start: start,
                                          end: end,
                                          aggregate: 'onchange'
                                      }
                                  }).then((result)=>{
                                      куры1 = result.result;
                                  });
                              })
                              .then(() => {
                                  return sendToPromise('history.0', 'getHistory', {
                                      id: 'sonoff.0.chicken2.POWER1',
                                      options: {
                                          start: start,
                                          end: end,
                                          aggregate: 'onchange'
                                      }
                                  }).then((result)=>{
                                      куры2свет = result.result;
                                  });
                              })
                              .then(() => {
                                  return sendToPromise('history.0', 'getHistory', {
                                      id: 'sonoff.0.chicken2.POWER2',
                                      options: {
                                          start: start,
                                          end: end,
                                          aggregate: 'onchange'
                                      }
                                  }).then((result)=>{
                                      куры2вент = result.result;
                                  });
                              })
                              // финальный шаг - создаем конфигурацию графиков
                              .then(()=>{
                                  const chartJsOptions = {
                                      // тип графика - линейный
                                      type: 'line',
                          			data: {
                          			    // список наборов данных
                          				datasets: [
                          			    {
                          			        // заголовок ряда с указанием последнего значения из ряда в скобках
                          					label: 'Улица ('+улица[улица.length - 1].val+')',
                          					// цвет
                          					backgroundColor: chartColors.blue,
                          					borderColor: chartColors.blue,
                          					// размер точек. 0 - нет точки
                          					pointRadius: 0,
                          					// ширина линии графика
                          					borderWidth: 3,
                          					// достанем данные из переменной 'улица' и оставим только значение и время изменения
                          					data: улица.map((item) => {
                          					    return {y: item.val, t: new Date(item.ts)}
                          					}),
                          					// заливка графика - нет
                          					fill: false,
                          					// идентификатор оси Y
                          					yAxisID: 'y-axis-1',
                          			    },{
                          					label: 'Куры 1 ('+куры1[куры1.length - 1].val+')',
                          					backgroundColor: chartColors.green,
                          					borderColor: chartColors.green,
                          					pointRadius: 0,
                          					borderWidth: 3,
                          					data: куры1.map((item) => {
                          					    return {y: item.val, t: new Date(item.ts)}
                          					}),
                          					fill: false,
                          					yAxisID: 'y-axis-1',
                          				},{
                          					label: 'Куры 2 ('+куры2[куры2.length - 1].val+')',
                          					backgroundColor: chartColors.red,
                          					borderColor: chartColors.red,
                          					pointRadius: 0,
                          					borderWidth: 3,
                          					data: куры2.map((item) => {
                          					    return {y: item.val, t: new Date(item.ts)}
                          					}),
                          					fill: false,
                          					yAxisID: 'y-axis-1',
                          				},{
                          					label: 'Куры 2 свет ('+куры2свет[куры2свет.length - 1].val+')',
                          					backgroundColor: chartColors.yellow,
                          					borderColor: chartColors.yellow,
                          					pointRadius: 0,
                          					borderWidth: 1,
                          					data: куры2свет.map((item) => {
                          					    return {y: (item.val) ? 1 : 0, t: new Date(item.ts)}
                          					}),
                          					fill: true,
                          					lineTension: 0,
                      		                steppedLine: true,
                          					yAxisID: 'y-axis-2',
                          				},{
                          					label: 'Куры 2 вент ('+куры2вент[куры2вент.length - 1].val+')',
                          					backgroundColor: chartColors.grey,
                          					borderColor: chartColors.grey,
                          					pointRadius: 0,
                          					borderWidth: 1,
                          					data: куры2вент.map((item) => {
                          					    return {y: (item.val) ? -1 : 0, t: new Date(item.ts)}
                          					}),
                          					fill: true,
                          					lineTension: 0,
                      		                steppedLine: true,
                          					yAxisID: 'y-axis-2',
                          				}
                          				]
                          			},
                          			options: {
                          				// настройка легенды
                          				legend: {
                          				    labels: {
                          				        // размер шрифта
                          				        fontSize: 20,
                          				    },
                          				},
                          				// оси координат
                          				scales: {
                          				    // оси X
                          					xAxes: [{
                          					    // тип - временная ось
                          					    type: 'time',  
                          						display: true,
                          						// метка оси
                          						scaleLabel: {
                          							display: true,
                          							labelString: 'Время'
                          						},
                          						// настройка формата оси (времени)
                          						time: {
                          						    unit: 'minute',
                          						    displayFormats: {
                                                          minute: 'HH:mm'
                                                      }
                          						},
                          					}],
                          					// оси Y
                          					yAxes: [{
                          					    // тип - линейная
                          					    type: 'linear',
                          						display: true,
                          						// метка оси
                          						scaleLabel: {
                          							display: true,
                          							labelString: 'Температура'
                          						},
                          						// расположение линейки - слева
                          						position: 'left',
                          						// идентификатор оси
                          						id: 'y-axis-1',
                          					},{
                          					    type: 'linear',
                          					    display: true,
                          						scaleLabel: {
                          							display: true,
                          							labelString: 'Свет и вентиляция'
                          						},
                          						ticks: {
                          							min: -4,
                          							max: 2
                          						},
                          						// расположение линейки - справа
                          						position: 'right',
                          						id: 'y-axis-2',
                              				}]
                          				}
                          			}
                      			};
                      			return chartJsOptions;
                              });
                      }
                      
                      function sendGraph0(user){
                          // имя файла, в который положим картинку с графиком
                          const filename = '/tmp/graph0.png';
                          // выполним подготовку данных 
                          prepareDraw0()
                              // на след шаге нарисуем
                              .then((result) => {
                                  // рисуем картинку по полученным данным и конфигурации
                                  return doDraw(result, filename);
                              })
                              .then(()=>{
                                  // теперь отправим сообщение в телеграм
                                  sendTo('telegram.0', {
                                      user: user, 
                                      text: filename, 
                                      caption: 'Пример графика',
                                  });
                              })
                              .catch((err)=>{
                                  console.error(err);
                              });
                      }
                      
                      /**
                       * функция отправки графика в телеграм
                       * @param user - какому юзеру слать. если пусто - всем
                       * @param chat_id - 
                       * @param message_id - в каком чате и какое сообщение заменить при обновлении
                       * @param hours - количество часов, за которые получить данные
                       */
                      
                      function sendGraph1(user, chat_id, message_id, hours){
                          // имя файла, в который положим картинку с графиком
                          const filename = '/tmp/graph1.png';
                          hours = hours || 1;
                          // выполним подготовку данных 
                          prepareDraw1(hours)
                              // на след шаге нарисуем
                              .then((result) => {
                                  // рисуем картинку по полученным данным и конфигурации
                                  return doDraw(result, filename);
                              })
                              .then(() => {
                                  // удалим предыдущее сообщение
                                  if (message_id && chat_id) {
                                      sendTo('telegram', {
                                          user: user,
                                          deleteMessage: {
                                              options: {
                                                  chat_id: chat_id, 
                                                  message_id: message_id
                                              }
                                          }
                                      });
                                  }
                              })
                              .then(()=>{
                                  // теперь отправим сообщение в телеграм
                                  sendTo('telegram.0', {
                                      user: user, 
                                      text: filename, 
                                      caption: 'Температура в курятниках ('+hours+'ч)',
                                      reply_markup: {
                                          inline_keyboard: [
                                              [
                                                  { text: '🔄', callback_data: 'graph_'+hours},
                                                  { text: '1 ч', callback_data: 'graph_1' },
                                                  { text: '2 ч', callback_data: 'graph_2' },
                                                  { text: '4 ч', callback_data: 'graph_4' },
                                                  { text: '12 ч', callback_data: 'graph_12' },
                                                  { text: '24 ч', callback_data: 'graph_24' },
                                              ]
                                          ]
                                      }
                                  });
                              })
                              .catch((err)=>{
                                  console.error(err);
                              });
                      }
                      
                      // будем слушать телеграм и ждать команды на построение графика
                      on({id: "telegram.0.communicate.request", ack: false, change: 'any'}, function (obj) {
                          var v;
                          var msg = obj.state.val;
                          var command = obj.state.val.substring(obj.state.val.indexOf(']')+1);
                          var user = obj.state.val.substring(obj.state.val.indexOf('[')+1,obj.state.val.indexOf(']'));
                          var chat_id = getState("telegram.0.communicate.requestChatId").val;
                          var message_id = getState("telegram.0.communicate.requestMessageId").val;
                      
                          // команда для графика - demo
                          if (command == 'demo') {
                              sendGraph0(user);
                          }
                          // команда для графика - graph
                          if (command.startsWith('graph')) {
                              const hours = parseInt(command.split('_')[1]);
                              sendGraph1(user, chat_id, message_id, hours);
                          }
                      });
                      
                      
                      K Offline
                      K Offline
                      kristow
                      schrieb am zuletzt editiert von
                      #22

                      @goofyk
                      Добрый день.
                      Установил chartjs и chartjs-node.
                      На основе вашего примера прописал свои параметры для вывода в график. Когда запускаю скрипт, то ошибок нет. Когда отправляю в телеграмм "demo", то вылетает ошибка "script.js.common.Chart: TypeError: canvas.getRootNode is not a function" и на этом все... Можете подсказать что сделать? для решения этой проблемы?
                      В самом скрипте этой функции нет. Нужно как-то хитрее ставить библиотеки? У меня iobroker работает на rasbian (если имеет значение).

                      1 Antwort Letzte Antwort
                      0
                      Antworten
                      • In einem neuen Thema antworten
                      Anmelden zum Antworten
                      • Älteste zuerst
                      • Neuste zuerst
                      • Meiste Stimmen


                      Support us

                      ioBroker
                      Community Adapters
                      Donate

                      800

                      Online

                      32.5k

                      Benutzer

                      81.7k

                      Themen

                      1.3m

                      Beiträge
                      Community
                      Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen | Einwilligungseinstellungen
                      ioBroker Community 2014-2025
                      logo
                      • Anmelden

                      • Du hast noch kein Konto? Registrieren

                      • Anmelden oder registrieren, um zu suchen
                      • Erster Beitrag
                        Letzter Beitrag
                      0
                      • Home
                      • Aktuell
                      • Tags
                      • Ungelesen 0
                      • Kategorien
                      • Unreplied
                      • Beliebt
                      • GitHub
                      • Docu
                      • Hilfe