ITСooky

IT-рецепты съедобные и не очень!

Добавляем в умный дом TelegramBot на Node.js

дата 25.06.2018

Продолжаю колхозить на тему хочу знать температуру и влажность спальни из любой точки мира и что выбрать как не разрекламированный теперь Telegram но сначала по порядку.

Беру OrangePi Zero 512mb вот такой

Обзор-тестирование[пришлось еще одну купить] Orange Pi Zero 512Mb с коробкой и платой расширения!



Температуру и остальное все еще меряет Arduino метеостанция, и это не смотря на мою пайку (температура только неадекватная завыщена, но это DHT22 датчик паленый видимо)

arduino_ch340_temp_ehernet_018
Мониторим по сети — свет, температуру, движение с Arduino Uno R3 CH340G и строим графики!


За это время образов для OrenagePi поубавилось, мне нравился DietPi но они сказали «хрен знает что за WiFi модуль тут, поддерживать не возможно, идите в«. Но все еще остается Arambien, они тоже говорят что «хрен знает что за WiFi модуль тут, поддерживать не возможно, может глючить«. Но тех кто любит апельсины этим не спугнуть, это вам не малинисты какие-нибудь с пошаговыми инстуркциями на все случаи жизни!

Качаю с этой страницы www.armbian.com/orange-pi-zero/ Strech образ, размер не пишут но он маленький должен влезть на 2gb кароточку(влез).

Записываю на карту по нашему по Ubuntu’вски
Подключим карту памяти и посмотрим в системе где она
sudo lsblk
В моем случае она sde та что 2 GB
Теперь её надо вынуть (но она все равно останестя в иконках дисков)
sudo umount /dev/sde1
теперь затрем
sudo mkfs.vfat -I /dev/sde
опять отмонтируем
sudo umount /dev/sde
Разархивируем образ и запишем на карту, это занимает несколько минут
Так опять новый архиватор 7z ставим сначала его
sudo apt-get install p7zip
и разархивируем
p7zip -d Debian_stretch_next.7z
пошла запись
sudo dd bs=1M if=Armbian_5.38_Orangepizero_Debian_stretch_next_4.14.14.img of=/dev/sde

Вставляем карту в зеро, если не грузится надо попробовать другую карту(реально это 98% проблем загрузки) для захода Log in as: root Password: 1234. А еще 2% из-за плохой записи флешки… вот не знаю записал второй раз и загрузилось, правда у меня самая фиговая карта старая Transcenent 2Gb без указания скорости.

IP апельсинки посмотрел на роутере среди выданных, коннектюсь по SSH
sudo ssh root@192.168.1.218
Подключение к Wi-Fi легко и просто, заходим в меню Armbian
sudo armbian-config
Далее по меню все просто даже рассказывать не буду, подключился к WiFi оно запомнилось и после перезагрузки само подключается

Теперь надо выбрать на чем, из чего, где, как вообще Telegram Bot будет работать то. Есть из чего выбрать, но так как мне не мешает знание ни одного из языков програмирования так что Node.JS — а почему нет! Кажется JS на конце это JavaScript а он очень похож на C++ не то чтобы я знаю, но видел.

Хотя бы инструкции есть, вот начну по мотивом этой замечательной статьи archakov.im/post/telegram-bot-on-nodejs.html сразу же отсылает к гуглу за установкой Node Js, да ничего страшного! Кстати, забегая из конца статьи, у меня вот по этой инструкции ничего не заработало, но вдохновило…

Установка Node.Js
Устанавливаем двумя коммандами
curl -sL https://deb.nodesource.com/setup_9.x | bash -
apt-get install -y nodejs

По умочнаию в armbian не было сурса где искать Node.JS со всеми плющками, первая его добавляет. Отожрало 56 мегабайт, боюсь за свою 2 Gb карту,я конечно хоть и нашел её в мусорке, но новой и много. А весь прикол что уже меньше 16gb не купить, тоесть можно купить 8Gb но по цене 16Gb!

Проверяем версии того что установилось коммандами
root@orangepizero:~# node --version
v9.11.1
root@orangepizero:~# npm --version
5.6.0

Добавляем безопасности
Всегда полезно скрыть свой реальный IP от всяких публичных сервисов, тем более если на этом IP работает что-то умное и потенциальное взломоопасное!

Ставим TOR
apt-get install tor

Тут какой то косяк в Debian не могу при редактирование в vim ничего вставить правой мышкой
надо создать файл
vi ~/.vimrc
и туда добавить строку

set mouse=

После этого начинает вставлять мышкой… иногда первую букву строки съедает…

Вставляем в файл
vi /etc/tor/torrc
вот эту строку

SocksPort 127.0.0.1:9050

больше там ничего не должно быть расскоменчено

Ставим прокси сервер Privoxy
apt-get install privoxy
Добавляем в файл
vi /etc/privoxy/config
строки

forward-socks5 / localhost:9050 .

Запускаем их
service tor start
service privoxy restart

Проверяем
Это наш IP в незащищенном виде
curl ident.me
А это через прокси
curl -x http://localhost:8118 ident.me
Если отличаются то сработало!!!
Добавляем в атозапуск
sudo update-rc.d privoxy enable
sudo update-rc.d tor enable

ругается на язык на perl чо, перезагружаюсь автозапуск сработал

Создаем бота получаем токен
Тут надо в Telegram поговорить с BotFather придумат название, бота и никнайм и он выдаст токен, не буду описывать есть везде.

Ставим — запускаем Telegram Bot’a
Хотя бы просто чтобы что-то
ставим
npm install node-telegram-bot-api
Посмотреть версию
npm list node-telegram-bot-api
Далее создаем папку и файл
mkdir tbot
cd tbot
vi bot.js

Сюда вставляем

const TelegramBot = require('node-telegram-bot-api');

// replace the value below with the Telegram token you receive from @BotFather
const token = 'YOUR_TOKEN_YOUR_TOKEN’;

// Create a bot that uses 'polling' to fetch new updates
const bot = new TelegramBot(token, {polling: true,
request: {
  proxy: "http://localhost:8118"
 }
});

// Matches "/echo [whatever]"
bot.onText(/\/echo (.+)/, (msg, match) => {
  // 'msg' is the received Message from Telegram
  // 'match' is the result of executing the regexp above on the text content
  // of the message

  const chatId = msg.chat.id;
  const resp = match[1]; // the captured "whatever"

  // send back the matched "whatever" to the chat
  bot.sendMessage(chatId, resp);
});

// Listen for any kind of message. There are different kinds of
// messages.
bot.on('message', (msg) => {
  const chatId = msg.chat.id;

  // send a message to the chat acknowledging receipt of their message
  bot.sendMessage(chatId, 'Received your message');
});

Запускаем
node bot.js
И вот оно, находим у себя на телефоне в Telegram бот по никнейму в перемешку с названием ITCooky home и пишем ему — он может только отвечать Received your message и повторят сообщение если оно начинается с /echo.

Добавляем в бот функцию сообщения о температуре
Представлял себе что буду читать файл, который формируется из опроса датчика по http, и последную строку, как актуальную температуру, будет бот выводить в ответ… Не фига, не знаю как это сделать, зато знаю как отвечать картинкой, а картинку буду делать обычными скриптами — температура на графике за 5 минут, за час, за день!

Подготавливаю данные и график, подойдут нароботки из статьи по SAPу, от FreeBSD есть отличия!

Ставим консольный браузер
apt-get install lynx
Делаем скрипт
vi andmon.sh
Вствляем

#!/bin/bash
d=`/usr/bin/lynx -source -connect_timeout=10 192.168.1.177 | awk 'NR==2'`
if [ -z "$d" ]
then
t=`/bin/date +%Y"."%m"."%d"-"%H":"%M" "`
/bin/echo "${t} 0 0 0 0 0" >> /root/tbot/mon.log
exit
elif ! [ -z "$d" ]
then
t=`/bin/date +%Y"."%m"."%d"-"%H":"%M" "`
/bin/echo "${t}${d}" >> /root/tbot/mon.log
fi

Делаем скрипт исполняемым
chmod +x andmon.sh
И засовываем в крон
crontab -e
срочку
*/1 * * * * /root/tbot/andmon.sh

Жду пару минут и смотрю появился ли файл /root/tbot/mon.log появилось, да, конечно

Ставим плотер для графиков, который печатает в файл
apt-get install gnuplot
делаем скрипт
vi plot.sh
вставляем

#!/bin/bash
/bin/cat /root/tbot/mon.log |/usr/bin/tail -n -5 | /usr/bin/xargs -n 6 /bin/echo > /root/tbot/temp5.log
/usr/bin/gnuplot << EOF
set terminal png size 800,500
set output '/root/tbot/temp5.png'
set autoscale y
set autoscale x
unset border
set xdata time
#set ytics 1
#set xtics 5 font "Verdana, 10" rotate 90
set grid
set timefmt "%Y.%m.%d-%H:%M"
set format x "%H:%M"
plot '/root/tbot/temp5.log' u 1:2 with lines linetype 1 t 'temperature C'
EOF
/bin/cat /root/tbot/mon.log |/usr/bin/tail -n -60 | /usr/bin/xargs -n 6 /bin/echo > /root/tbot/temph.log
/usr/bin/gnuplot << EOF
set terminal png size 800,500
set output '/root/tbot/temph.png'
set autoscale y
set autoscale x
unset border
set xdata time
#set ytics 1
#set xtics 5 font "Verdana, 10" rotate 90
set grid
set timefmt "%Y.%m.%d-%H:%M"
set format x "%H:%M"
plot '/root/tbot/temph.log' u 1:2 with lines linetype 1 t 'temperature C'
EOF
/bin/cat /root/tbot/mon.log |/usr/bin/tail -n -1440 | /usr/bin/xargs -n 6 /bin/echo > /root/tbot/tempd.log
/usr/bin/gnuplot << EOF
set terminal png size 800,500
set output '/root/tbot/tempd.png'
set autoscale y
set autoscale x
unset border
set xdata time
#set ytics 1
#set xtics 5 font "Verdana, 10" rotate 90
set grid
set timefmt "%Y.%m.%d-%H:%M"
set format x "%H"
plot '/root/tbot/tempd.log' u 1:2 with lines linetype 1 t 'temperature C'
EOF

Делаем скрипт исполняемым
chmod +x plot.sh
И засовываем в крон
crontab -e
строчку
*/1 * * * * /root/tbot/plot.sh

делаем скрипт бота
vi bot0.js
вставляем

process.env["NTBA_FIX_350"] = 1;
process.env["NTBA_FIX_319"] = 1;

const TelegramBot = require('node-telegram-bot-api');

// replace the value below with the Telegram token you receive from @BotFather
const token = 'YOUR_TOKEN';

// Create a bot that uses 'polling' to fetch new updates
const bot = new TelegramBot(token, {polling: true,
request: {
  proxy: "http://localhost:8118"
 }
});


// Matches "/echo [whatever]"
bot.onText(/[T/t]est/, (msg, match) => {
const chatId = msg.chat.id;
bot.sendMessage(chatId, 'I am working');
});


bot.onText(/[T/t]emp5/, (msg, match) => {
const chatId = msg.chat.id;

    const photo5 = 'temp5.png';
    bot.sendPhoto(chatId, photo5, {caption: 'Temp last 5 min'});

});
bot.onText(/[T/t]emph/, (msg, match) => {
const chatId = msg.chat.id;

   const photoh = 'temph.png';
    bot.sendPhoto(chatId, photoh, {caption: 'Temp last 60 min'});

});
bot.onText(/[T/t]empd/, (msg, match) => {
const chatId = msg.chat.id;

   const photod = 'tempd.png';
    bot.sendPhoto(chatId, photod, {caption: 'Temp last 24h'});

});

Первые две строчки нужны, чтобы не возникали угрожающие ошибки… не знаю как это работает, но все ставят и ошибки не вылетают
Команды бота, все с большой и малой буквы
test — просто говорит я рабоитаю
temp5 — график с температурой за последние 5 минут
temph — за последний час
tempd — за последние 24 часа

Просто запустить его недостаточно, хотелось бы чтобы он сам запускался после перезагрузки
Для этого ставим pm2

npm i pm2 -g

Запускаем
pm2 start bot0.js --name bot0
И еще команда, теперь бот будет запускаться после перезагрузки
pm2 startup
Так можно посмотреть какие боты запушены
pm2 list

┌──────────┬────┬──────┬──────┬────────┬─────────┬────────┬─────┬───────────┬──────┬──────────┐
│ App name │ id │ mode │ pid  │ status │ restart │ uptime │ cpu │ mem       │ user │ watching │
├──────────┼────┼──────┼──────┼────────┼─────────┼────────┼─────┼───────────┼──────┼──────────┤
│ bot0     │ 0  │ fork │ 2376 │ online │ 0       │ 47m    │ 0%  │ 46.6 MB   │ root │ disabled │
└──────────┴────┴──────┴──────┴────────┴─────────┴────────┴─────┴───────────┴──────┴──────────┘
 Use `pm2 show <id|name>` to get more details about an app

А это мониторинг
pm2 monit

Комманды остановить запусить
pm2 stop App-name
pm2 start App-name

Убрать из pm2 из автозапуска
pm2 delete App-name

Перегружаюсь — Работает!

Добавляем аватарку в бот
Это надо делать через свой телеграм, сказать @BotFather фразу /setuserpic и дельше отвчать ему и прислать картинку

ToDo
Понять почему OrangePi зависает — перегрев(маловероятно но), блокпитания(поменять на фирменный), WiFi модуль (перейти на Ethernet), карта памяти Да из-за зарядки, заменил ашановскую на фирменную шаоми, эх а так хочется верить в зарядку за 120 руб,в кабель лайтнинг за 60…
— Сделать уведомления при определенных условиях
— И понять как ограничить доступ к боту (упс)

Делаем уведомления при определенных условиях
Уффф это было тяжко, увлекательно, больно, но приятно. Кое что осталось непонятным, но результат есть! Мозги от нового языка, синтаксиса — немного звенят!

Первым делом я так и не понял как взять из файла из строки второе значение средствами Node.js, консольными коммандами как два пальца, поэтому вставляю в файл для плотера строку

/bin/cat /root/tbot/mon.log |/usr/bin/tail -n -5 | /usr/bin/awk '{print $2}' > /root/tbot/tw.log

Это дает файл tw.log где в столбец пять значений температуры за последние пять минут, и тоже самое для влажность hw

итого у меня теперь два файла для картинок со статистикой
plotmin.sh

#!/bin/bash
/bin/cat /root/tbot/mon.log |/usr/bin/tail -n -5 | /usr/bin/xargs -n 6 /bin/echo > /root/tbot/mon5.log
/bin/cat /root/tbot/mon.log |/usr/bin/tail -n -5 | /usr/bin/awk '{print $2}' > /root/tbot/tw.log
/bin/cat /root/tbot/mon.log |/usr/bin/tail -n -5 | /usr/bin/awk '{print $3}' > /root/tbot/hw.log

/usr/bin/gnuplot << EOF
set terminal png size 800,500
set output '/root/tbot/temp5.png'
set autoscale y
set autoscale x
unset border
set xdata time
#set ytics 1
#set xtics 5 font "Verdana, 10" rotate 90
set grid
set timefmt "%Y.%m.%d-%H:%M"
set format x "%H:%M"
plot '/root/tbot/mon5.log' u 1:2 with lines linetype 1 t 'temperature C'
EOF
/usr/bin/gnuplot << EOF
set terminal png size 800,500
set output '/root/tbot/hum5.png'
set autoscale y
set autoscale x
unset border
set xdata time
#set ytics 1
#set xtics 5 font "Verdana, 10" rotate 90
set grid
set timefmt "%Y.%m.%d-%H:%M"
set format x "%H:%M"
plot '/root/tbot/mon5.log' u 1:3 with lines linetype 2 t 'humidity %'
EOF

и plot.sh

#!/bin/bash
/bin/cat /root/tbot/mon.log |/usr/bin/tail -n -60 | /usr/bin/xargs -n 6 /bin/echo > /root/tbot/monh.log
/usr/bin/gnuplot << EOF
set terminal png size 800,500
set output '/root/tbot/temph.png'
set autoscale y
set autoscale x
unset border
set xdata time
set grid
set timefmt "%Y.%m.%d-%H:%M"
set format x "%H:%M"
plot '/root/tbot/monh.log' u 1:2 with lines linetype 1 t 'temperature C'
EOF
/bin/cat /root/tbot/mon.log |/usr/bin/tail -n -1440 | /usr/bin/xargs -n 6 /bin/echo > /root/tbot/mond.log
/usr/bin/gnuplot << EOF
set terminal png size 800,500
set output '/root/tbot/tempd.png'
set autoscale y
set autoscale x
unset border
set xdata time
set grid
set timefmt "%Y.%m.%d-%H:%M"
set format x "%H"
plot '/root/tbot/mond.log' u 1:2 with lines linetype 1 t 'temperature C'
EOF
/usr/bin/gnuplot << EOF
set terminal png size 800,500
set output '/root/tbot/humh.png'
set autoscale y
set autoscale x
unset border
set xdata time
set grid
set timefmt "%Y.%m.%d-%H:%M"
set format x "%H:%M"
plot '/root/tbot/monh.log' u 1:3 with lines linetype 2 t 'humidity %'
EOF
/usr/bin/gnuplot << EOF
set terminal png size 800,500
set output '/root/tbot/humd.png'
set autoscale y
set autoscale x
unset border
set xdata time
set grid
set timefmt "%Y.%m.%d-%H:%M"
set format x "%H"
plot '/root/tbot/mond.log' u 1:3 with lines linetype 2 t 'humidity %'
EOF

и вот так они запускаются в
crontab -e
строчки
*/1 * * * * /root/tbot/plotmin.sh
*/5 * * * * /root/tbot/plotmin.sh

Переписал сам бот, красиво все равно не получилось, почему-то не сработали functions() видимо что-то со вставлянием и передачей параметров из скобок, поэтому код повторяется.
Сам бот делаю файл
vi itchomebot.js
и вставляю

process.env["NTBA_FIX_350"] = 1;
process.env["NTBA_FIX_319"] = 1;

const TelegramBot = require('node-telegram-bot-api');
// replace the value below with the Telegram token you receive from @BotFather
const token = '5YouR_b0t_tokEn_heAR';

const adminId = 1112t2333;

// Create a bot that uses 'polling' to fetch new updates
const bot = new TelegramBot(token, {polling: true,
request: {
  proxy: "http://localhost:8118"
 }
});

// start var
var fs = require('fs');
var readline = require('readline');
var stream = require('stream');
//for min max status
tw1 = 29;
alert1 = 0;
tw2 = 15;
alert2 = 0;
hw1 = 70;
alert3 = 0;
hw2 = 20;
alert4 = 0;
// end var

//start all 


bot.onText(/[T/t]est/, (msg, match) => {
bot.sendMessage(msg.chat.id, 'I am working');
});

//start help
bot.onText(/\/help/, (msg, match) => {
bot.sendMessage(msg.chat.id, 'Manual:\n/start - start and subscribe for warnings\n/help - this manual\n/toadmin text - send message to bot admin\n/touser 111222333 "text" - send message to user(only for admin)\nTest - test\nTemp5 - temp stat for 5 min\nTemph - temp stat for last 60 min\nTempd - temp stat for last 24h\nHum5 - humidity stat for 5 min\nHumh - humidity stat for last 60 min\nHumd - humidity stat for last 24h\nKkk -to run inline keybord\n/warnings off - warnings off\n/warnings on - warnings on');
});
//end help

//start send message to bot admin
bot.onText(/\/toadmin (.+)/, (msg, match) => {
  const fromUser = msg.from.id;
  const resp = match[1]; // the captured "whatever"
  bot.sendMessage(adminId, 'Message from ' + fromUser + ' "' + resp + '"');
});
//ens send message to bot admin

//start send message to user 
bot.onText(/\/touser (.+) "(.+)"/, (msg, match) => {
  const fromUser = msg.from.id;
 const touserId = match[1]
 const touserText = match[2]
if (fromUser == adminId) {
  bot.sendMessage(touserId, 'Message from bot admin: "' + touserText + '"');
} else {
bot.sendMessage(fromUser, 'You are not athtorised');
};
});
//ens send message to user 

//start send pic stat
bot.onText(/[H/h]um5/, (msg, match) => {
  bot.sendPhoto(msg.chat.id, 'hum5.png', {caption: 'Humidity last 5 min'});
});
bot.onText(/[H/h]umh/, (msg, match) => {
  bot.sendPhoto(msg.chat.id, 'humh.png', {caption: 'Humidity last 60 min'});
});
bot.onText(/[H/h]umd/, (msg, match) => {
  bot.sendPhoto(msg.chat.id, 'humd.png', {caption: 'Humidity last 24h'});
});
bot.onText(/[T/t]emp5/, (msg, match) => {
  bot.sendPhoto(msg.chat.id, 'temp5.png', {caption: 'Temp last 5 min'});
});
bot.onText(/[T/t]emph/, (msg, match) => {
  bot.sendPhoto(msg.chat.id, 'temph.png', {caption: 'Temp last 60 min'});
});
bot.onText(/[T/t]empd/, (msg, match) => {
  bot.sendPhoto(msg.chat.id, 'tempd.png', {caption: 'Temp last 24h'});
});
//end send pic stat

//start start 
bot.onText(/\/start/, (msg, match) => {
bot.sendMessage(msg.chat.id, 'Welcome! This is ItCooky.com TelegramBot running on OrangePi PC Plus 1Gb RAM 8Gb eMMC\n\n For recieve warnings run:\n/warnings on');
});
//end start 



//start warnigs 

//start find midscope by file name
function midscope(arg1, callback) {
var arrreadfile = [];
readline.createInterface(fs.createReadStream(arg1), new stream).on('line', function(line) {
arrreadfile.push(line);
});
readline.createInterface(fs.createReadStream(arg1), new stream).on('close', function() {
var arrvaluesfromfile = arrreadfile.map(function (x) {
return parseInt(x, 10);
});
const reducer = (accumulator, currentValue) => accumulator + currentValue;
 var midscopevalue = (arrvaluesfromfile.reduce(reducer) / arrvaluesfromfile.length);
callback (midscopevalue);
});
};
//stop find midscope by file name

//start send messages to id in list file
function sendtoidfromfile (arg1,arg2,arg3,arg4) {
readline.createInterface(fs.createReadStream(arg1), new stream).on('line', function(line) {
bot.sendMessage(line, '' + arg2 + arg3 + arg4 + '');
});
readline.createInterface(fs.createReadStream(arg1), new stream).on('close', function() {
});
}


//end send messages to id in list file



function warningtemp(arg1,arg2) {
midscope ('./tw.log', function (num) {
if (num >= arg1 &&  alert1 == 0 )
{

sendtoidfromfile ('./warning_users.id','WARNING: Height Temp in badroom! More than ',tw1,'C!');

alert1 = 1;
} else {
if (num < arg1 && alert1 == 1 )
{
sendtoidfromfile ('./warning_users.id','RELAX: Normal temp in badroom! Less than ',tw1,'C!');
alert1 = 0;
};
};
if (num <= arg2 &&  alert2 == 0 )
{

sendtoidfromfile ('./warning_users.id','WARNING: Low Temp in badroom! Less than ',arg2,'C!');

alert2 = 1;
} else {
if (num > arg2 && alert2 == 1 )
{
sendtoidfromfile ('./warning_users.id','RELAX: Normal temp in badroom! More than ',arg2,'C!');
alert2 = 0;
};
};
});


};
setInterval(warningtemp, 300500, tw1, tw2);

function warninghum(arg1,arg2) {
midscope ('./hw.log', function (num) {
if (num >= arg1 &&  alert3 == 0 )
{

sendtoidfromfile ('./warning_users.id','WARNING: Height humidity in badroom! More than ',arg1,'%!');

alert3 = 1;
} else {
if (num < arg1 && alert3 == 1 )
{sendtoidfromfile ('./warning_users.id','RELAX: Normal humuduty in badroom! Less than ',arg1,'%!');
alert3 = 0;
};
};
if (num <= arg2 &&  alert4 == 0 )
{

sendtoidfromfile ('./warning_users.id','WARNING: Low humidity in badroom! Less than ',arg2,'%!');

alert4 = 1;
} else {
if (num > arg2 && alert4 == 1 )
{sendtoidfromfile ('./warning_users.id','RELAX: Normal humidity in badroom! More than ',arg2,'%!');
alert4 = 0;
};
};
});


};
setInterval(warninghum, 290000, hw1, hw2);


//end warnigs


//set warnings on
bot.onText(/\/[W/w]arnings on/, (msg, match) => {
var users = msg.from.id;
var dubl = 0;
var instream = fs.createReadStream('./warning_users.id');
var rl = readline.createInterface(instream, new stream);
rl.on('line', function(line) {
console.log(line);
if ( line == users) {
dubl = dubl + 1;
};
});
rl.on('close', function() {
 if (dubl == 0) {
var fs = require('fs');
fs.appendFile('warning_users.id', `${users}\n`, (error) => { console.log("Error!");
});
bot.sendMessage(msg.chat.id, 'Youv bin subscribed to warnings');
};
if (dubl != 0) {
bot.sendMessage(msg.chat.id, 'You are allready subcribed to warnings');
};
});
});
//end set warnings on



//delete form warnings function arg file name and word

function delstring(arg1,arg2) {
var value = arg2 + '\n';
var datafromfile = fs.readFileSync('./' + arg1, 'utf-8');
var newDataFile = datafromfile.replace(value, '');
fs.writeFileSync('./' + arg1, newDataFile, 'utf-8');
};

//end delete functions


//start warnigs off 
bot.onText(/[W/w]arnings off/, (msg, match) => {
var user = msg.from.id;
filename = 'warning_users.id';
delstring(filename, user);

});

Удаляю из списка запуска сатрый бот
pm2 delete bot0
и запускаю новый
pm2 start itchomebot.js --name ITCooky
и делаем опять
pm2 startup
Куски кода подписаны. Нельзя отправлять уведомления не зная ID пользователей — их надо собрать. Событие для сбора /start эту команду выполняют все вновь заходящие в бот. Если хочете получать уведомления надо сказать боту /warnings on ID пишутся в файл, и не просто так, а проверяется есть ли он там уже. Надо будет сделать удаление из этого списка по желанию пользователя, но это потом. Чтобы выключить предупреждения /warnings off

Далее (в конце бота с //start warnigs for height temp)считается среднее значение из файла tw.log, тут теряются десетые, но мне такая точность и не нужна, потом сравнивается со значение tw, если больше то открывается файл с ID пользователей и им рассылается сообщение. Эта функция запускается коммандой (нет уже по другому, читай дальше)

setInterval(warning, 300000);

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

Можно отправить соощение админу бота /toadmin text Надо назначить админа бота для этого надо прописать свой номер из 9 цифр в начале в cons = 111222333 номер я не понля, его просто так в своих настройках не поcмотреть, но он у меня пишется в warnings_users.id. Админ тоже может отправить /touser 111222333 «text»

UPD
Опять переписал, bot. Не знаю толи асинхронное програмирование я не понимаю(скорей всего), толи оно не для того что я делаю. Удалось запихнуть в функцию midscope(аргумент путь к файлу) нахождение среднего из 5 значений в файле — выпихнуть из функции это значение не получилось так что дальше все идет в этой функции. Удалось сделать отправку сообщений по ID из файла в функции sendtoidfromfile(аргументы путь к файлу с ID, первая часть сообщения, значение показателя, конец сообщения). С глобальными переменными в Node.Js беда какаято, но если их объявлять вот так в начале (alert1 и тп) то работают, сквозят по функциям, из функций значения не вытаскиваются, хотя в учебных примерах вытаскиваются… ну ничего, бот опять работает бот опять сигнализиурет, когда сслишком высоко или низко, температура или влажность в спальне!

UPD: Добавляем экранную клавиатуру в TelegramBot

Все говорят это просто, просто если бы в мануле telegram были примеры, как это вот так без примеров просто на словах — не понимаю.

Добавляем в конце бота вот это

//custome keyboard settings
const keyMYboard = {
   reply_markup: {
       inline_keyboard: [
           [
{text: `Temperature`, callback_data:'t'},
{text: `5m`, callback_data:'temp5'},
{text: `1h`, callback_data:'temph'},
{text: `24h`, callback_data:'tempd'}
  ],[
{text: `Humidity`, callback_data:'h'},
{text: `5m`, callback_data:'hum5'},
{text: `1h`, callback_data:'humh'},
{text: `24h`, callback_data:'humd'}
]]}}

//this runs inline keyboard
bot.onText(/[K/k]kk/, (msg, match) => {
bot.sendMessage(msg.chat.id, 'ITChomeBot Keyboard', keyMYboard);
});

//this start button press reader - only once ofr all inline_keyboards imho
bot.on('callback_query', function (msg) {
if (msg.data === 'temp5'){
bot.sendPhoto(msg.from.id, 'temp5.png', {caption: 'Temp last 5 min'});
bot.answerCallbackQuery(msg.id, "Done", false);
}
if (msg.data === 'temph'){
bot.sendPhoto(msg.from.id, 'temph.png', {caption: 'Temp last 60 min'});
bot.answerCallbackQuery(msg.id, "Done", false);
}
if (msg.data === 'tempd'){
bot.sendPhoto(msg.from.id, 'tempd.png', {caption: 'Temp last 24h'});
bot.answerCallbackQuery(msg.id, "Done", false);
}
if (msg.data === 'hum5'){
bot.sendPhoto(msg.from.id, 'hum5.png', {caption: 'Humidity last 5 min'});
bot.answerCallbackQuery(msg.id, "Done", false);
}
if (msg.data === 'humh'){
bot.sendPhoto(msg.from.id, 'humh.png', {caption: 'Humidity last 60 min'});
bot.answerCallbackQuery(msg.id, "Done", false);
}
if (msg.data === 'humd'){
bot.sendPhoto(msg.from.id, 'humd.png', {caption: 'Humidity last 24h'});
bot.answerCallbackQuery(msg.id, "Done", false);
}
});


Останавливаем бота и запускаем по новой
pm2 stop ITCooky
pm2 start ITCooky

Действительно все просто. Вначале создаем const имя(любое) keyMYboard, далее описываем текст который будет на кнопке и что она будет посылать. Тут оказывается нельзя просто текст на кнопку — должна чтото посылать, не важно что если нужна просто кнопка с текстом.

Чтобы вызвать клавиатуру пишем боту Kkk или kkk. Он отвечает, как бы обычно но в конце в комманде после текста keyboard — тут она и вылезает в чате.

Далее ловим ответы с кнопок bot.on и if — тут я хотел просто посылать текст комманды на которые должен реагировать бот — нет не сработало, пришлось описывать по полной. После нажатия на кнопку в её левом углу что-то крутится, и продолжает крутится какое то время даже когда ответ получен — раздражает. Оказалось, этого нет во всех примерах в Интернете, но это ошибка — после того как мы хватаем ответ с кнопки, надо в кнопку обратно ответить чтобы она не ждала и не крутилась. Для этого нужно ставить

bot.answerCallbackQuery(msg.id, "Done", false);

— если поставить true то Done будте видеть чатланен на весь экран и будет принужден еще нажать ОК.

Была загадка запустил раз клавиатуру получаешь по одному ответу, запустил второй раз получаешь два ответа на одно нажатие кнопки и так далее. Вынул обработчик нажатий кнопок из вызова клавиатуры, достаточно его отдельно один раз запустить и он все обработает, а то было сколько клавиатур столько обработок нажатий поэтому и ответы повторялись.

С этой клавой остается еще одна загадка она срабатывает если в чате послать /(исправляется заменой K на подлиннее Kkk но почему).