Add files via upload
This commit is contained in:
parent
973ad00377
commit
0adfd4c1ed
|
@ -0,0 +1,249 @@
|
|||
|
||||
|
||||
// Version 0.1 25-04-2020
|
||||
// - special for ESP8266, gmail works on port = 465
|
||||
|
||||
|
||||
#ifndef Email_Support_h
|
||||
#define Email_Support_h 0.1
|
||||
|
||||
|
||||
// ***********************************************************************************
|
||||
// Encode64 is based on the code from AlertMe
|
||||
// ***********************************************************************************
|
||||
const char PROGMEM b64_alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"0123456789+/";
|
||||
|
||||
|
||||
// ***********************************************************************************
|
||||
inline void a3_to_a4(unsigned char * a4, unsigned char * a3) {
|
||||
a4[0] = (a3[0] & 0xfc) >> 2;
|
||||
a4[1] = ((a3[0] & 0x03) << 4) + ((a3[1] & 0xf0) >> 4);
|
||||
a4[2] = ((a3[1] & 0x0f) << 2) + ((a3[2] & 0xc0) >> 6);
|
||||
a4[3] = (a3[2] & 0x3f);
|
||||
}
|
||||
|
||||
// ***********************************************************************************
|
||||
int base64_encode(char *output, char *input, int inputLen) {
|
||||
int i = 0, j = 0;
|
||||
int encLen = 0;
|
||||
unsigned char a3[3];
|
||||
unsigned char a4[4];
|
||||
|
||||
while (inputLen--) {
|
||||
a3[i++] = *(input++);
|
||||
if (i == 3) {
|
||||
a3_to_a4(a4, a3);
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
output[encLen++] = pgm_read_byte(&b64_alphabet[a4[i]]);
|
||||
}
|
||||
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (i) {
|
||||
for (j = i; j < 3; j++) {
|
||||
a3[j] = '\0';
|
||||
}
|
||||
|
||||
a3_to_a4(a4, a3);
|
||||
|
||||
for (j = 0; j < i + 1; j++) {
|
||||
output[encLen++] = pgm_read_byte(&b64_alphabet[a4[j]]);
|
||||
}
|
||||
|
||||
while ((i++ < 3)) {
|
||||
output[encLen++] = '=';
|
||||
}
|
||||
}
|
||||
output[encLen] = '\0';
|
||||
return encLen;
|
||||
}
|
||||
|
||||
// ***********************************************************************************
|
||||
int base64_enc_length(int plainLen) {
|
||||
int n = plainLen;
|
||||
return (n + 2 - ((n + 2) % 3)) / 3 * 4;
|
||||
}
|
||||
|
||||
// ***********************************************************************************
|
||||
const char* encode64_f ( char* Line , uint8_t len ) {
|
||||
int encodedLen = base64_enc_length(len);
|
||||
static char encoded[256];
|
||||
// note input is consumed in this step: it will be empty afterwards
|
||||
base64_encode ( encoded, Line, len );
|
||||
return encoded;
|
||||
}
|
||||
|
||||
// ****************************************************************************
|
||||
// ****************************************************************************
|
||||
String Encode64 ( String Line ) {
|
||||
const int MaxLen = 100 ;
|
||||
|
||||
char Copy[MaxLen] ;
|
||||
Line.toCharArray ( Copy, MaxLen );
|
||||
|
||||
String Result = encode64_f ( Copy, Line.length() ) ;
|
||||
return Result ;
|
||||
}
|
||||
|
||||
|
||||
#ifndef ESP32
|
||||
#include <WiFiClientSecure.h>
|
||||
|
||||
// ***********************************************************************************
|
||||
bool Email_Wait ( WiFiClientSecure &Mail_Client, String Response = "", uint16_t timeOut = 10000 ) {
|
||||
uint32_t ts = millis();
|
||||
while ( !Mail_Client.available () ) {
|
||||
if ( millis() > ( ts + timeOut ) ) {
|
||||
Serial.println ( "ERROR: Email_Wait timed out" ) ;
|
||||
return false;
|
||||
}
|
||||
yield();
|
||||
}
|
||||
String Server_Response = Mail_Client.readStringUntil ( '\n' ) ;
|
||||
Serial.println ( "Waiting for: "+ Response + " Received: " + Server_Response ) ;
|
||||
if ( ( Response.length() > 0 ) && Server_Response.indexOf ( Response ) == -1 ) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// ***********************************************************************************
|
||||
// ***********************************************************************************
|
||||
class _Email_Client_Class {
|
||||
public:
|
||||
|
||||
// _Email_Client_Class **************************************************
|
||||
// ***********************************************************************
|
||||
_Email_Client_Class ( String xSMTP_Server, int xSMTP_Port,
|
||||
String xSMTP_User, String xSMTP_PWD, String xSMTP_MailTo ) {
|
||||
this->_SMTP_Server = xSMTP_Server ;
|
||||
this->_SMTP_Port = xSMTP_Port ;
|
||||
this->_SMTP_User = xSMTP_User ;
|
||||
this->_SMTP_PWD = xSMTP_PWD ;
|
||||
this->_SMTP_MailTo = xSMTP_MailTo ;
|
||||
}
|
||||
_Email_Client_Class ( String xSMTP_Server, int xSMTP_Port,
|
||||
String xSMTP_User, String xSMTP_PWD ) {
|
||||
this->_SMTP_Server = xSMTP_Server ;
|
||||
this->_SMTP_Port = xSMTP_Port ;
|
||||
this->_SMTP_User = xSMTP_User ;
|
||||
this->_SMTP_PWD = xSMTP_PWD ;
|
||||
this->_SMTP_MailTo = xSMTP_User ;
|
||||
|
||||
}
|
||||
|
||||
|
||||
// _Email_Client_Class **************************************************
|
||||
// ***********************************************************************
|
||||
bool Send_Mail ( String MailTo, String Subject, String Message, bool HTML_Format = false ) {
|
||||
|
||||
if ( WiFi.status () != WL_CONNECTED ) {
|
||||
WiFi.mode ( WIFI_STA ) ;
|
||||
WiFi.begin ( __SECRET_Wifi_Name, __SECRET_Wifi_PWD ) ;
|
||||
Serial.println ( "..... Trying to connect to " + String ( __SECRET_Wifi_Name ) ) ;
|
||||
while ( WiFi.status () != WL_CONNECTED ) {
|
||||
delay ( 500 ) ;
|
||||
Serial.print ( "." ) ;
|
||||
}
|
||||
Serial.println () ;
|
||||
}
|
||||
|
||||
Serial.println ( "Connecting to mailserver:" + this->_SMTP_Server + " Port:" + String (this->_SMTP_Port ));
|
||||
|
||||
WiFiClientSecure Email_Client ;
|
||||
Email_Client.setInsecure () ;
|
||||
delay(1000);
|
||||
|
||||
if ( !Email_Client.connect( this->_SMTP_Server, this->_SMTP_Port )) {
|
||||
Serial.println ( "Could not connect to mail server:" + this->_SMTP_Server +" Port:" + String(this->_SMTP_Port) ) ;
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !Email_Wait ( Email_Client, "220" ) ) {
|
||||
Serial.println( "Connection Error");
|
||||
return false;
|
||||
}
|
||||
|
||||
Email_Client.println ( "HELO friend" ) ;
|
||||
if ( !Email_Wait ( Email_Client, "250" ) ) {
|
||||
Serial.println( "identification error");
|
||||
return false;
|
||||
}
|
||||
|
||||
Email_Client.println ( "AUTH LOGIN" ) ;
|
||||
Email_Wait ( Email_Client, "" ) ;
|
||||
|
||||
Email_Client.println ( Encode64 ( this->_SMTP_User ) ) ;
|
||||
Email_Wait ( Email_Client, "" ) ;
|
||||
|
||||
Email_Client.println ( Encode64 ( this->_SMTP_PWD ) ) ;
|
||||
if ( !Email_Wait ( Email_Client, "235" ) ) {
|
||||
Serial.println( "SMTP AUTH error");
|
||||
return false;
|
||||
}
|
||||
|
||||
String mailFrom = "MAIL FROM: <MiRa@gmail.com>" ;
|
||||
Email_Client.println ( mailFrom ) ;
|
||||
Email_Wait ( Email_Client, "" ) ;
|
||||
|
||||
String Recipient = "RCPT TO: <" + MailTo + ">" ;
|
||||
Email_Client.println ( Recipient ) ;
|
||||
Email_Wait ( Email_Client, "" ) ;
|
||||
|
||||
Email_Client.println ( "DATA" ) ;
|
||||
if ( !Email_Wait ( Email_Client, "354" ) ) {
|
||||
Serial.println( "SMTP DATA error");
|
||||
return false;
|
||||
}
|
||||
|
||||
String From = "From: <" + this->_SMTP_User + ">" ;
|
||||
Email_Client.println ( From ) ;
|
||||
String To = "To: <" + MailTo + ">" ;
|
||||
Email_Client.println( To );
|
||||
|
||||
Email_Client.print ( "Subject: " );
|
||||
Email_Client.println ( Subject ) ;
|
||||
|
||||
Email_Client.println ( "Mime-Version: 1.0" ) ;
|
||||
Email_Client.println ( "Content-Type: text/html; charset=\"UTF-8\"" ) ;
|
||||
Email_Client.println ( "Content-Transfer-Encoding: 7bit" ) ;
|
||||
Email_Client.println () ;
|
||||
String Body = Message ;
|
||||
if ( HTML_Format ) Body = "<!DOCTYPE html><html lang=\"en\">" + Message + "</html>" ;
|
||||
Email_Client.println ( Body ) ;
|
||||
Email_Client.println ("." ) ;
|
||||
if (!Email_Wait ( Email_Client, "250" ) ) {
|
||||
Serial.println( "Sending message error");
|
||||
return false;
|
||||
}
|
||||
|
||||
Email_Client.println ( "QUIT" ) ;
|
||||
if ( !Email_Wait ( Email_Client, "221" ) ) {
|
||||
Serial.println( "SMTP QUIT error" ) ;
|
||||
return false ;
|
||||
}
|
||||
return true ;
|
||||
}
|
||||
|
||||
bool Send_Mail ( String Subject, String Message ) {
|
||||
return this-> Send_Mail ( this->_SMTP_MailTo, Subject, Message ) ;
|
||||
}
|
||||
|
||||
|
||||
// _Email_Client_Class **************************************************
|
||||
// ***********************************************************************
|
||||
private :
|
||||
String _SMTP_Server ;
|
||||
int _SMTP_Port ;
|
||||
String _SMTP_User ;
|
||||
String _SMTP_PWD ;
|
||||
String _SMTP_MailTo ;
|
||||
|
||||
} ;
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -98,8 +98,8 @@ class _FS_class {
|
|||
if ( !this->_Opened ) {
|
||||
this->_Opened = SPIFFS.begin ( true ) ; // format if no filesystem yet
|
||||
}
|
||||
Serial.println ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ" ) ;
|
||||
Serial.println ( this->_Opened ) ;
|
||||
//Serial.println ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ" ) ;
|
||||
//Serial.println ( this->_Opened ) ;
|
||||
if ( this->_Opened ) {
|
||||
if ( _Parse_Filename ( Filename ) ) {
|
||||
String Last_File_Pre = _Temp_Last_File_Pre ;
|
||||
|
|
|
@ -213,9 +213,10 @@ class _My_Settings_Class {
|
|||
// ***********************************************************************
|
||||
String Get_Set_Default_String ( String Key, String Default, bool Force = false ) {
|
||||
String Value = _My_Settings_Buffer [ Key ].as<String>();
|
||||
Serial.println ( "Get_Set_Default_String ::: " + Value + "::: " + Default + " ;;; " + String (Force) ) ;
|
||||
//Serial.println ( "Get_Set_Default_String ::: " + Value + "::: " + Default + " ;;; " + String (Force) ) ;
|
||||
if ( Force || ( Value == "null" ) ) {
|
||||
_My_Settings_Buffer [ Key ] = Default ;
|
||||
//Serial.println ( Key + "---" + String(Default) ) ;
|
||||
UnStored_Changes = true ;
|
||||
return Default ;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ class _Receiver_BaseClass {
|
|||
String MQTT_Callback_Topic = "" ;
|
||||
bool Character_Display = false ;
|
||||
bool _Is_Receiver_SDFat = false ;
|
||||
bool _Is_Receiver_Email = false ;
|
||||
bool Device_Active = true ;
|
||||
|
||||
// **********************************************************************************************
|
||||
|
@ -95,7 +96,7 @@ class _Receiver_BaseClass {
|
|||
// ***********************************************************************
|
||||
virtual bool Publish ( String Topic, String Payload ) {}
|
||||
virtual bool Publish_Without_ ( String Topic, String Payload ) {}
|
||||
virtual bool connected () {}
|
||||
virtual bool Connected () {}
|
||||
|
||||
// ***********************************************************************
|
||||
// even voor SSD1306
|
||||
|
|
|
@ -0,0 +1,211 @@
|
|||
|
||||
// Version 0.1 23-04-2020
|
||||
// - original release, only for ESP32
|
||||
|
||||
#ifndef Receiver_Email_h
|
||||
#define Receiver_Email_h 0.1
|
||||
|
||||
|
||||
#ifdef ESP32
|
||||
#include "ESP32_MailClient.h"
|
||||
|
||||
// should be part of the class
|
||||
SMTPData Mail_Client ;
|
||||
#else
|
||||
#include "Email_Support.h"
|
||||
#endif
|
||||
|
||||
|
||||
// _Receiver_Email ******************************************************************
|
||||
// ***********************************************************************************
|
||||
class _Receiver_Email : public _Receiver_BaseClass {
|
||||
public:
|
||||
|
||||
// _Receiver_Email ******************************************************
|
||||
// ***********************************************************************
|
||||
_Receiver_Email (){
|
||||
this -> Default_Settings () ;
|
||||
this -> Constructor_Finish () ;
|
||||
}
|
||||
_Receiver_Email ( String xSMTP_Server, int xSMTP_Port, String xSMTP_User, String xSMTP_Password ){
|
||||
this->_SMTP_Server = xSMTP_Server ;
|
||||
this->_SMTP_Port = xSMTP_Port ;
|
||||
this->_SMTP_User = xSMTP_User ;
|
||||
this->_SMTP_PWD = xSMTP_Password ;
|
||||
this -> Constructor_Finish () ;
|
||||
}
|
||||
|
||||
// _Sensor_RFLink ********************************************************
|
||||
// ***********************************************************************
|
||||
void Constructor_Finish () {
|
||||
this->_Is_Receiver_Email = true ;
|
||||
|
||||
Version_Name = "V" + String ( Receiver_Email_h ) + " Receiver_Email.h" ;
|
||||
Serial.println ( "CREATE " + Version_Name ) ;
|
||||
}
|
||||
|
||||
// _Receiver_Email ******************************************************
|
||||
// ***********************************************************************
|
||||
void setup () {
|
||||
//Serial.print ( "SETUP of _Send_BaseClass, ID = " ) ;
|
||||
//External_Watchdog_Disarm () ;
|
||||
}
|
||||
|
||||
// _Receiver_Email ******************************************************
|
||||
// ***********************************************************************
|
||||
void Default_Settings ( bool Force = false ) {
|
||||
#ifdef __SECRET_SMTP_Server
|
||||
this->_SMTP_Server = Settings.Get_Set_Default_String ( "Email Server", __SECRET_SMTP_Server, Force ) ;
|
||||
#else
|
||||
this->_SMTP_Server = Settings.Get_Set_Default_String ( "Email Server", "smtp.gmail.com" , Force ) ;
|
||||
#endif
|
||||
|
||||
#ifdef __SECRET_SMTP_Port
|
||||
this->_SMTP_Port = Settings.Get_Set_Default_Int ( "Email Port", __SECRET_SMTP_Port, Force ) ;
|
||||
#else
|
||||
this->_SMTP_Port = Settings.Get_Set_Default_Int ( "Email Port", 465 , Force ) ;
|
||||
#endif
|
||||
|
||||
#ifdef __SECRET_SMTP_User
|
||||
this->_SMTP_User = Settings.Get_Set_Default_String ( "Email User", __SECRET_SMTP_User, Force ) ;
|
||||
#else
|
||||
this->_SMTP_User = Settings.Get_Set_Default_String ( "Email User", "User@gmail.com" , Force ) ;
|
||||
#endif
|
||||
|
||||
#ifdef __SECRET_SMTP_PWD
|
||||
this->_SMTP_PWD = Settings.Get_Set_Default_String ( "$Email Password" , __SECRET_SMTP_PWD, Force ) ;
|
||||
#else
|
||||
this->_SMTP_PWD = Settings.Get_Set_Default_String ( "$Email Password" , "Email Password" , Force ) ;
|
||||
#endif
|
||||
|
||||
#ifdef __SECRET_SMTP_MailTo
|
||||
this->_SMTP_MailTo = Settings.Get_Set_Default_String ( "Email To:", __SECRET_SMTP_MailTo, Force ) ;
|
||||
#else
|
||||
this->_SMTP_MailTo = Settings.Get_Set_Default_String ( "Email To:", this->_SMTP_User , Force ) ;
|
||||
#endif
|
||||
}
|
||||
|
||||
// _Receiver_Email ******************************************************
|
||||
// ***********************************************************************
|
||||
bool Check_Modified_Settings () {
|
||||
bool Restart = false ;
|
||||
|
||||
int New_Value_Int ;
|
||||
String New_Value ;
|
||||
|
||||
String xSMTP_Server = Settings.Read_String ( "Email Server" ) ;
|
||||
int xSMTP_Port = Settings.Read_Int ( "Email Port" ) ;
|
||||
String xSMTP_User = Settings.Read_String ( "Email User" ) ;
|
||||
String xSMTP_PWD = Settings.Read_String ( "$Email Password" ) ;
|
||||
String xSMTP_MailTo = Settings.Read_String ( "Email To:" ) ;
|
||||
|
||||
for ( int i=0; i<My_Webserver.args(); i++ ) {
|
||||
New_Value = My_Webserver.arg(i) ;
|
||||
New_Value_Int = (My_Webserver.arg(i)).toInt() ;
|
||||
|
||||
if ( My_Webserver.argName(i) == "Email Server" ) {
|
||||
if ( New_Value != xSMTP_Server ) {
|
||||
_My_Settings_Buffer [ "Email Server" ] = New_Value ;
|
||||
}
|
||||
}
|
||||
|
||||
else if ( My_Webserver.argName(i) == "Email Port" ) {
|
||||
if ( New_Value_Int != xSMTP_Port ) {
|
||||
_My_Settings_Buffer [ "Email Port" ] = New_Value_Int ;
|
||||
}
|
||||
}
|
||||
|
||||
else if ( My_Webserver.argName(i) == "Email User" ) {
|
||||
if ( New_Value != xSMTP_User ) {
|
||||
_My_Settings_Buffer [ "Email User" ] = New_Value ;
|
||||
}
|
||||
}
|
||||
|
||||
else if ( My_Webserver.argName(i) == "$Email Password" ) {
|
||||
if ( New_Value != xSMTP_PWD ) {
|
||||
_My_Settings_Buffer [ "$Email Password" ] = New_Value ;
|
||||
}
|
||||
}
|
||||
|
||||
else if ( My_Webserver.argName(i) == "Email To:" ) {
|
||||
if ( New_Value != xSMTP_MailTo ) {
|
||||
_My_Settings_Buffer [ "Email To:" ] = New_Value ;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return Restart ;
|
||||
}
|
||||
|
||||
// _Receiver_Email ******************************************************
|
||||
// ***********************************************************************
|
||||
#ifdef ESP32
|
||||
void Mail_Callback ( SendStatus msg ) {
|
||||
Serial.println ( msg.info () ) ;
|
||||
//Don know how to connect this method ????
|
||||
/*
|
||||
if (msg.success()) {
|
||||
Serial.println("----------------");
|
||||
}
|
||||
/*/
|
||||
}
|
||||
#endif
|
||||
|
||||
// _Receiver_Email ******************************************************
|
||||
// ***********************************************************************
|
||||
void Send_Email ( String MailTo, String Subject, String Body, bool HTML_Format=false ) {
|
||||
#ifdef ESP32
|
||||
if ( WiFi.status () == WL_CONNECTED ) {
|
||||
/*
|
||||
Serial.println ( "Server : " + this->_SMTP_Server ) ;
|
||||
Serial.println ( "Account: " + this->_SMTP_User ) ;
|
||||
Serial.println ( this->_SMTP_PWD );
|
||||
Serial.println ( "Port : " + (String) this->_SMTP_Port ) ;
|
||||
Serial.println ( "MailTo: " + MailTo ) ;
|
||||
//*/
|
||||
Mail_Client.setLogin ( this->_SMTP_Server, this->_SMTP_Port, this->_SMTP_User, this->_SMTP_PWD ) ;
|
||||
Mail_Client.setSTARTTLS ( true ) ;
|
||||
Mail_Client.setSender ( _Main_Name, this->_SMTP_User ) ;
|
||||
Mail_Client.setPriority ( "High" ) ;
|
||||
Mail_Client.setSubject ( Subject ) ;
|
||||
Mail_Client.setMessage ( Body, HTML_Format ) ;
|
||||
if ( MailTo.length() > 0 ) Mail_Client.addRecipient ( MailTo ) ;
|
||||
else Mail_Client.addRecipient ( this->_SMTP_User ) ;
|
||||
//Mail_Client.setSendCallback ( Receiver_Email_Callback ) ;
|
||||
|
||||
if ( MailClient.sendMail ( Mail_Client ) ) {
|
||||
Serial.println ( "Email send: " + Subject ) ;
|
||||
} else {
|
||||
Serial.println ( "ERROR: Receiver_Email, sending Email," + MailClient.smtpErrorReason () ) ;
|
||||
}
|
||||
|
||||
Mail_Client.empty () ;
|
||||
}
|
||||
|
||||
// ESP 8266 *********************************************************
|
||||
#else
|
||||
// WERKT NIET OM ONBEKENDE REDEN !!!!
|
||||
/*
|
||||
_Email_Client_Class My_Mail_Client ( this->_SMTP_Server, this->_SMTP_Port,
|
||||
this->_SMTP_User, this->_SMTP_PWD ) ;
|
||||
bool Result ;
|
||||
Result = My_Mail_Client.Send_Mail ( MailTo, Subject, Body, HTML_Format ) ;
|
||||
if ( Result ) Serial.println ( "Email Succeeded" ) ;
|
||||
else Serial.println ( "Email Failed" ) ;
|
||||
*/
|
||||
#endif
|
||||
}
|
||||
// ***********************************************************************
|
||||
private:
|
||||
// ***********************************************************************
|
||||
String _SMTP_Server = "";
|
||||
int _SMTP_Port ;
|
||||
String _SMTP_User ;
|
||||
String _SMTP_PWD ;
|
||||
String _SMTP_MailTo ;
|
||||
|
||||
bool Email_Do_Send = true ;
|
||||
|
||||
|
||||
};
|
||||
#endif
|
|
@ -82,9 +82,12 @@ class _Receiver_MQTT : public _Receiver_BaseClass {
|
|||
this -> Constructor_Finish () ;
|
||||
}
|
||||
|
||||
_Receiver_MQTT ( String Topic = "MQTT_Receiver/Test", bool Make_Device_Active = true ) { //, bool Keep_Connection = false ){
|
||||
// _Receiver_MQTT ( String Topic = "MQTT_Receiver/Test", bool Make_Device_Active = true ) { //, bool Keep_Connection = false ){
|
||||
_Receiver_MQTT ( String Topic="MQTT_Receiver/Test", String User="", String Password="" ) {
|
||||
MQTT_Topic = Topic ;
|
||||
this->Device_Active = Make_Device_Active ;
|
||||
this->_MQTT_User = User ;
|
||||
this->_MQTT_PWD = Password ;
|
||||
// this->Device_Active = Make_Device_Active ;
|
||||
this -> Constructor_Finish () ;
|
||||
}
|
||||
|
||||
|
@ -154,6 +157,8 @@ MyMQTT->setCallback ( _MQTT_Callback_Wrapper ) ;
|
|||
if ( ! this->Device_Active ) return ;
|
||||
MQTT_Topic = Settings.Get_Set_Default_String ( "MQTT Topic" , "huis/verdieping/kamer/ding", Force ) ;
|
||||
MQTT_Broker_IP = Settings.Get_Set_Default_String ( "MQTT Broker-IP", "192.168.0.18" , Force ) ;
|
||||
_MQTT_User = Settings.Get_Set_Default_String ( "MQTT User" , "" , Force ) ;
|
||||
_MQTT_PWD = Settings.Get_Set_Default_String ( "$MQTT Password", "" , Force ) ;
|
||||
}
|
||||
|
||||
// **********************************************************************************************
|
||||
|
@ -164,8 +169,10 @@ MyMQTT->setCallback ( _MQTT_Callback_Wrapper ) ;
|
|||
bool Restart = false ;
|
||||
|
||||
String New_Value ;
|
||||
String Topic = Settings.Read_String ( "MQTT Topic" ) ;
|
||||
String Broker = Settings.Read_String ( "MQTT Broker-IP" ) ;
|
||||
String Topic = Settings.Read_String ( "MQTT Topic" ) ;
|
||||
String Broker = Settings.Read_String ( "MQTT Broker-IP" ) ;
|
||||
String User = Settings.Read_String ( "MQTT User" ) ;
|
||||
String Password = Settings.Read_String ( "$MQTT Password" ) ;
|
||||
|
||||
for ( int i=0; i<My_Webserver.args(); i++ ) {
|
||||
New_Value = My_Webserver.arg(i) ;
|
||||
|
@ -176,12 +183,28 @@ MyMQTT->setCallback ( _MQTT_Callback_Wrapper ) ;
|
|||
Restart = true ;
|
||||
}
|
||||
}
|
||||
|
||||
else if ( My_Webserver.argName(i) == "MQTT Broker-IP" ) {
|
||||
if ( New_Value != Broker ) {
|
||||
_My_Settings_Buffer [ "MQTT Broker-IP" ] = New_Value ;
|
||||
Restart = true ;
|
||||
}
|
||||
}
|
||||
|
||||
else if ( My_Webserver.argName(i) == "MQTT User" ) {
|
||||
if ( New_Value != User ) {
|
||||
_My_Settings_Buffer [ "MQTT User" ] = New_Value ;
|
||||
Restart = true ;
|
||||
}
|
||||
}
|
||||
|
||||
else if ( My_Webserver.argName(i) == "$MQTT Password" ) {
|
||||
if ( New_Value != Password ) {
|
||||
_My_Settings_Buffer [ "$MQTT Password" ] = New_Value ;
|
||||
Restart = true ;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return Restart ;
|
||||
}
|
||||
|
@ -219,6 +242,8 @@ MyMQTT->setCallback ( _MQTT_Callback_Wrapper ) ;
|
|||
bool Publish ( String Topic, String Payload ) {
|
||||
return this->Publish_Without_ ( Topic + "_", Payload ) ;
|
||||
}
|
||||
|
||||
// ***********************************************************************
|
||||
bool Publish_Without_ ( String Topic, String Payload ) {
|
||||
if ( ! this->Device_Active ) return false ;
|
||||
|
||||
|
@ -245,6 +270,12 @@ Serial.println ( "Published To: " + this->_MQTT_Broker_IPx + " Topic: " + Top
|
|||
}
|
||||
|
||||
|
||||
// ***********************************************************************
|
||||
// ***********************************************************************
|
||||
bool Connected () {
|
||||
return MyMQTT->connected () ;
|
||||
}
|
||||
|
||||
// ***********************************************************************
|
||||
// ***********************************************************************
|
||||
bool Send_Data ( String Payload ) {
|
||||
|
@ -258,20 +289,23 @@ Serial.println ( " publish: " + MQTT_Topic + " // " + Payload ) ;
|
|||
// ***********************************************************************
|
||||
// ***********************************************************************
|
||||
private :
|
||||
int _State = 0 ;
|
||||
unsigned long _Error_Time = 0 ;
|
||||
int _State = 0 ;
|
||||
unsigned long _Error_Time = 0 ;
|
||||
String _MQTT_ID ;
|
||||
String _MQTT_User ;
|
||||
String _MQTT_PWD ;
|
||||
String _Subscription_Out ;
|
||||
String _LWT ;
|
||||
String _ALIVE ;
|
||||
unsigned long _ReConnect_Start = 0 ;
|
||||
int _ReConnect_Count = 0 ;
|
||||
String _MQTT_Broker_IPx ;
|
||||
|
||||
// unsigned long _State_Start = 0 ;
|
||||
String _MQTT_ID ;
|
||||
// int _MQTT_Connect_Retries ;
|
||||
// unsigned long _MQTT_Connect_Start ;
|
||||
// unsigned long _Alive_Time ;
|
||||
// bool _Keep_Connection ;
|
||||
String _Subscription_Out ;
|
||||
String _LWT ;
|
||||
String _ALIVE ;
|
||||
unsigned long _ReConnect_Start = 0 ;
|
||||
int _ReConnect_Count = 0 ;
|
||||
String _MQTT_Broker_IPx ;
|
||||
|
||||
|
||||
// ***********************************************************************
|
||||
|
@ -285,11 +319,20 @@ Serial.println ( " publish: " + MQTT_Topic + " // " + Payload ) ;
|
|||
#endif
|
||||
//*/
|
||||
|
||||
Serial.println ( "try reconnect 0 ") ;
|
||||
bool Result ;
|
||||
if ( this->_MQTT_User.length() > 0 ) {
|
||||
Result = MyMQTT->connect ( _MQTT_ID.c_str(), this->_MQTT_User.c_str(), this->_MQTT_PWD.c_str(),
|
||||
_Subscription_Out.c_str(), 1, 1, _LWT.c_str() ) ;
|
||||
}
|
||||
else {
|
||||
Result = MyMQTT->connect ( _MQTT_ID.c_str(),
|
||||
_Subscription_Out.c_str(), 1, 1, _LWT.c_str() ) ;
|
||||
}
|
||||
|
||||
//if ( MyMQTT->connect ( _MQTT_ID.c_str(), MQTT_User, MQTT_Pwd,
|
||||
if ( MyMQTT -> connect ( _MQTT_ID.c_str(),
|
||||
_Subscription_Out.c_str(), 1, 1, _LWT.c_str() )) {
|
||||
Serial.println ( "try reconnect 1 ") ;
|
||||
//if ( MyMQTT -> connect ( _MQTT_ID.c_str(),
|
||||
// _Subscription_Out.c_str(), 1, 1, _LWT.c_str() )) {
|
||||
if ( Result ) {
|
||||
Set_Signal_LED ( 4, 100, 100 ) ;
|
||||
for ( int i=0; i<MAX_MQTT_TOPICS; i++ ) {
|
||||
if ( MQTT_Topics[i].length() > 0 ) {
|
||||
|
@ -298,7 +341,6 @@ Set_Signal_LED ( 4, 100, 100 ) ;
|
|||
}
|
||||
else break ;
|
||||
}
|
||||
Serial.println ( "try reconnect 2 ") ;
|
||||
|
||||
if ( ToPublish.length() > 0 ) {
|
||||
MyMQTT->publish ( _Subscription_Out.c_str(), ToPublish.c_str() );
|
||||
|
|
|
@ -233,7 +233,7 @@ void Handle_Modifed_Settings () {
|
|||
Restart_Needed = true ;
|
||||
}
|
||||
else if ( ( My_Webserver.arg ( Key ) == "" ) && ( Value.as<bool>() ) ) {
|
||||
Serial.println ( "RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR " + Key + " // " + My_Webserver.arg ( Key ) ) ;
|
||||
//Serial.println ( "RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR " + Key + " // " + My_Webserver.arg ( Key ) ) ;
|
||||
_My_Settings_Buffer [ Key ] = false ;
|
||||
Restart_Needed = true ;
|
||||
}
|
||||
|
|
|
@ -88,9 +88,9 @@ class _Sensor_RFLink : public _Sensor_BaseClass {
|
|||
|
||||
this->MQTT_Callback_Topic = First_Part + "/from_HA/" ; //MQTT_Topic_Rec ;
|
||||
_RFLink_MQTT_Topic_Send = First_Part + "/from_RFLink/" ;
|
||||
Serial.println ( "xaaa" + MQTT_Topic ) ;
|
||||
Serial.println ( "xbbb" + MQTT_Callback_Topic ) ;
|
||||
Serial.println ( "xccc" + _RFLink_MQTT_Topic_Send ) ;
|
||||
//Serial.println ( "xaaa" + MQTT_Topic ) ;
|
||||
//Serial.println ( "xbbb" + MQTT_Callback_Topic ) ;
|
||||
//Serial.println ( "xccc" + _RFLink_MQTT_Topic_Send ) ;
|
||||
|
||||
Help_Text = " >>>>>>> ToDO Help tekst" ;
|
||||
}
|
||||
|
@ -120,9 +120,9 @@ Serial.println ( "xccc" + _RFLink_MQTT_Topic_Send ) ;
|
|||
|
||||
this->MQTT_Callback_Topic = First_Part + "/from_HA/" ; //MQTT_Topic_Rec ;
|
||||
_RFLink_MQTT_Topic_Send = First_Part + "/from_RFLink/" ;
|
||||
Serial.println ( "aaa" + MQTT_Topic ) ;
|
||||
Serial.println ( "bbb" + MQTT_Callback_Topic ) ;
|
||||
Serial.println ( "ccc" + _RFLink_MQTT_Topic_Send ) ;
|
||||
//Serial.println ( "aaa" + MQTT_Topic ) ;
|
||||
//Serial.println ( "bbb" + MQTT_Callback_Topic ) ;
|
||||
//Serial.println ( "ccc" + _RFLink_MQTT_Topic_Send ) ;
|
||||
|
||||
RFLink_File.Begin () ;
|
||||
|
||||
|
@ -177,22 +177,21 @@ Serial.println ( "ccc" + _RFLink_MQTT_Topic_Send ) ;
|
|||
}
|
||||
|
||||
if ( ( millis() - this->_Heartbeat_Last_Time ) > 60000 ) {
|
||||
//String Topic = MQTT_Topic_Send + "Heartbeat" ;
|
||||
String Topic = _RFLink_MQTT_Topic_Send + "Heartbeat" ;
|
||||
|
||||
String Payload ;
|
||||
Payload += "{\"Seconds\":" ;
|
||||
Payload += String ( millis() / 1000 ) ;
|
||||
Payload += ", \"RSSI\":" ;
|
||||
Payload += String ( WiFi.RSSI() ) ;
|
||||
Payload += "}" ;
|
||||
//String Topic = MQTT_Topic_Send + "Heartbeat" ;
|
||||
String Topic = _RFLink_MQTT_Topic_Send + "Heartbeat" ;
|
||||
|
||||
String Payload ;
|
||||
Payload += "{\"Seconds\":" ;
|
||||
Payload += String ( millis() / 1000 ) ;
|
||||
Payload += ", \"RSSI\":" ;
|
||||
Payload += String ( WiFi.RSSI() ) ;
|
||||
Payload += "}" ;
|
||||
//Serial.println ( "333" + Topic ) ;
|
||||
My_MQTT_Client->Publish_Without_ ( Topic, Payload );
|
||||
this->_Heartbeat_Last_Time = millis() ;
|
||||
}
|
||||
My_MQTT_Client->Publish_Without_ ( Topic, Payload );
|
||||
this->_Heartbeat_Last_Time = millis() ;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if ( Learning_Mode == 9 ) {
|
||||
if ( millis() > 2000 + _Learning_Mode_9_LastTime ) {
|
||||
if ( _Learning_Mode_9_State ) {
|
||||
|
@ -208,6 +207,32 @@ Serial.println ( "ccc" + _RFLink_MQTT_Topic_Send ) ;
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// ***********************************
|
||||
// On Restart, Send Email
|
||||
// ***********************************
|
||||
if ( this->First_Time_After_Restart_Email && ( WiFi.status () == WL_CONNECTED ) ) {
|
||||
//Serial.println ( "(((((((((((((((((((((((((((((((((((((((((" );
|
||||
this->First_Time_After_Restart_Email = false ;
|
||||
String Email_Subject = (String)_Main_Name + " Warning: Device Restarted" ;
|
||||
Send_Email ( "", Email_Subject, "", false ) ;
|
||||
}
|
||||
// ***********************************
|
||||
// On restart, Send Special MQTT message
|
||||
// ***********************************
|
||||
//((_Receiver_MQTT*)_p_Receiver_Email) -> Send_Email ( Mail_To, Subject, Body, HTML_Format ) ;
|
||||
if ( this->First_Time_After_Restart_MQTT && My_MQTT_Client->Connected() ) {
|
||||
String Topic = _RFLink_MQTT_Topic_Send + "Restarted" ;
|
||||
String Payload ;
|
||||
Payload += "{\"Seconds\":" ;
|
||||
Payload += String ( millis() / 1000 ) ;
|
||||
Payload += ", \"RSSI\":" ;
|
||||
Payload += String ( WiFi.RSSI() ) ;
|
||||
Payload += "}" ;
|
||||
My_MQTT_Client->Publish_Without_ ( Topic, Payload );
|
||||
this->First_Time_After_Restart_MQTT = false ;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -548,9 +573,12 @@ RFLink_File.Log_Line ( Line_2_File ) ;
|
|||
// ***********************************************************************
|
||||
private:
|
||||
// ***********************************************************************
|
||||
int _Receive_Pin = -1 ;
|
||||
int _Transmit_Pin = -1 ;
|
||||
unsigned long _Heartbeat_Last_Time = 0 ;
|
||||
int _Receive_Pin = -1 ;
|
||||
int _Transmit_Pin = -1 ;
|
||||
unsigned long _Heartbeat_Last_Time = 0 ;
|
||||
bool First_Time_After_Restart_Email = true ;
|
||||
bool First_Time_After_Restart_MQTT = true ;
|
||||
|
||||
|
||||
bool _Learning_Mode_9_State ;
|
||||
unsigned long _Learning_Mode_9_LastTime = 0 ;
|
||||
|
@ -581,7 +609,6 @@ RFLink_File.Log_Line ( Line_2_File ) ;
|
|||
|
||||
String Commands_Text = "\n\
|
||||
10;LIST; // list all commands\r\n\
|
||||
10;PRINT; // list all Known Devices\r\n\
|
||||
10;PING; // return PONG\r\n\
|
||||
10;REBOOT; // reboot RFLink\r\n\
|
||||
10;VERSION; // displays version information\r\n\
|
||||
|
@ -589,6 +616,7 @@ RFLink_File.Log_Line ( Line_2_File ) ;
|
|||
10;DEBUG=x; // Enter Learning/Debug Mode\r\n\
|
||||
12;Name;ID; // In Learning_Mode=1 add this device\r\n\
|
||||
X // In Learning_Mode=1 add the last seen Device\r\n\
|
||||
19;PRINT; // list all Known Devices\r\n\
|
||||
19;DIR; // Directory of the file-system\r\n\
|
||||
19;DUMP;Filename; // Print the content of the file\r\n\
|
||||
19:DEL;Filename; // Delete the file\r\n\
|
||||
|
|
|
@ -254,6 +254,7 @@ void Store_Modified_Settings_From_Webserver ( bool Restart_Needed ) ;
|
|||
//void Settings_Factory () ;
|
||||
void Set_Signal_LED ( int N, int On, int Off ) ;
|
||||
void Update_All_Headers () ;
|
||||
void Send_Email ( String Mail_To, String Subject, String Body, bool HTML_Format ) ;
|
||||
// ****************************************************************************
|
||||
|
||||
|
||||
|
@ -464,6 +465,7 @@ _Receiver_BaseClass *My_MQTT_Client ;
|
|||
bool _MQTT_Client_Available = false ;
|
||||
_Receiver_BaseClass *_Character_Display ;
|
||||
_Receiver_BaseClass *_p_Receiver_SDfat = NULL ;
|
||||
_Receiver_BaseClass *_p_Receiver_Email = NULL ;
|
||||
|
||||
|
||||
String MQTT_ID ;
|
||||
|
@ -473,7 +475,7 @@ void Debug ( String Line ) {
|
|||
}
|
||||
#ifndef NOT_INCLUDE_RECEIVER_MQTT
|
||||
if ( _Debug_Over_MQTT ) {
|
||||
if ( My_MQTT_Client->connected() ) {
|
||||
if ( My_MQTT_Client->Connected() ) {
|
||||
// ********************************************************
|
||||
// If MQTT_ID still empty, take the last part of MQTT_Topic
|
||||
// ********************************************************
|
||||
|
@ -1187,6 +1189,10 @@ void Settings_Factory () {
|
|||
|
||||
#include "Receiver_Serial.h"
|
||||
|
||||
#ifndef NOT_INCLUDE_RECEIVER_EMAIL
|
||||
#include "Receiver_Email.h"
|
||||
#endif
|
||||
|
||||
#ifndef NOT_INCLUDE_RECEIVER_SSD1306
|
||||
#include "Receiver_SSD1306.h"
|
||||
#endif
|
||||
|
@ -1246,6 +1252,10 @@ Serial.println ( "&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
|
|||
}
|
||||
#endif
|
||||
|
||||
if ( Receiver -> _Is_Receiver_Email ) {
|
||||
_p_Receiver_Email = Receiver ;
|
||||
}
|
||||
|
||||
External_Watchdog_Toggle () ;
|
||||
return Receiver ;
|
||||
}
|
||||
|
@ -1563,6 +1573,40 @@ Serial.println ( "Restart Needed total " + String (Restart_Needed) ) ;
|
|||
}
|
||||
|
||||
|
||||
|
||||
// ***********************************************************************************
|
||||
// Special function (only for ESP8266) to sed a mail on (re-)start
|
||||
// Call this function before any sensor or receiver is added!!!!
|
||||
// ***********************************************************************************
|
||||
void Restart_Email ( String MailTo, String Subject, String Body, bool HTML_Format=false ) {
|
||||
#ifndef ESP32
|
||||
_Email_Client_Class My_Mail_Client ( __SECRET_SMTP_Server, __SECRET_SMTP_Port,
|
||||
__SECRET_SMTP_User, __SECRET_SMTP_PWD ) ;
|
||||
|
||||
bool Result ;
|
||||
|
||||
Result = My_Mail_Client.Send_Mail ( MailTo, Subject, Body ) ;
|
||||
if ( Result ) Serial.println ( "Email Succeeded" ) ;
|
||||
else Serial.println ( "Email Failed" ) ;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// ********************************************************************************
|
||||
// ********************************************************************************
|
||||
void Send_Email ( String Mail_To, String Subject, String Body, bool HTML_Format=false ) {
|
||||
//Serial.println ( "PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP" + Subject ) ;
|
||||
#ifndef NOT_INCLUDE_RECEIVER_EMAIL
|
||||
if ( _p_Receiver_Email != NULL ){
|
||||
//Serial.println ( "(((((((((((((((((((((((((((((((((((((((((" );
|
||||
((_Receiver_Email*)_p_Receiver_Email) -> Send_Email ( Mail_To, Subject, Body, HTML_Format ) ;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int _Loop_Send_Time = 10000 ;
|
||||
unsigned long _Loop_Last_Time = 0 ;
|
||||
// ***********************************************************************************
|
||||
|
@ -1582,6 +1626,12 @@ void Settings_Setup () {
|
|||
Settings.Setup() ;
|
||||
// ************************************************************
|
||||
// ************************************************************
|
||||
|
||||
#ifndef NOT_INCLUDE_RECEIVER_EMAIL
|
||||
#ifndef ESP32
|
||||
Restart_Email ( __SECRET_SMTP_MailTo, "RFLink Restarted", "Body" ) ;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//??int Baudrate = Settings.Get_Set_Default_Int ( F("RS232 Baudrate"), 115200 ) ;
|
||||
int Baudrate = Settings.Get_Set_Default_Int ( "RS232 Baudrate", 115200 ) ;
|
||||
|
@ -1787,6 +1837,15 @@ void Settings_Setup () {
|
|||
_My_Settings_Buffer.remove ( F("Receiver_Fijnstof_Conditionering") ) ;
|
||||
#endif
|
||||
|
||||
#ifndef NOT_INCLUDE_RECEIVER_EMAIL
|
||||
if ( Settings.Read_Bool ( F("Receiver_Email") ) ) Receivers.Add ( new _Receiver_Email () ) ;
|
||||
else _My_Settings_Buffer [ F("Receiver_Email") ] = false ;
|
||||
#else
|
||||
_My_Settings_Buffer.remove ( F("Receiver_Email") ) ;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifndef NOT_INCLUDE_RECEIVER_MQTT
|
||||
if ( Settings.Read_Bool ( F("Receiver_MQTT") ) ) Receivers.Add ( new _Receiver_MQTT ( 684 ) ) ;
|
||||
else _My_Settings_Buffer [ F("Receiver_MQTT") ] = false ;
|
||||
|
|
|
@ -48,8 +48,8 @@ class _Sensor_Wifi : public _Sensor_BaseClass {
|
|||
this -> Constructor_Finish ( WIFI_OPTIONS_SINGLE ) ;
|
||||
}
|
||||
_Sensor_Wifi ( int Options = WIFI_OPTIONS_MUTIPLE ) {
|
||||
_Wifi_Name = Local_Wifi_Name ;
|
||||
_Wifi_PWD = Local_Wifi_PWD ;
|
||||
_Wifi_Name = __SECRET_Wifi_Name ;
|
||||
_Wifi_PWD = __SECRET_Wifi_PWD ;
|
||||
this -> Constructor_Finish ( Options ) ;
|
||||
}
|
||||
|
||||
|
@ -60,9 +60,9 @@ class _Sensor_Wifi : public _Sensor_BaseClass {
|
|||
Serial.println ( "CREATE " + Version_Name ) ;
|
||||
this -> _Wifi_Options = Options ;
|
||||
|
||||
#ifdef Local_Broker_IP
|
||||
#ifdef __SECRET_Broker_IP
|
||||
if ( MQTT_Broker_IP.length()== 0 ) {
|
||||
MQTT_Broker_IP = Local_Broker_IP ;
|
||||
MQTT_Broker_IP = __SECRET_Broker_IP ;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -97,14 +97,14 @@ class _Sensor_Wifi : public _Sensor_BaseClass {
|
|||
// **********************************************************************************************
|
||||
// **********************************************************************************************
|
||||
void Default_Settings ( bool Force = false ) {
|
||||
#ifdef Local_Wifi_Name
|
||||
_Wifi_Name = Settings.Get_Set_Default_String ( "Wifi-Netwerk" , Local_Wifi_Name, Force ) ;
|
||||
#ifdef __SECRET_Wifi_Name
|
||||
_Wifi_Name = Settings.Get_Set_Default_String ( "Wifi-Netwerk" , __SECRET_Wifi_Name, Force ) ;
|
||||
#else
|
||||
_Wifi_Name = Settings.Get_Set_Default_String ( "Wifi-Netwerk" , "lokaal Netwerk", Force ) ;
|
||||
#endif
|
||||
|
||||
#ifdef Local_Wifi_PWD
|
||||
_Wifi_PWD = Settings.Get_Set_Default_String ( "$Wifi-Password", Local_Wifi_PWD, Force ) ;
|
||||
#ifdef __SECRET_Wifi_PWD
|
||||
_Wifi_PWD = Settings.Get_Set_Default_String ( "$Wifi-Password", __SECRET_Wifi_PWD, Force ) ;
|
||||
#else
|
||||
_Wifi_PWD = Settings.Get_Set_Default_String ( "$Wifi-Password", "password", Force ) ;
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue