412 lines
12 KiB
C++
412 lines
12 KiB
C++
/*
|
|
notifications_service.cpp - notifications service functions class
|
|
|
|
Copyright (c) 2014 Luc Lebosse. All rights reserved.
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2.1 of the License, or (at your option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
License along with this library; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
//Inspired by following sources
|
|
//* Line :
|
|
// - https://github.com/TridentTD/TridentTD_LineNotify
|
|
// - https://notify-bot.line.me/doc/en/
|
|
//* Pushover:
|
|
// - https://github.com/ArduinoHannover/Pushover
|
|
// - https://pushover.net/api
|
|
//* Email:
|
|
// - https://github.com/CosmicBoris/ESP8266SMTP
|
|
// - https://www.electronicshub.org/send-an-email-using-esp8266/
|
|
|
|
#include "config.h"
|
|
#ifdef ENABLE_NOTIFICATIONS
|
|
#include "grbl.h"
|
|
#include "commands.h"
|
|
#include "notifications_service.h"
|
|
#include <WiFiClientSecure.h>
|
|
#include <Preferences.h>
|
|
#include <base64.h>
|
|
#include "wificonfig.h"
|
|
|
|
#define PUSHOVERTIMEOUT 5000
|
|
#define PUSHOVERSERVER "api.pushover.net"
|
|
#define PUSHOVERPORT 443
|
|
|
|
#define LINETIMEOUT 5000
|
|
#define LINESERVER "notify-api.line.me"
|
|
#define LINEPORT 443
|
|
|
|
#define EMAILTIMEOUT 5000
|
|
|
|
NotificationsService notificationsservice;
|
|
|
|
bool Wait4Answer(WiFiClientSecure & client, const char * linetrigger, const char * expected_answer, uint32_t timeout)
|
|
{
|
|
if(client.connected()) {
|
|
String answer;
|
|
uint32_t starttimeout = millis();
|
|
while (client.connected() && ((millis() -starttimeout) < timeout)) {
|
|
answer = client.readStringUntil('\n');
|
|
log_d("Answer: %s", answer.c_str());
|
|
if ((answer.indexOf(linetrigger) != -1) || (strlen(linetrigger) == 0)) {
|
|
break;
|
|
}
|
|
COMMANDS::wait(10);
|
|
}
|
|
if (strlen(expected_answer) == 0) {
|
|
log_d("Answer ignored as requested");
|
|
return true;
|
|
}
|
|
if(answer.indexOf(expected_answer) == -1) {
|
|
log_d("Did not got answer!");
|
|
return false;
|
|
} else {
|
|
log_d("Got expected answer");
|
|
return true;
|
|
}
|
|
}
|
|
log_d("Failed to send message");
|
|
return false;
|
|
}
|
|
|
|
NotificationsService::NotificationsService()
|
|
{
|
|
_started = false;
|
|
_notificationType = 0;
|
|
_token1 = "";
|
|
_token1 = "";
|
|
_settings = "";
|
|
}
|
|
NotificationsService::~NotificationsService()
|
|
{
|
|
end();
|
|
}
|
|
|
|
bool NotificationsService::started()
|
|
{
|
|
return _started;
|
|
}
|
|
|
|
const char * NotificationsService::getTypeString()
|
|
{
|
|
switch(_notificationType) {
|
|
case ESP_PUSHOVER_NOTIFICATION:
|
|
return "Pushover";
|
|
case ESP_EMAIL_NOTIFICATION:
|
|
return "Email";
|
|
case ESP_LINE_NOTIFICATION:
|
|
return "Line";
|
|
default:
|
|
break;
|
|
}
|
|
return "None";
|
|
}
|
|
|
|
bool NotificationsService::sendMSG(const char * title, const char * message)
|
|
{
|
|
if (!_started) return false;
|
|
if (!((strlen(title) == 0) && (strlen(message) == 0))) {
|
|
switch(_notificationType) {
|
|
case ESP_PUSHOVER_NOTIFICATION:
|
|
return sendPushoverMSG(title,message);
|
|
break;
|
|
case ESP_EMAIL_NOTIFICATION:
|
|
return sendEmailMSG(title,message);
|
|
break;
|
|
case ESP_LINE_NOTIFICATION :
|
|
return sendLineMSG(title,message);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
//Messages are currently limited to 1024 4-byte UTF-8 characters
|
|
//but we do not do any check
|
|
bool NotificationsService::sendPushoverMSG(const char * title, const char * message)
|
|
{
|
|
String data;
|
|
String postcmd;
|
|
bool res;
|
|
WiFiClientSecure Notificationclient;
|
|
if (!Notificationclient.connect(_serveraddress.c_str(), _port)) {
|
|
log_d("Error connecting server %s:%d", _serveraddress.c_str(), _port);
|
|
return false;
|
|
}
|
|
//build data for post
|
|
data = "user=";
|
|
data += _token1;
|
|
data += "&token=";
|
|
data += _token2;;
|
|
data +="&title=";
|
|
data += title;
|
|
data += "&message=";
|
|
data += message;
|
|
data += "&device=";
|
|
data += wifi_config.Hostname();
|
|
//build post query
|
|
postcmd = "POST /1/messages.json HTTP/1.1\r\nHost: api.pushover.net\r\nConnection: close\r\nCache-Control: no-cache\r\nUser-Agent: ESP3D\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\nContent-Length: ";
|
|
postcmd += data.length();
|
|
postcmd +="\r\n\r\n";
|
|
postcmd +=data;
|
|
log_d("Query: %s", postcmd.c_str());
|
|
//send query
|
|
Notificationclient.print(postcmd);
|
|
res = Wait4Answer(Notificationclient, "{", "\"status\":1", PUSHOVERTIMEOUT);
|
|
Notificationclient.stop();
|
|
return res;
|
|
}
|
|
bool NotificationsService::sendEmailMSG(const char * title, const char * message)
|
|
{
|
|
WiFiClientSecure Notificationclient;
|
|
log_d("Connect to server");
|
|
if (!Notificationclient.connect(_serveraddress.c_str(), _port)) {
|
|
log_d("Error connecting server %s:%d", _serveraddress.c_str(), _port);
|
|
return false;
|
|
}
|
|
//Check answer of connection
|
|
if(!Wait4Answer(Notificationclient, "220", "220", EMAILTIMEOUT)) {
|
|
log_d("Connection failed!");
|
|
return false;
|
|
}
|
|
//Do HELO
|
|
log_d("HELO");
|
|
Notificationclient.print("HELO friend\r\n");
|
|
if(!Wait4Answer(Notificationclient, "250", "250", EMAILTIMEOUT)) {
|
|
log_d("HELO failed!");
|
|
return false;
|
|
}
|
|
log_d("AUTH LOGIN");
|
|
//Request AUthentication
|
|
Notificationclient.print("AUTH LOGIN\r\n");
|
|
if(!Wait4Answer(Notificationclient, "334", "334", EMAILTIMEOUT)) {
|
|
log_d("AUTH LOGIN failed!");
|
|
return false;
|
|
}
|
|
log_d("Send LOGIN");
|
|
//sent Login
|
|
Notificationclient.printf("%s\r\n",_token1.c_str());
|
|
if(!Wait4Answer(Notificationclient, "334", "334", EMAILTIMEOUT)) {
|
|
log_d("Sent login failed!");
|
|
return false;
|
|
}
|
|
log_d("Send PASSWORD");
|
|
//Send password
|
|
Notificationclient.printf("%s\r\n",_token2.c_str());
|
|
if(!Wait4Answer(Notificationclient, "235", "235", EMAILTIMEOUT)) {
|
|
log_d("Sent password failed!");
|
|
return false;
|
|
}
|
|
log_d("MAIL FROM");
|
|
//Send From
|
|
Notificationclient.printf("MAIL FROM: <%s>\r\n",_settings.c_str());
|
|
if(!Wait4Answer(Notificationclient, "250", "250", EMAILTIMEOUT)) {
|
|
log_d("MAIL FROM failed!");
|
|
return false;
|
|
}
|
|
log_d("RCPT TO");
|
|
//Send To
|
|
Notificationclient.printf("RCPT TO: <%s>\r\n",_settings.c_str());
|
|
if(!Wait4Answer(Notificationclient, "250", "250", EMAILTIMEOUT)) {
|
|
log_d("RCPT TO failed!");
|
|
return false;
|
|
}
|
|
log_d("DATA");
|
|
//Send Data
|
|
Notificationclient.print("DATA\r\n");
|
|
if(!Wait4Answer(Notificationclient, "354", "354", EMAILTIMEOUT)) {
|
|
log_d("Preparing DATA failed!");
|
|
return false;
|
|
}
|
|
log_d("Send message");
|
|
//Send message
|
|
Notificationclient.printf("From:ESP3D<%s>\r\n",_settings.c_str());
|
|
Notificationclient.printf("To: <%s>\r\n",_settings.c_str());
|
|
Notificationclient.printf("Subject: %s\r\n\r\n",title);
|
|
Notificationclient.println(message);
|
|
|
|
log_d("Send final dot");
|
|
//Send Final dot
|
|
Notificationclient.print(".\r\n");
|
|
if(!Wait4Answer(Notificationclient, "250", "250", EMAILTIMEOUT)) {
|
|
log_d("Sending final dot failed!");
|
|
return false;
|
|
}
|
|
log_d("QUIT");
|
|
//Quit
|
|
Notificationclient.print("QUIT\r\n");
|
|
if(!Wait4Answer(Notificationclient, "221", "221", EMAILTIMEOUT)) {
|
|
log_d("QUIT failed!");
|
|
return false;
|
|
}
|
|
|
|
Notificationclient.stop();
|
|
return true;
|
|
}
|
|
bool NotificationsService::sendLineMSG(const char * title, const char * message)
|
|
{
|
|
String data;
|
|
String postcmd;
|
|
bool res;
|
|
WiFiClientSecure Notificationclient;
|
|
(void)title;
|
|
if (!Notificationclient.connect(_serveraddress.c_str(), _port)) {
|
|
log_d("Error connecting server %s:%d", _serveraddress.c_str(), _port);
|
|
return false;
|
|
}
|
|
//build data for post
|
|
data = "message=";
|
|
data += message;
|
|
//build post query
|
|
postcmd = "POST /api/notify HTTP/1.1\r\nHost: notify-api.line.me\r\nConnection: close\r\nCache-Control: no-cache\r\nUser-Agent: ESP3D\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\nContent-Type: application/x-www-form-urlencoded\r\n";
|
|
postcmd +="Authorization: Bearer ";
|
|
postcmd += _token1 + "\r\n";
|
|
postcmd += "Content-Length: ";
|
|
postcmd += data.length();
|
|
postcmd +="\r\n\r\n";
|
|
postcmd +=data;
|
|
log_d("Query: %s", postcmd.c_str());
|
|
//send query
|
|
Notificationclient.print(postcmd);
|
|
res = Wait4Answer(Notificationclient, "{", "\"status\":200", LINETIMEOUT);
|
|
Notificationclient.stop();
|
|
return res;
|
|
}
|
|
//Email#serveraddress:port
|
|
bool NotificationsService::getPortFromSettings()
|
|
{
|
|
Preferences prefs;
|
|
String defV = DEFAULT_TOKEN;
|
|
prefs.begin(NAMESPACE, true);
|
|
String tmp = prefs.getString(NOTIFICATION_TS, defV);
|
|
prefs.end();
|
|
int pos = tmp.lastIndexOf(':');
|
|
if (pos == -1) {
|
|
return false;
|
|
}
|
|
_port= tmp.substring(pos+1).toInt();
|
|
log_d("port : %d", _port);
|
|
if (_port > 0) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
//Email#serveraddress:port
|
|
bool NotificationsService::getServerAddressFromSettings()
|
|
{
|
|
Preferences prefs;
|
|
String defV = DEFAULT_TOKEN;
|
|
prefs.begin(NAMESPACE, true);
|
|
String tmp = prefs.getString(NOTIFICATION_TS, defV);
|
|
prefs.end();
|
|
int pos1 = tmp.indexOf('#');
|
|
int pos2 = tmp.lastIndexOf(':');
|
|
if ((pos1 == -1) || (pos2 == -1)) {
|
|
return false;
|
|
}
|
|
|
|
//TODO add a check for valid email ?
|
|
_serveraddress = tmp.substring(pos1+1, pos2);
|
|
log_d("server : %s", _serveraddress.c_str());
|
|
return true;
|
|
}
|
|
//Email#serveraddress:port
|
|
bool NotificationsService::getEmailFromSettings()
|
|
{
|
|
Preferences prefs;
|
|
String defV = DEFAULT_TOKEN;
|
|
prefs.begin(NAMESPACE, true);
|
|
String tmp = prefs.getString(NOTIFICATION_TS, defV);
|
|
prefs.end();
|
|
int pos = tmp.indexOf('#');
|
|
if (pos == -1) {
|
|
return false;
|
|
}
|
|
_settings = tmp.substring(0, pos);
|
|
log_d("email : %s", _settings.c_str());
|
|
//TODO add a check for valid email ?
|
|
return true;
|
|
}
|
|
|
|
|
|
bool NotificationsService::begin()
|
|
{
|
|
bool res = true;
|
|
end();
|
|
Preferences prefs;
|
|
String defV = DEFAULT_TOKEN;
|
|
prefs.begin(NAMESPACE, true);
|
|
_notificationType = prefs.getChar(NOTIFICATION_TYPE, DEFAULT_NOTIFICATION_TYPE);
|
|
switch(_notificationType) {
|
|
case 0: //no notification = no error but no start
|
|
return true;
|
|
case ESP_PUSHOVER_NOTIFICATION:
|
|
_token1 = prefs.getString(NOTIFICATION_T1, defV);
|
|
_token2 = prefs.getString(NOTIFICATION_T2, defV);
|
|
_port = PUSHOVERPORT;
|
|
_serveraddress = PUSHOVERSERVER;
|
|
break;
|
|
case ESP_LINE_NOTIFICATION:
|
|
_token1 = prefs.getString(NOTIFICATION_T1, defV);
|
|
_port = LINEPORT;
|
|
_serveraddress = LINESERVER;
|
|
break;
|
|
case ESP_EMAIL_NOTIFICATION:
|
|
_token1 = base64::encode(prefs.getString(NOTIFICATION_T1, defV));
|
|
_token2 = base64::encode(prefs.getString(NOTIFICATION_T2, defV));
|
|
//log_d("%s",Settings_ESP3D::read_string(ESP_NOTIFICATION_TOKEN1));
|
|
//log_d("%s",Settings_ESP3D::read_string(ESP_NOTIFICATION_TOKEN2));
|
|
if(!getEmailFromSettings() || !getPortFromSettings()|| !getServerAddressFromSettings()) {
|
|
prefs.end();
|
|
return false;
|
|
}
|
|
break;
|
|
default:
|
|
prefs.end();
|
|
return false;
|
|
break;
|
|
}
|
|
prefs.end();
|
|
if(WiFi.getMode() != WIFI_STA){
|
|
res = false;
|
|
}
|
|
if (!res) {
|
|
end();
|
|
}
|
|
_started = res;
|
|
return _started;
|
|
}
|
|
void NotificationsService::end()
|
|
{
|
|
if(!_started) {
|
|
return;
|
|
}
|
|
_started = false;
|
|
_notificationType = 0;
|
|
_token1 = "";
|
|
_token1 = "";
|
|
_settings = "";
|
|
_serveraddress = "";
|
|
_port = 0;
|
|
}
|
|
|
|
void NotificationsService::handle()
|
|
{
|
|
if (_started) {
|
|
}
|
|
}
|
|
|
|
#endif //ENABLE_NOTIFICATIONS
|