СМС-термометр из связки Google script, Google Doc, Wolfram-Alpha и Sms.ru

в 15:14, , рубрики: Google API, Google Docs, javascript, sms, Wolfram Alpha, погода, Программирование

Всем привет!
Захотел сделать так, чтобы на мой простенький телефон по утрам приходили оповещения о текущей погоде (разумеется, бесплатно). Потому, что нет обычного термометра, из-за этого насколько тепло нужно одеваться, понятно не всегда.
Кому интересно, как я это реализовал – добро пожаловать под кат.

Поискав что-то подобное на хабре, я наткнулся вот на эту статью, откуда узнал про сервис sms.ru, про Google script и прочее, за что отдельное спасибо.
Информацию о погоде решил получать с Wolfram-Alpha. Почему вольфрам-альфа? В своё время меня покорила строчка «данные взяты с метеостанции Баландино, 119 км от центра Златоуста». Поэтому мне хотелось брать информацию именно с этого сайта.

Итак, для начала нам нужно завести (если нет) аккаунт на Google, а так же зарегистрироваться на сервисе Sms.ru (если, опять же, нет). Сервис Sms.ru предоставляет на момент написания статьи 5 бесплатных сообщений на свой номер (на их сайте написано «для программистов»).

После успешной регистрации, переходим на гугл-диск (drive.google.com) и создаём новый пустой документ. Даём ему имя и ждём, пока он сохранится на диске.
Теперь переходим на script.google.com, выбираем Blank Project. Даём будущему скрипту какое-нибудь имя (скрипт также сохранится на гугл-диске). Удаляем всё, что там есть.
Теперь вставляем следующий код:

Код скрипта

function responseWeather()
{
//Здесь вписывается: город, телефонный номер для доставки SMS, уникальный ID с sms.ru, код документа Google
 var cityTown= "zlatoust";
 var phoneNum="71111111111";
 var apiID="111111111111111111111111111111111111";
 var docID="11111111111111111111111111111111111111111111";

//Открываем документ, в который будем записывать ответ с вольфрама 
 var serverAv = false;
 while (serverAv){
  try {
  DocumentApp.openById(docID);
  serverAv=true;
  } catch (e) {
 Logger.log('Ошибка открытия');
  }
 }
 var docmain = DocumentApp.openById(docID);
 var bodydoc = docmain.getBody();
 bodydoc.clear();//На всякий случай очищаем содержимое
 var response = UrlFetchApp.fetch("http://www.wolframalpha.com/input/?i="+cityTown+"+weather");
 bodydoc.setText(response);
 var textEdit = bodydoc.editAsText();
 textEdit.deleteText(0, 37280); //Удаляем начало документа, оно нам не нужно

/*
 При отладке температура выдаётся в Цельсиях.
 При запуске автоматом от триггера - в Фаренгейтах.
 Аналогично со скоростью ветра - ms и mph соотв.
 Отмечаем, что будем конвертировать.
*/
 if (textEdit.findText('°C')!=null){
 var degree = '°C';
 var convert = false;
  } else {
 degree = '°F';
 convert = true;
 }
// Находим всю нужную информацию
 textEdit.deleteText(0, textEdit.findText(degree).getStartOffset()-5); 
 textEdit.replaceText('</span><span class="info"><dt></dt><dd class="conditions">', ', ');
 textEdit.replaceText('</dd><dt>', '; ');
 textEdit.replaceText('wind:</dt><dd>', 'wind: ');
 textEdit.replaceText('<span> at </span>', ' at ');
 textEdit.replaceText('humidity:</dt><dd>', 'hum.: ');
 textEdit.deleteText(textEdit.findText("%").getEndOffsetInclusive()+1, textEdit.findText('"  />').getEndOffsetInclusive());
 textEdit.replaceText('<span  class="high">', ' (buf');
 textEdit.replaceText('</span><span class="low">', '...fub'); 
 textEdit.replaceText("</span>", ")</span>");
 textEdit.deleteText(textEdit.findText("</span>").getStartOffset(), textEdit.getText().length-1);

//В начале для метки оставалось несколько символов - теперь они больше не нужны, удаляем
 if (textEdit.findText('>')!=null){
   textEdit.deleteText(0, textEdit.findText('>').getEndOffsetInclusive());
 }
 
//Конвертация
 if (convert==true){
 //Конвертация первого значения температуры
 var buffer1 = textEdit.getText();
 textEdit.deleteText(textEdit.findText(degree).getStartOffset(), textEdit.getText().length-1);
 var len = textEdit.getText().length-1;
 var buffer2 = Number(textEdit.getText());
 bodydoc.clear();
 var result = Math.round((buffer2-32)/1.8);
 textEdit.setText(buffer1);
 textEdit.deleteText(0, len);
 textEdit.insertText(0, result);
 //Конвертация второго значения температуры
 buffer1 = textEdit.getText();
 textEdit.deleteText(0, textEdit.findText("buf").getEndOffsetInclusive());
 textEdit.deleteText(textEdit.findText(degree).getStartOffset(), textEdit.getText().length-1);
 len = textEdit.getText().length-1;
 buffer2 = Number(textEdit.getText());
 bodydoc.clear();
 result = Math.round((buffer2-32)/1.8);
 textEdit.setText(buffer1);
 textEdit.deleteText(textEdit.findText("buf").getEndOffsetInclusive()+1, textEdit.findText("buf").getEndOffsetInclusive()+1+len);
 textEdit.insertText(textEdit.findText("buf").getEndOffsetInclusive()+1, result);
 //Конвертация третьего значения температуры
 buffer1 = textEdit.getText();
 textEdit.deleteText(0, textEdit.findText('fub').getEndOffsetInclusive());
 textEdit.deleteText(textEdit.findText(degree).getStartOffset(), textEdit.getText().length-1);
 len = textEdit.getText().length-1;
 buffer2 = Number(textEdit.getText());
 bodydoc.clear();
 result = Math.round((buffer2-32)/1.8);
 textEdit.setText(buffer1);
 textEdit.deleteText(textEdit.findText('fub').getEndOffsetInclusive()+1,textEdit.findText('fub').getEndOffsetInclusive()+1+len);
 textEdit.insertText(textEdit.findText('fub').getEndOffsetInclusive()+1, result);
 //Конвертация скоррости ветра
 buffer1 = textEdit.getText();
 textEdit.deleteText(0, textEdit.findText('at ').getEndOffsetInclusive());
 textEdit.deleteText(textEdit.findText('mph').getStartOffset(), textEdit.getText().length-1);
 len = textEdit.getText().length-1;
 buffer2 = Number(textEdit.getText());
 bodydoc.clear();
 result = Math.round(buffer2*0.44704);
 textEdit.setText(buffer1);
 textEdit.deleteText(textEdit.findText('at ').getEndOffsetInclusive()+1,textEdit.findText('at ').getEndOffsetInclusive()+1+len);
 textEdit.insertText(textEdit.findText('at ').getEndOffsetInclusive()+1, result);
 textEdit.replaceText('mph', 'm/s');
};
 //Подчищаем...
 textEdit.replaceText('buf', '');
 textEdit.replaceText('fub', '');
 textEdit.replaceText(degree, "*C");
 
 //Дописываем в конец для какого города
 textEdit.insertText(textEdit.getText().length, '  '+cityTown);
  
//Если вдруг текст будет больше одного сообщения, то удаляем концовку
 if (textEdit.getText().length>70){
 textEdit.deleteText(69, textEdit.getText().length-1);
 }
 var textSMS = bodydoc.getText();

 UrlFetchApp.fetch("http://sms.ru/sms/send?api_id="+apiID+"&to="+phoneNum+"&text="+encodeURI(textSMS));
 bodydoc.clear();
}

Примечание. В коде отображается °C, а должно "& deg;C" (без пробела перед deg). Учтите это при копировании!

Вставляете в соответствующие переменные необходимые данные.
Переменная cityTown – город транслитом, для которого хотите получать погоду; phoneNum – номер, который вы зарегистрировали на Sms.ru и, соответственно, на который будут отправляться бесплатные СМС (без плюса и каких-либо разделителей); apiID – уникальный идентификатор для сервиса Sms.ru, смотреть на соответствующем сайте:
СМС термометр из связки Google script, Google Doc, Wolfram Alpha и Sms.ru

docID – уникальный идентификатор документа (не скрипта!) на гугл-диске. Найти можно в адресной строке:
СМС термометр из связки Google script, Google Doc, Wolfram Alpha и Sms.ru

После того, как все необходимые переменные заполнены, запускаем скрипт. При первом запуске скрипт запросит разрешение на работу с ссылками и документами на гугл-диске. Разрешаем всё. Скрипт должен отработать, и на телефон придёт сообщение.
Теперь осталось задать автоматический запуск. Для этого нажимаем на значок (1), выбираем необходимый интервал (2).

СМС термометр из связки Google script, Google Doc, Wolfram Alpha и Sms.ru

Так как мне нужно было знать погоду рано утром перед выходом на работу, я выставил таймер на 7 часов утра. Для себя я ещё выставил оповещения на почту в случае ошибки отработки кода – в интервале «незамедлительно».
Сохраняем триггер. Теперь всё готово, каждое утро будет приходить сообщение о текущей погоде.

Несколько замечаний по поводу кода. Я знаю javascript поверхностно, а google-script ещё меньше – поэтому, если есть какие-то замечания по оптимизации, буду рад узнать. По поводу конвертации из Фаренгейта в Цельсий. Видимо, Вольфраму передаются данные о местоположении запроса, и он подстраивает выводимые данные под регион. Поэтому, когда отладка скрипта идёт в онлайн-режиме (при запуске вручную), гугл передаёт, что я из России, а Вольфрам отвечает Цельсием и метрами в секунду. При запуске от триггера – Гугл говорит, что я в Калифорнии, из-за чего Вольфрам выдаёт Фаренгейты и мили в час.

На будущее я планирую ещё сделать запрос погоды через MMS – отправкой сообщения на почтовый ящик с текстом «город погода» и получением ответного сообщения. Может быть, спорное решение, просто у меня подключен давнишний пакет и MMS не особо дорогие.

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

Автор: morgreek

Источник



https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js