ESP3D  3.0
Firmware for ESP boards connected to 3D Printer
notifications_service.cpp
Go to the documentation of this file.
1 /*
2  notifications_service.cpp - notifications service functions class
3 
4  Copyright (c) 2014 Luc Lebosse. All rights reserved.
5 
6  This library is free software; you can redistribute it and/or
7  modify it under the terms of the GNU Lesser General Public
8  License as published by the Free Software Foundation; either
9  version 2.1 of the License, or (at your option) any later version.
10 
11  This library is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  Lesser General Public License for more details.
15 
16  You should have received a copy of the GNU Lesser General Public
17  License along with this library; if not, write to the Free Software
18  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20 //Inspired by following sources
21 //* Line :
22 // - https://github.com/TridentTD/TridentTD_LineNotify
23 // - https://notify-bot.line.me/doc/en/
24 //* Pushover:
25 // - https://github.com/ArduinoHannover/Pushover
26 // - https://pushover.net/api
27 //* Email:
28 // - https://github.com/CosmicBoris/ESP8266SMTP
29 // - https://www.electronicshub.org/send-an-email-using-esp8266/
30 
31 #include "../../include/esp3d_config.h"
32 #ifdef NOTIFICATION_FEATURE
33 #include "notifications_service.h"
34 #include "../../core/settings_esp3d.h"
35 #include "../../core/esp3doutput.h"
36 #include "../network/netconfig.h"
37 
38 #if defined( ARDUINO_ARCH_ESP8266)
39 #define USING_AXTLS
40 #if defined(USING_AXTLS)
41 #include "WiFiClientSecureAxTLS.h"
42 using namespace axTLS;
43 typedef axTLS::WiFiClientSecure TSecureClient;
44 #else
45 #include <WiFiClientSecure.h>
46 typedef WiFiClientSecure TSecureClient;
47 #endif //USING_AXTLS
48 #endif //ARDUINO_ARCH_ESP8266
49 
50 #if defined(ARDUINO_ARCH_ESP32)
51 #include <WiFiClientSecure.h>
52 typedef WiFiClientSecure TSecureClient;
53 #endif //ARDUINO_ARCH_ESP32
54 
55 #include <base64.h>
56 
57 #define PUSHOVERTIMEOUT 5000
58 #define PUSHOVERSERVER "api.pushover.net"
59 #define PUSHOVERPORT 443
60 
61 #define LINETIMEOUT 5000
62 #define LINESERVER "notify-api.line.me"
63 #define LINEPORT 443
64 
65 #define EMAILTIMEOUT 5000
66 
68 
69 bool Wait4Answer(TSecureClient & client, const char * linetrigger, const char * expected_answer, uint32_t timeout)
70 {
71  if(client.connected()) {
72  String answer;
73  uint32_t starttimeout = millis();
74  while (client.connected() && ((millis() -starttimeout) < timeout)) {
75  answer = client.readStringUntil('\n');
76  log_esp3d("Answer: %s", answer.c_str());
77  if ((answer.indexOf(linetrigger) != -1) || (strlen(linetrigger) == 0)) {
78  break;
79  }
80  Hal::wait(10);
81  }
82  if (strlen(expected_answer) == 0) {
83  log_esp3d("Answer ignored as requested");
84  return true;
85  }
86  if(answer.indexOf(expected_answer) == -1) {
87  log_esp3d("Did not got answer!");
88  return false;
89  } else {
90  log_esp3d("Got expected answer");
91  return true;
92  }
93  }
94  log_esp3d("Failed to send message");
95  return false;
96 }
97 
99 {
100  if (!(NetConfig::started()) || (NetConfig::getMode() != ESP_WIFI_STA)|| (!_started) || (!_autonotification)) {
101  log_esp3d("Auto notification rejected");
102  return false;
103  }
104  String msgtpl = msg;
105  //check if has variable to change
106  if (msgtpl.indexOf("%") != -1) {
107  msgtpl.replace("%ESP_IP%", WiFi.localIP().toString().c_str());
108  msgtpl.replace("%ESP_NAME%", NetConfig::hostname());
109  }
110  if (!sendMSG(ESP_NOTIFICATION_TITLE, msgtpl.c_str())) {
111  log_esp3d("Auto notification failed");
112  return false;
113  } else {
114  log_esp3d("Auto notification sent");
115  return true;
116  }
117 }
118 
120 {
121  _started = false;
122  _notificationType = 0;
123  _token1 = "";
124  _token1 = "";
125  _settings = "";
126 }
128 {
129  end();
130 }
131 
133 {
134  return _started;
135 }
136 
138 {
139  switch(_notificationType) {
141  return "Pushover";
143  return "Email";
145  return "Line";
146  default:
147  break;
148  }
149  return "None";
150 }
151 
152 bool NotificationsService::sendMSG(const char * title, const char * message)
153 {
154  if(!_started) {
155  return false;
156  }
157  if (!((strlen(title) == 0) && (strlen(message) == 0))) {
158  switch(_notificationType) {
160  return sendPushoverMSG(title,message);
161  break;
163  return sendEmailMSG(title,message);
164  break;
165  case ESP_LINE_NOTIFICATION :
166  return sendLineMSG(title,message);
167  break;
168  default:
169  break;
170  }
171  }
172  return false;
173 }
174 //Messages are currently limited to 1024 4-byte UTF-8 characters
175 //but we do not do any check
176 bool NotificationsService::sendPushoverMSG(const char * title, const char * message)
177 {
178  String data;
179  String postcmd;
180  bool res;
181 #pragma GCC diagnostic push
182 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
183  TSecureClient Notificationclient;
184 #pragma GCC diagnostic pop
185 #if defined(ARDUINO_ARCH_ESP8266) && !defined(USING_AXTLS)
186  Notificationclient.setInsecure();
187 #endif //ARDUINO_ARCH_ESP8266 && !USING_AXTLS
188  if (!Notificationclient.connect(_serveraddress.c_str(), _port)) {
189  log_esp3d("Error connecting server %s:%d", _serveraddress.c_str(), _port);
190  return false;
191  }
192  //build data for post
193  data = "user=";
194  data += _token1;
195  data += "&token=";
196  data += _token2;;
197  data +="&title=";
198  data += title;
199  data += "&message=";
200  data += message;
201  data += "&device=";
202  data += NetConfig::hostname();
203  //build post query
204  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: ";
205  postcmd += data.length();
206  postcmd +="\r\n\r\n";
207  postcmd +=data;
208  log_esp3d("Query: %s", postcmd.c_str());
209  //send query
210  Notificationclient.print(postcmd);
211  res = Wait4Answer(Notificationclient, "{", "\"status\":1", PUSHOVERTIMEOUT);
212  Notificationclient.stop();
213  return res;
214 }
215 bool NotificationsService::sendEmailMSG(const char * title, const char * message)
216 {
217 #pragma GCC diagnostic push
218 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
219  TSecureClient Notificationclient;
220 #pragma GCC diagnostic pop
221 #if defined(ARDUINO_ARCH_ESP8266) && !defined(USING_AXTLS)
222  Notificationclient.setInsecure();
223 #endif //ARDUINO_ARCH_ESP8266 && !USING_AXTLS
224  log_esp3d("Connect to server");
225  if (!Notificationclient.connect(_serveraddress.c_str(), _port)) {
226  log_esp3d("Error connecting server %s:%d", _serveraddress.c_str(), _port);
227  return false;
228  }
229  //Check answer of connection
230  if(!Wait4Answer(Notificationclient, "220", "220", EMAILTIMEOUT)) {
231  log_esp3d("Connection failed!");
232  return false;
233  }
234  //Do HELO
235  log_esp3d("HELO");
236  Notificationclient.print("HELO friend\r\n");
237  if(!Wait4Answer(Notificationclient, "250", "250", EMAILTIMEOUT)) {
238  log_esp3d("HELO failed!");
239  return false;
240  }
241  log_esp3d("AUTH LOGIN");
242  //Request AUthentication
243  Notificationclient.print("AUTH LOGIN\r\n");
244  if(!Wait4Answer(Notificationclient, "334", "334", EMAILTIMEOUT)) {
245  log_esp3d("AUTH LOGIN failed!");
246  return false;
247  }
248  log_esp3d("Send LOGIN");
249  //sent Login
250  Notificationclient.printf("%s\r\n",_token1.c_str());
251  if(!Wait4Answer(Notificationclient, "334", "334", EMAILTIMEOUT)) {
252  log_esp3d("Sent login failed!");
253  return false;
254  }
255  log_esp3d("Send PASSWORD");
256  //Send password
257  Notificationclient.printf("%s\r\n",_token2.c_str());
258  if(!Wait4Answer(Notificationclient, "235", "235", EMAILTIMEOUT)) {
259  log_esp3d("Sent password failed!");
260  return false;
261  }
262  log_esp3d("MAIL FROM");
263  //Send From
264  Notificationclient.printf("MAIL FROM: <%s>\r\n",_settings.c_str());
265  if(!Wait4Answer(Notificationclient, "250", "250", EMAILTIMEOUT)) {
266  log_esp3d("MAIL FROM failed!");
267  return false;
268  }
269  log_esp3d("RCPT TO");
270  //Send To
271  Notificationclient.printf("RCPT TO: <%s>\r\n",_settings.c_str());
272  if(!Wait4Answer(Notificationclient, "250", "250", EMAILTIMEOUT)) {
273  log_esp3d("RCPT TO failed!");
274  return false;
275  }
276  log_esp3d("DATA");
277  //Send Data
278  Notificationclient.print("DATA\r\n");
279  if(!Wait4Answer(Notificationclient, "354", "354", EMAILTIMEOUT)) {
280  log_esp3d("Preparing DATA failed!");
281  return false;
282  }
283  log_esp3d("Send message");
284  //Send message
285  Notificationclient.printf("From:ESP3D<%s>\r\n",_settings.c_str());
286  Notificationclient.printf("To: <%s>\r\n",_settings.c_str());
287  Notificationclient.printf("Subject: %s\r\n\r\n",title);
288  Notificationclient.println(message);
289 
290  log_esp3d("Send final dot");
291  //Send Final dot
292  Notificationclient.print(".\r\n");
293  if(!Wait4Answer(Notificationclient, "250", "250", EMAILTIMEOUT)) {
294  log_esp3d("Sending final dot failed!");
295  return false;
296  }
297  log_esp3d("QUIT");
298  //Quit
299  Notificationclient.print("QUIT\r\n");
300  if(!Wait4Answer(Notificationclient, "221", "221", EMAILTIMEOUT)) {
301  log_esp3d("QUIT failed!");
302  return false;
303  }
304 
305  Notificationclient.stop();
306  return true;
307 }
308 bool NotificationsService::sendLineMSG(const char * title, const char * message)
309 {
310  String data;
311  String postcmd;
312  bool res;
313 #pragma GCC diagnostic push
314 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
315  TSecureClient Notificationclient;
316 #pragma GCC diagnostic pop
317 #if defined(ARDUINO_ARCH_ESP8266) && !defined(USING_AXTLS)
318  Notificationclient.setInsecure();
319 #endif //ARDUINO_ARCH_ESP8266 && !USING_AXTLS
320  (void)title;
321  if (!Notificationclient.connect(_serveraddress.c_str(), _port)) {
322  log_esp3d("Error connecting server %s:%d", _serveraddress.c_str(), _port);
323  return false;
324  }
325  //build data for post
326  data = "message=";
327  data += message;
328  //build post query
329  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";
330  postcmd +="Authorization: Bearer ";
331  postcmd += _token1 + "\r\n";
332  postcmd += "Content-Length: ";
333  postcmd += data.length();
334  postcmd +="\r\n\r\n";
335  postcmd +=data;
336  log_esp3d("Query: %s", postcmd.c_str());
337  //send query
338  Notificationclient.print(postcmd);
339  res = Wait4Answer(Notificationclient, "{", "\"status\":200", LINETIMEOUT);
340  Notificationclient.stop();
341  return res;
342 }
343 //Email#serveraddress:port
344 bool NotificationsService::getPortFromSettings()
345 {
347  int pos = tmp.lastIndexOf(':');
348  if (pos == -1) {
349  return false;
350  }
351  _port= tmp.substring(pos+1).toInt();
352  log_esp3d("port : %d", _port);
353  if (_port > 0) {
354  return true;
355  } else {
356  return false;
357  }
358 }
359 //Email#serveraddress:port
360 bool NotificationsService::getServerAddressFromSettings()
361 {
363  int pos1 = tmp.indexOf('#');
364  int pos2 = tmp.lastIndexOf(':');
365  if ((pos1 == -1) || (pos2 == -1)) {
366  return false;
367  }
368 
369  //TODO add a check for valid email ?
370  _serveraddress = tmp.substring(pos1+1, pos2);
371  log_esp3d("server : %s", _serveraddress.c_str());
372  return true;
373 }
374 //Email#serveraddress:port
375 bool NotificationsService::getEmailFromSettings()
376 {
378  int pos = tmp.indexOf('#');
379  if (pos == -1) {
380  return false;
381  }
382  _settings = tmp.substring(0, pos);
383  log_esp3d("email : %s", _settings.c_str());
384  //TODO add a check for valid email ?
385  return true;
386 }
387 
388 
390 {
391  bool res = true;
392  end();
394  switch(_notificationType) {
395  case 0: //no notification = no error but no start
396  return true;
400  _port = PUSHOVERPORT;
401  _serveraddress = PUSHOVERSERVER;
402  break;
405  _port = LINEPORT;
406  _serveraddress = LINESERVER;
407  break;
409  _token1 = base64::encode(Settings_ESP3D::read_string(ESP_NOTIFICATION_TOKEN1));
410  _token2 = base64::encode(Settings_ESP3D::read_string(ESP_NOTIFICATION_TOKEN2));
411  //log_esp3d("%s",Settings_ESP3D::read_string(ESP_NOTIFICATION_TOKEN1));
412  //log_esp3d("%s",Settings_ESP3D::read_string(ESP_NOTIFICATION_TOKEN2));
413  if(!getEmailFromSettings() || !getPortFromSettings()|| !getServerAddressFromSettings()) {
414  return false;
415  }
416  break;
417  default:
418  return false;
419  break;
420  }
421  _autonotification = (Settings_ESP3D::read_byte(ESP_AUTO_NOTIFICATION) == 0) ? false: true;
422  if (!res) {
423  end();
424  }
425  _started = res;
426  return _started;
427 }
429 {
430  if(!_started) {
431  return;
432  }
433  _started = false;
434  _notificationType = 0;
435  _token1 = "";
436  _token1 = "";
437  _settings = "";
438  _serveraddress = "";
439  _port = 0;
440 }
441 
443 {
444  if (_started) {
445  }
446 }
447 
448 #endif //NOTIFICATION_FEATURE
ESP_NOTIFICATION_TITLE
#define ESP_NOTIFICATION_TITLE
Definition: configuration.h:262
NotificationsService::sendAutoNotification
bool sendAutoNotification(const char *msg)
Definition: notifications_service.cpp:98
ESP_EMAIL_NOTIFICATION
#define ESP_EMAIL_NOTIFICATION
Definition: defines.h:86
Settings_ESP3D::read_string
static const char * read_string(int pos, bool *haserror=NULL)
Definition: settings_esp3d.cpp:794
ESP_LINE_NOTIFICATION
#define ESP_LINE_NOTIFICATION
Definition: defines.h:87
Hal::wait
static void wait(uint32_t milliseconds)
Definition: hal.cpp:226
NotificationsService::begin
bool begin()
Definition: notifications_service.cpp:389
notificationsservice
NotificationsService notificationsservice
Definition: notifications_service.cpp:67
ESP_NOTIFICATION_TYPE
#define ESP_NOTIFICATION_TYPE
Definition: settings_esp3d.h:47
ESP_WIFI_STA
#define ESP_WIFI_STA
Definition: netconfig.h:41
NotificationsService::end
void end()
Definition: notifications_service.cpp:428
PUSHOVERSERVER
#define PUSHOVERSERVER
Definition: notifications_service.cpp:58
NotificationsService::handle
void handle()
Definition: notifications_service.cpp:442
PUSHOVERPORT
#define PUSHOVERPORT
Definition: notifications_service.cpp:59
ESP_AUTO_NOTIFICATION
#define ESP_AUTO_NOTIFICATION
Definition: settings_esp3d.h:89
NotificationsService::~NotificationsService
~NotificationsService()
Definition: notifications_service.cpp:127
ESP_NOTIFICATION_TOKEN1
#define ESP_NOTIFICATION_TOKEN1
Definition: settings_esp3d.h:69
Wait4Answer
bool Wait4Answer(TSecureClient &client, const char *linetrigger, const char *expected_answer, uint32_t timeout)
Definition: notifications_service.cpp:69
NetConfig::hostname
static const char * hostname(bool fromsettings=false)
Definition: netconfig.cpp:331
ESP_NOTIFICATION_SETTINGS
#define ESP_NOTIFICATION_SETTINGS
Definition: settings_esp3d.h:83
NotificationsService::getTypeString
const char * getTypeString()
Definition: notifications_service.cpp:137
notifications_service.h
NetConfig::getMode
static uint8_t getMode()
Definition: netconfig.cpp:207
LINESERVER
#define LINESERVER
Definition: notifications_service.cpp:62
NotificationsService::NotificationsService
NotificationsService()
Definition: notifications_service.cpp:119
NotificationsService::started
bool started()
Definition: notifications_service.cpp:132
NotificationsService::sendMSG
bool sendMSG(const char *title, const char *message)
Definition: notifications_service.cpp:152
EMAILTIMEOUT
#define EMAILTIMEOUT
Definition: notifications_service.cpp:65
LINETIMEOUT
#define LINETIMEOUT
Definition: notifications_service.cpp:61
log_esp3d
#define log_esp3d(format,...)
Definition: debug_esp3d.h:29
ESP_PUSHOVER_NOTIFICATION
#define ESP_PUSHOVER_NOTIFICATION
Definition: defines.h:85
LINEPORT
#define LINEPORT
Definition: notifications_service.cpp:63
NetConfig::started
static bool started()
Definition: netconfig.h:74
Settings_ESP3D::read_byte
static uint8_t read_byte(int pos, bool *haserror=NULL)
Definition: settings_esp3d.cpp:715
PUSHOVERTIMEOUT
#define PUSHOVERTIMEOUT
Definition: notifications_service.cpp:57
ESP_NOTIFICATION_TOKEN2
#define ESP_NOTIFICATION_TOKEN2
Definition: settings_esp3d.h:70
NotificationsService
Definition: notifications_service.h:27