new file: .idea/.idea.GSM-Chata.dir/.idea/.gitignore
new file: .idea/.idea.GSM-Chata.dir/.idea/encodings.xml
new file: .idea/.idea.GSM-Chata.dir/.idea/indexLayout.xml
new file: .idea/.idea.GSM-Chata.dir/.idea/vcs.xml
new file: .vscode/settings.json
modified: platformio.ini
new file: src/Data/DeviceBase.cpp
new file: src/Data/DeviceBase.h
new file: src/Data/GSMData.cpp
new file: src/Data/GSMData.h
new file: src/Data/PinTypeIn.cpp
new file: src/Data/PinTypeIn.h
new file: src/Data/PinTypeOut.cpp
new file: src/Data/PinTypeOut.h
new file: src/Device/EEPROMUtils.cpp
modified: src/Device/EEPROMUtils.h
new file: src/Device/GSMDevice.cpp
new file: src/Device/GSMDevice.h
new file: src/Device/WebServer.cpp
new file: src/Helper/HTMLGenerator.cpp
new file: src/Helper/HTMLGenerator.h
new file: src/PinDefinitions.cpp
new file: src/PinDefinitions.h
new file: src/Utills.cpp
new file: src/Utills.h
deleted: src/Zabezpecovacka-GSM.cpp
new file: src/main.cpp
This commit is contained in:
+13
@@ -0,0 +1,13 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Rider ignored files
|
||||||
|
/contentModel.xml
|
||||||
|
/modules.xml
|
||||||
|
/projectSettingsUpdater.xml
|
||||||
|
/.idea.GSM-Chata.iml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
||||||
+4
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
|
||||||
|
</project>
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="UserContentModel">
|
||||||
|
<attachedFolders />
|
||||||
|
<explicitIncludes />
|
||||||
|
<explicitExcludes />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
Generated
+6
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
Vendored
+5
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"files.associations": {
|
||||||
|
"pinsdefinitions": "c"
|
||||||
|
}
|
||||||
|
}
|
||||||
+4
-1
@@ -12,4 +12,7 @@
|
|||||||
platform = atmelavr
|
platform = atmelavr
|
||||||
board = uno
|
board = uno
|
||||||
framework = arduino
|
framework = arduino
|
||||||
lib_deps = arduino-libraries/Ethernet@^2.0.2
|
lib_deps =
|
||||||
|
arduino-libraries/Ethernet@^2.0.2
|
||||||
|
featherfly/SoftwareSerial@^1.0
|
||||||
|
build_flags = -DNDEBUG
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
class DeviceBase
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
String Id;
|
||||||
|
DeviceBase(const String id) : Id(id) {}
|
||||||
|
};
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
#ifndef _Device_h
|
||||||
|
#define _Device_h
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
class DeviceBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
String Id;
|
||||||
|
DeviceBase(const String id) : Id(id) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
#include <Arduino.h>
|
||||||
|
#include <Device/EEPROMUtils.h>
|
||||||
|
#include <Utills.h>
|
||||||
|
#include <Data/DeviceBase.h>
|
||||||
|
|
||||||
|
class GSMData : public DeviceBase
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
String MobileNumber;
|
||||||
|
String Sms;
|
||||||
|
|
||||||
|
GSMData(String id): DeviceBase(id)
|
||||||
|
{
|
||||||
|
MobileNumber = EEPROMUtils::ReadString(1, 20);
|
||||||
|
Sms = EEPROMUtils::ReadString(21, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateMobileNumber(const String &newMobileNumber)
|
||||||
|
{
|
||||||
|
MobileNumber = newMobileNumber;
|
||||||
|
EEPROMUtils::WriteString(1, newMobileNumber, 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateSMS(const String &newSMS)
|
||||||
|
{
|
||||||
|
Sms = newSMS;
|
||||||
|
EEPROMUtils::WriteString(21, newSMS, 100);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
#ifndef GSMData_H
|
||||||
|
#define GSMData_H
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <Device/EEPROMUtils.h>
|
||||||
|
#include <Utills.h>
|
||||||
|
#include <Data/DeviceBase.h>
|
||||||
|
|
||||||
|
class GSMData : public DeviceBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
String MobileNumber;
|
||||||
|
String Sms;
|
||||||
|
|
||||||
|
GSMData(String id): DeviceBase(id){};
|
||||||
|
|
||||||
|
void updateMobileNumber(const String &newMobileNumber);
|
||||||
|
|
||||||
|
void updateSMS(const String &newSMS);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // GSMData_H
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
#include <Arduino.h>
|
||||||
|
#include "DeviceBase.h"
|
||||||
|
|
||||||
|
class PinTypeIn : DeviceBase
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
int pin;
|
||||||
|
unsigned long debounceDelay;
|
||||||
|
unsigned long lastDebounceTime;
|
||||||
|
int lastButtonState;
|
||||||
|
int buttonState;
|
||||||
|
const char *description;
|
||||||
|
|
||||||
|
bool ReadValue()
|
||||||
|
{
|
||||||
|
int reading = digitalRead(pin);
|
||||||
|
|
||||||
|
if (reading != lastButtonState)
|
||||||
|
{
|
||||||
|
lastDebounceTime = millis();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((millis() - lastDebounceTime) > debounceDelay)
|
||||||
|
{
|
||||||
|
if (reading != buttonState)
|
||||||
|
{
|
||||||
|
buttonState = reading;
|
||||||
|
|
||||||
|
if (buttonState == HIGH)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lastButtonState = reading;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
PinTypeIn(String id, int pin, unsigned long debounceDelay, const char *description) : DeviceBase(id)
|
||||||
|
{
|
||||||
|
this->pin = pin;
|
||||||
|
this->debounceDelay = debounceDelay;
|
||||||
|
this->description = description;
|
||||||
|
|
||||||
|
lastDebounceTime = 0;
|
||||||
|
lastButtonState = LOW;
|
||||||
|
buttonState = LOW;
|
||||||
|
pinMode(pin, INPUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsSetPinValueToHigh()
|
||||||
|
{
|
||||||
|
return ReadValue();
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
#ifndef PinTypeIn_H
|
||||||
|
#define PinTypeIn_H
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <Data/DeviceBase.h>
|
||||||
|
|
||||||
|
class PinTypeIn : public DeviceBase
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
uint8_t pin;
|
||||||
|
unsigned long debounceDelay;
|
||||||
|
unsigned long lastDebounceTime;
|
||||||
|
int lastButtonState;
|
||||||
|
int buttonState;
|
||||||
|
|
||||||
|
bool ReadValue();
|
||||||
|
|
||||||
|
public:
|
||||||
|
PinTypeIn(String id, int pin, unsigned long debounceDelay, const char *description): DeviceBase(id){};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
#include <Arduino.h>
|
||||||
|
#include "DeviceBase.h"
|
||||||
|
#include "Utills.h"
|
||||||
|
|
||||||
|
class PinTypeOut : public DeviceBase
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
uint8_t pinNumber;
|
||||||
|
bool lastState;
|
||||||
|
unsigned long debounceTime;
|
||||||
|
unsigned long lastStateChangeTime;
|
||||||
|
const char *description;
|
||||||
|
|
||||||
|
public:
|
||||||
|
PinTypeOut(String id, uint8_t pinNumber, bool lastState, unsigned long debounceTime, const char *description)
|
||||||
|
: DeviceBase(id), pinNumber(pinNumber), lastState(lastState), debounceTime(debounceTime), lastStateChangeTime(0), description(description)
|
||||||
|
{
|
||||||
|
pinMode(pinNumber, OUTPUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkPin()
|
||||||
|
{
|
||||||
|
bool currentInputState = digitalRead(pinNumber);
|
||||||
|
if (currentInputState != lastState && millis() - lastStateChangeTime >= debounceTime)
|
||||||
|
{
|
||||||
|
lastState = currentInputState;
|
||||||
|
lastStateChangeTime = millis();
|
||||||
|
Utills::logDebug("Pin " + String(pinNumber) + " changed to " + String(lastState));
|
||||||
|
// Add pin state change logic here
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsTimeIgnoredPin()
|
||||||
|
{
|
||||||
|
bool currentInputState = digitalRead(pinNumber);
|
||||||
|
if (currentInputState != lastState && millis() - lastStateChangeTime >= debounceTime)
|
||||||
|
{
|
||||||
|
lastState = currentInputState;
|
||||||
|
lastStateChangeTime = millis();
|
||||||
|
// Add pin state change logic here
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetOutputSignalToHighWithtimeIgnoring()
|
||||||
|
{
|
||||||
|
if (IsTimeIgnoredPin())
|
||||||
|
{
|
||||||
|
digitalWrite(pinNumber, HIGH);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetOutputSignalToLowWithtimeIgnoring()
|
||||||
|
{
|
||||||
|
if (IsTimeIgnoredPin())
|
||||||
|
{
|
||||||
|
digitalWrite(pinNumber, LOW);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetOutputSignalToHigh()
|
||||||
|
{
|
||||||
|
digitalWrite(pinNumber, HIGH);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetOutputSignalToLow()
|
||||||
|
{
|
||||||
|
digitalWrite(pinNumber, LOW);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
#ifndef PinTypeOut_H
|
||||||
|
#define PinTypeOut_H
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include "DeviceBase.h"
|
||||||
|
#include "Utills.h"
|
||||||
|
|
||||||
|
class PinTypeOut : public DeviceBase
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
uint8_t pinNumber;
|
||||||
|
bool lastState;
|
||||||
|
unsigned long debounceTime;
|
||||||
|
unsigned long lastStateChangeTime;
|
||||||
|
const char *description;
|
||||||
|
|
||||||
|
public:
|
||||||
|
PinTypeOut(String id, uint8_t pinNumber, bool lastState, unsigned long debounceTime, const char *description)
|
||||||
|
: DeviceBase(id), pinNumber(pinNumber), lastState(lastState), debounceTime(debounceTime), lastStateChangeTime(0), description(description)
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @brief Ignoring input signal for debounce time
|
||||||
|
/// @return true is signal is ignored (debounced)
|
||||||
|
bool IsTimeIgnoredPin();
|
||||||
|
void SetOutputSignalToHighWithtimeIgnoring();
|
||||||
|
void SetOutputSignalToLowWithtimeIgnoring();
|
||||||
|
void SetOutputSignalToHigh();
|
||||||
|
void SetOutputSignalToLow();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // PinOutData_H
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
#include <EEPROM.h>
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
class EEPROMUtils
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Statická metoda pro čtení řetězce z EEPROM
|
||||||
|
static String ReadString(int addr, int length)
|
||||||
|
{
|
||||||
|
String data;
|
||||||
|
for (int i = 0; i < length; i++)
|
||||||
|
{
|
||||||
|
char onedata = char(EEPROM.read(addr + i)); // read one byte at a time
|
||||||
|
if (onedata == '\n')
|
||||||
|
return data;
|
||||||
|
data += onedata;
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Statická metoda pro zápis řetězce do EEPROM
|
||||||
|
static void WriteString(int addr, const String &data, int limit)
|
||||||
|
{
|
||||||
|
int numBytes = data.length(); // get length of the string
|
||||||
|
for (int i = 0; i < numBytes && i < limit; i++)
|
||||||
|
{
|
||||||
|
EEPROM.write(addr + i, data[i]); // write one byte at a time
|
||||||
|
}
|
||||||
|
if (numBytes < limit)
|
||||||
|
{
|
||||||
|
EEPROM.write(addr + numBytes, '\n'); // add newline character at the end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
#ifndef _EEPROMUtils_h
|
||||||
|
#define _EEPROMUtils_h
|
||||||
|
|
||||||
|
#include <SoftwareSerial.h>
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <Data/GSMData.h>
|
||||||
|
|
||||||
|
|
||||||
|
class EEPROMUtils
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static String ReadString(int addr, int length);
|
||||||
|
static void WriteString(int addr, const String &data, int limit);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
#include <Data/GSMData.h>
|
||||||
|
#include <SoftwareSerial.h>
|
||||||
|
|
||||||
|
class GSMDevice
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
SoftwareSerial gsmSerial;
|
||||||
|
|
||||||
|
void end()
|
||||||
|
{
|
||||||
|
gsmSerial.end();
|
||||||
|
Utills::logDebug("GSM End ..");
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExecuteAtCommand(const String &atCommand)
|
||||||
|
{
|
||||||
|
Utills::logDebug(atCommand);
|
||||||
|
gsmSerial.print(atCommand + "\r");
|
||||||
|
delay(500);
|
||||||
|
}
|
||||||
|
|
||||||
|
String ReadStringSerialPort()
|
||||||
|
{
|
||||||
|
return gsmSerial.readString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendSMSToGSM(GSMData gsmData)
|
||||||
|
{
|
||||||
|
Utills::logDebug("SMS Start SEND SMS Id:" + gsmData.Id + " M:" + gsmData.MobileNumber + " with message " + gsmData.Sms);
|
||||||
|
|
||||||
|
ExecuteAtCommand("AT+CMGF=1");
|
||||||
|
ExecuteAtCommand("AT + CMGS =\"" + gsmData.MobileNumber + "\"");
|
||||||
|
ExecuteAtCommand("ID:" + gsmData.Id + " Msg:" + gsmData.Sms);
|
||||||
|
|
||||||
|
delay(1000);
|
||||||
|
// Send a Ctrl+Z / ASCII SUB
|
||||||
|
gsmSerial.print((char)26);
|
||||||
|
delay(500);
|
||||||
|
// Close the connection
|
||||||
|
gsmSerial.print((char)27);
|
||||||
|
delay(500);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CheckSMSError()
|
||||||
|
{
|
||||||
|
String response = ReadStringSerialPort();
|
||||||
|
if (response.indexOf("ERROR") != -1)
|
||||||
|
{
|
||||||
|
// If there was an error, try to reconnect and resend
|
||||||
|
gsmSerial.println("AT+CFUN=1,1"); // Restart the module
|
||||||
|
delay(15000); // Wait for the module to restart
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
GSMDevice(uint8_t pinRx, uint8_t pinTx, long baudRate): gsmSerial(pinRx, pinTx)
|
||||||
|
{
|
||||||
|
//init software serial
|
||||||
|
gsmSerial.begin(baudRate);
|
||||||
|
Utills::logDebug("GSM Init ..");
|
||||||
|
delay(5000); // initialization GSM module (give it some time to boot up)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void sendSMS(GSMData gsmData)
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
sendSMSToGSM(gsmData);
|
||||||
|
|
||||||
|
if (CheckSMSError())
|
||||||
|
{
|
||||||
|
sendSMSToGSM(gsmData);
|
||||||
|
}
|
||||||
|
|
||||||
|
end();
|
||||||
|
}
|
||||||
|
|
||||||
|
~GSMDevice()
|
||||||
|
{
|
||||||
|
// close gsmSerial
|
||||||
|
// close gsmSerial
|
||||||
|
gsmSerial.end();
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
#ifndef GSMDevice_H
|
||||||
|
#define GSMDevice_H
|
||||||
|
|
||||||
|
#include <Data/GSMData.h>
|
||||||
|
#include <SoftwareSerial.h>
|
||||||
|
#include <Data/GSMData.h>
|
||||||
|
|
||||||
|
class GSMDevice
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
SoftwareSerial gsmSerial;
|
||||||
|
// Methods
|
||||||
|
void end();
|
||||||
|
void ExecuteAtCommand(const String &atCommand);
|
||||||
|
String ReadStringSerialPort();
|
||||||
|
void sendSMSToGSM(GSMData gsmData);
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Constructor
|
||||||
|
GSMDevice(uint8_t pinRx, uint8_t pinTx, long baudRate);
|
||||||
|
|
||||||
|
// Destructor
|
||||||
|
~GSMDevice();
|
||||||
|
|
||||||
|
// Methods
|
||||||
|
void sendSMS(GSMData gsmData);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // GSMDevice_H
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
#include <Arduino.h>
|
||||||
|
#include <Ethernet.h>
|
||||||
|
|
||||||
|
class WebServer {
|
||||||
|
private:
|
||||||
|
byte mac[6];
|
||||||
|
IPAddress ip;
|
||||||
|
EthernetServer server;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Constructor
|
||||||
|
WebServer(byte mac[6], IPAddress ip, uint16_t port) : ip(ip), server(port) {
|
||||||
|
// Initialization code here
|
||||||
|
memcpy(this->mac, mac, sizeof(this->mac));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize the Ethernet and start the server
|
||||||
|
void begin() {
|
||||||
|
Ethernet.begin(mac, ip);
|
||||||
|
server.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle client requests
|
||||||
|
void handleClient() {
|
||||||
|
// Check if a client has connected
|
||||||
|
EthernetClient client = server.available();
|
||||||
|
if (client) {
|
||||||
|
// An http request ends with a blank line
|
||||||
|
boolean currentLineIsBlank = true;
|
||||||
|
while (client.connected()) {
|
||||||
|
if (client.available()) {
|
||||||
|
char c = client.read();
|
||||||
|
// If you've gotten to the end of the line (received a newline
|
||||||
|
// character) and the line is blank, the http request has ended,
|
||||||
|
// so you can send a reply
|
||||||
|
if (c == '\n' && currentLineIsBlank) {
|
||||||
|
// Send a standard http response header
|
||||||
|
client.println("HTTP/1.1 200 OK");
|
||||||
|
client.println("Content-Type: text/html");
|
||||||
|
client.println("Connection: close"); // The connection will be closed after completion of the response
|
||||||
|
client.println();
|
||||||
|
client.println("<!DOCTYPE HTML>");
|
||||||
|
client.println("<html>");
|
||||||
|
// Add your HTML content here
|
||||||
|
client.println("</html>");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (c == '\n') {
|
||||||
|
// You're starting a new line
|
||||||
|
currentLineIsBlank = true;
|
||||||
|
} else if (c != '\r') {
|
||||||
|
// You've gotten a character on the current line
|
||||||
|
currentLineIsBlank = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Give the web browser time to receive the data
|
||||||
|
delay(1);
|
||||||
|
// Close the connection
|
||||||
|
client.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
class HTMLGenerator {
|
||||||
|
public:
|
||||||
|
|
||||||
|
static const String GetElement(const String& tag, const String& content, const String& attributes = "") {
|
||||||
|
String html_content = "";
|
||||||
|
if (attributes != "") {
|
||||||
|
html_content += "<" + tag + " " + attributes + ">" + content + "</" + tag + ">";
|
||||||
|
} else {
|
||||||
|
html_content += "<" + tag + ">" + content + "</" + tag + ">";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const String DisplayPinStatus(const String& status, const String& link, bool isOn) {
|
||||||
|
String element = isOn ? "H4" : "p";
|
||||||
|
String content = status + (link != "" ? " <a href=\"" + link + "\">" + (isOn ? "OFF" : "ON") + "</a>" : "");
|
||||||
|
return GetElement(element, content);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
#ifndef HTMLGENERATOR_H
|
||||||
|
#define HTMLGENERATOR_H
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
class HTMLGenerator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static const String GetElement(const String &tag, const String &content, const String &attributes = "");
|
||||||
|
static const String DisplayPinStatus(const String &status, const String &link, bool isOn);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // HTMLGENERATOR_H
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
#include <Data/PinTypeOut.h>
|
||||||
|
#include <Data/PinTypeIn.h>
|
||||||
|
|
||||||
|
class PinDefinitions
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
// PIN OUTPUT
|
||||||
|
static const int COUNT_OUTPUTS_PIN_OUT = 2;
|
||||||
|
static PinTypeOut PinIn8;
|
||||||
|
static PinTypeOut PinIn7;
|
||||||
|
static const PinTypeOut *INPUT_PINS_ARRAY[COUNT_OUTPUTS_PIN_OUT];
|
||||||
|
|
||||||
|
// PIN INPUT
|
||||||
|
static const int COUNT_INPUTS_PIN_IN = 2;
|
||||||
|
static PinTypeIn PinIn2;
|
||||||
|
static PinTypeIn PinIn3;
|
||||||
|
static const PinTypeIn *OUPUTS_PINS_ARRAY[COUNT_INPUTS_PIN_IN];
|
||||||
|
|
||||||
|
static const uint8_t GSM_PIN_RX = 10;
|
||||||
|
static const uint8_t GSM_PIN_TX = 11;
|
||||||
|
static const long GSM_BAUD_RATE = 115200;
|
||||||
|
|
||||||
|
PinDefinitions()
|
||||||
|
{
|
||||||
|
// PIN INPUT Inicialization
|
||||||
|
PinDefinitions::PinIn7 = PinTypeOut("PIN7", 7, LOW, 100, "Default Description");
|
||||||
|
PinDefinitions::PinIn8 = PinTypeOut("PIN8", 8, LOW, 10000, "Electric Alarm");
|
||||||
|
|
||||||
|
INPUT_PINS_ARRAY[0] = &PinDefinitions::PinIn7;
|
||||||
|
INPUT_PINS_ARRAY[1] = &PinDefinitions::PinIn8;
|
||||||
|
|
||||||
|
// PIN INPUT Inicialization
|
||||||
|
PinDefinitions::PinIn2 = PinTypeIn("PIN2",2, 100, "Input EZS ALARM"); // 100ms debounce
|
||||||
|
PinDefinitions::PinIn3 = PinTypeIn("PIN3" ,3, 100, "Input Contact Box");
|
||||||
|
|
||||||
|
OUPUTS_PINS_ARRAY[0] = &PinDefinitions::PinIn2;
|
||||||
|
OUPUTS_PINS_ARRAY[1] = &PinDefinitions::PinIn3;
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
#ifndef PinDefinitions_H
|
||||||
|
#define PinDefinitions_H
|
||||||
|
|
||||||
|
#include <Data/PinTypeOut.h>
|
||||||
|
#include <Data/PinTypeIn.h>
|
||||||
|
|
||||||
|
class PinDefinitions
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static const int COUNT_OUTPUTS_PIN_OUT = 2;
|
||||||
|
static PinTypeOut PinIn8;
|
||||||
|
static PinTypeOut PinIn7;
|
||||||
|
static const PinTypeOut *INPUT_PINS_ARRAY[COUNT_OUTPUTS_PIN_OUT];
|
||||||
|
|
||||||
|
static const int COUNT_INPUTS_PIN_IN = 2;
|
||||||
|
static PinTypeIn PinIn2;
|
||||||
|
static PinTypeIn PinIn3;
|
||||||
|
static const PinTypeIn *OUPUTS_PINS_ARRAY[COUNT_INPUTS_PIN_IN];
|
||||||
|
|
||||||
|
static const uint8_t GSM_PIN_RX = 10;
|
||||||
|
static const uint8_t GSM_PIN_TX = 11;
|
||||||
|
static const long GSM_BAUD_RATE = 115200;
|
||||||
|
|
||||||
|
PinDefinitions();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // PinDefinition_H
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
class Utills
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static void logDebug(const String &log)
|
||||||
|
{
|
||||||
|
// Serial.println(log);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
#ifndef Utills_H
|
||||||
|
#define Utills_H
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
class Utills {
|
||||||
|
public:
|
||||||
|
static void logDebug(const String &log);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,337 +0,0 @@
|
|||||||
#include <SoftwareSerial.h>
|
|
||||||
#include <EEPROM.h>
|
|
||||||
#include <Arduino.h>
|
|
||||||
#include <Ethernet.h>
|
|
||||||
|
|
||||||
#define DEBUG
|
|
||||||
|
|
||||||
// MAC address and IP address for the Ethernet module
|
|
||||||
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
|
|
||||||
IPAddress ip(192, 168, 1, 177);
|
|
||||||
|
|
||||||
// Initialize the Ethernet server (port 80 is default for HTTP)
|
|
||||||
EthernetServer server(80);
|
|
||||||
|
|
||||||
// Initialize software serial for RS232 communication (RX, TX)
|
|
||||||
SoftwareSerial gsmSerial(5, 6); // RX, TX (this is using for communicate with GSM module as AT commands)
|
|
||||||
|
|
||||||
uint8_t PIN_OUT_2 = 2;
|
|
||||||
uint8_t PIN_OUT_3 = 3;
|
|
||||||
|
|
||||||
String ElmP = "p";
|
|
||||||
String ElmH2 = "H2";
|
|
||||||
EthernetClient client;
|
|
||||||
|
|
||||||
struct BaseTypeScript {
|
|
||||||
String id;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Definice struktury pro ukládání parametrů GET požadavku
|
|
||||||
struct GsmPostParams : public BaseTypeScript {
|
|
||||||
String mobileNumber;
|
|
||||||
String sms;
|
|
||||||
};
|
|
||||||
|
|
||||||
//Pin (Vstupni piny)
|
|
||||||
struct pinState {
|
|
||||||
uint8_t pinNumber;
|
|
||||||
volatile bool lastState;
|
|
||||||
unsigned long debounceTime;
|
|
||||||
unsigned long lastStateChangeTime;
|
|
||||||
const char *description;
|
|
||||||
};
|
|
||||||
|
|
||||||
const uint8_t numInputPins = 2; // Replace with the actual number of input pins
|
|
||||||
|
|
||||||
// definice ignorace vstupnich pinu
|
|
||||||
pinState inputStates[numInputPins] = {
|
|
||||||
// { 4, LOW, 60000, 0, "Enter Door" }, // Pin 4, debounce time 1 minute
|
|
||||||
{ 7, LOW, 30000, 0, "Alarm Alert" }, // Pin 8, debounce time 30 seconds
|
|
||||||
{ 8, LOW, 10000, 0, "Electric Alarm" } // Pin 9, debounce time 10 seconds
|
|
||||||
};
|
|
||||||
GsmPostParams gsmPostParams;
|
|
||||||
|
|
||||||
String readStringFromEEPROM(int addr, int length) {
|
|
||||||
String data;
|
|
||||||
for (int i = 0; i < length; i++) {
|
|
||||||
char onedata = char(EEPROM.read(addr + i)); // read one byte at a time
|
|
||||||
if (onedata == '\n') return data;
|
|
||||||
data += onedata;
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
void logDebug(const String &log) {
|
|
||||||
// Serial.println(log);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setup() {
|
|
||||||
|
|
||||||
// if (Serial.available() > 0) {
|
|
||||||
// Serial.begin(115200);
|
|
||||||
// }
|
|
||||||
|
|
||||||
gsmSerial.begin(115200);
|
|
||||||
|
|
||||||
// Start the Ethernet connection and the server
|
|
||||||
Ethernet.begin(mac, ip);
|
|
||||||
server.begin();
|
|
||||||
|
|
||||||
gsmPostParams.mobileNumber = readStringFromEEPROM(1, 20);
|
|
||||||
gsmPostParams.sms = readStringFromEEPROM(21, 200);
|
|
||||||
gsmPostParams.id = "GSM";
|
|
||||||
|
|
||||||
logDebug("Init ..");
|
|
||||||
// Set all input pins as inputs
|
|
||||||
for (int i = 0; i < numInputPins; i++) {
|
|
||||||
pinMode(inputStates[i].pinNumber, INPUT);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set pin 2 and 3 as OUTPUT
|
|
||||||
pinMode(PIN_OUT_2, OUTPUT);
|
|
||||||
pinMode(PIN_OUT_3, OUTPUT);
|
|
||||||
|
|
||||||
logDebug("Init I/O is OK");
|
|
||||||
// Open serial communications
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
String removeAllCharactesrAfterEmpty(String& data) {
|
|
||||||
int keyIndex = data.indexOf(' ');
|
|
||||||
if (keyIndex == -1) {
|
|
||||||
return data; // return empty string if key is not found
|
|
||||||
}
|
|
||||||
data.remove(keyIndex);
|
|
||||||
data.replace("+", " ");
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Metoda pro parsování parametrů
|
|
||||||
|
|
||||||
String getValue(String &data, const String &key) {
|
|
||||||
int keyIndex = data.indexOf(key);
|
|
||||||
if (keyIndex == -1) {
|
|
||||||
return ""; // return empty string if key is not found
|
|
||||||
}
|
|
||||||
int separatorIndex = data.indexOf('&', keyIndex);
|
|
||||||
|
|
||||||
String value = data.substring(keyIndex + key.length(), separatorIndex != -1 ? separatorIndex : data.length());
|
|
||||||
logDebug("Only value:" + value);
|
|
||||||
return removeAllCharactesrAfterEmpty(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void writeToLogAndIntoWebAsP(const String &msg, const String &element) {
|
|
||||||
String lineElement = "<" + element + ">" + msg + "</" + element + ">";
|
|
||||||
// logDebug(msg);
|
|
||||||
//gsmlogDebug("GSM:" + msg);
|
|
||||||
client.println(lineElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
// pin = definice pinu Arduino, string je post hodnota, ktera se porovnava
|
|
||||||
void checkValue(String &request, uint8_t pin, const String &postValue) {
|
|
||||||
if (request.indexOf("/PIN") == -1) return;
|
|
||||||
|
|
||||||
if (request.indexOf("/" + postValue + "=ON") != -1) {
|
|
||||||
digitalWrite(pin, HIGH);
|
|
||||||
String msgOn = "PIN ON: " + String(pin) + " PostVale: " + postValue;
|
|
||||||
writeToLogAndIntoWebAsP(msgOn, ElmH2); // Send state to debug console
|
|
||||||
}
|
|
||||||
if (request.indexOf("/" + postValue + "=OFF") != -1) {
|
|
||||||
digitalWrite(pin, LOW);
|
|
||||||
String msgOff = "PIN OFF: " + String(pin) + " PostVale: " + postValue;
|
|
||||||
writeToLogAndIntoWebAsP(msgOff, ElmH2); // Send state to debug console
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
String ConvertStatusToString(uint8_t &pin, bool showLink) {
|
|
||||||
String pinAsStr = String(pin);
|
|
||||||
String elm = "";
|
|
||||||
if (digitalRead(pin) == HIGH) {
|
|
||||||
elm = "PIN" + pinAsStr + " is ON ";
|
|
||||||
if (showLink) elm += "<a href=\"PIN" + pinAsStr + "=OFF\">OFF</a>";
|
|
||||||
return elm;
|
|
||||||
}
|
|
||||||
|
|
||||||
elm = "PIN" + pinAsStr + " is OFF ";
|
|
||||||
if (showLink) elm += "<a href=\"PIN" + pinAsStr + "=ON\">ON</a>";
|
|
||||||
return elm;
|
|
||||||
}
|
|
||||||
|
|
||||||
void changeDataIfNotNull(String &variable, String &data) {
|
|
||||||
if (data == "") return;
|
|
||||||
variable = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SednAtCommandWithLog(String msg) {
|
|
||||||
logDebug(msg);
|
|
||||||
gsmSerial.print(msg + "\r");
|
|
||||||
delay(400);
|
|
||||||
logDebug(gsmSerial.readString());
|
|
||||||
}
|
|
||||||
|
|
||||||
void SendSMS(String pin) {
|
|
||||||
// Set the SIM900A to text mode
|
|
||||||
SednAtCommandWithLog("AT+CMGF=1");
|
|
||||||
delay(400);
|
|
||||||
|
|
||||||
SednAtCommandWithLog("AT + CMGS =\"" + gsmPostParams.mobileNumber + "\"");
|
|
||||||
delay(400);
|
|
||||||
|
|
||||||
// Specify the SMS message
|
|
||||||
SednAtCommandWithLog(pin + " " + gsmPostParams.sms);
|
|
||||||
delay(1000);
|
|
||||||
|
|
||||||
// Send a Ctrl+Z / ASCII SUB
|
|
||||||
gsmSerial.print((char)26);
|
|
||||||
delay(1000);
|
|
||||||
// Close the connection
|
|
||||||
gsmSerial.print((char)27);
|
|
||||||
delay(1000);
|
|
||||||
logDebug("Close communication GSM");
|
|
||||||
// String msg = gsmSerial.readStringUntil("/n");
|
|
||||||
// gsmlogDebug("Msg:"+msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
void writeStringToEEPROM(int addr, const String &data, int limit) {
|
|
||||||
uint8_t endIndex =0;
|
|
||||||
int numBytes = data.length(); // get length of the string
|
|
||||||
for (uint8_t i = 0; i < numBytes && i < limit; i++) {
|
|
||||||
EEPROM.write(addr + i, data[i]); // write one byte at a time
|
|
||||||
endIndex = i;
|
|
||||||
}
|
|
||||||
if (endIndex < limit) {
|
|
||||||
EEPROM.write(addr + endIndex + 1, '\n');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetPin(uint8_t pin, const char *description) {
|
|
||||||
SendSMS("PIN:" + String(pin) + "|" + description);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void checkInputPins() {
|
|
||||||
unsigned long currentTime = millis();
|
|
||||||
|
|
||||||
for (int i = 0; i < numInputPins; i++) {
|
|
||||||
pinState *currentState = &inputStates[i]; // Pointer to current pin state
|
|
||||||
|
|
||||||
bool currentInputState = digitalRead(currentState->pinNumber);
|
|
||||||
if (currentInputState != currentState->lastState && currentTime - currentState->lastStateChangeTime >= currentState->debounceTime) {
|
|
||||||
// Input state change confirmed after debounce time
|
|
||||||
currentState->lastState = currentInputState;
|
|
||||||
|
|
||||||
if (currentInputState) {
|
|
||||||
|
|
||||||
// Call SetPin function (modify for specific pin control)
|
|
||||||
SetPin(currentState->pinNumber, currentState->description); // Example usage with pin number passed
|
|
||||||
}
|
|
||||||
currentState->lastStateChangeTime = currentTime;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int iterationCounter = 0; // Counter for loop iterations
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void loop() {
|
|
||||||
// Listen for incoming clients
|
|
||||||
String msg = "";
|
|
||||||
client = server.available();
|
|
||||||
|
|
||||||
if (client) {
|
|
||||||
String request = client.readStringUntil('\r');
|
|
||||||
|
|
||||||
logDebug("request:" + request);
|
|
||||||
|
|
||||||
if (request.indexOf("GET /?id=GSM") != -1) {
|
|
||||||
logDebug("it is GSM");
|
|
||||||
//int start = request.indexOf("/?id=") + 2;
|
|
||||||
String data = request.substring(6);
|
|
||||||
logDebug("data:" + data);
|
|
||||||
|
|
||||||
String id = getValue(data, "id=");
|
|
||||||
logDebug("id data:" + id);
|
|
||||||
|
|
||||||
String value = getValue(data, "mobileNumber=");
|
|
||||||
changeDataIfNotNull(gsmPostParams.mobileNumber, value);
|
|
||||||
|
|
||||||
value = getValue(data, "sms=");
|
|
||||||
changeDataIfNotNull(gsmPostParams.sms, value);
|
|
||||||
msg += "PARSING GMS DATA SUCESSFULLY";
|
|
||||||
}
|
|
||||||
|
|
||||||
logDebug("struc GSM:" + gsmPostParams.mobileNumber + " sms:" + gsmPostParams.sms);
|
|
||||||
|
|
||||||
if (request.indexOf("GET /SEND-SMS") != -1) {
|
|
||||||
msg += "SEND SMS TROUGHT GSM. ";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (request.indexOf("GET /SAVE-EEPROM") != -1) {
|
|
||||||
writeStringToEEPROM(1, gsmPostParams.mobileNumber, 20);
|
|
||||||
writeStringToEEPROM(21, gsmPostParams.sms, 200);
|
|
||||||
msg += "Update to EEPROM is sucessfully. ";
|
|
||||||
}
|
|
||||||
|
|
||||||
logDebug("Request:" + request);
|
|
||||||
client.println("HTTP/1.1 200 OK");
|
|
||||||
client.println("Content-Type: text/html");
|
|
||||||
client.println("Connection: close");
|
|
||||||
client.println();
|
|
||||||
client.println("<html><head><style>");
|
|
||||||
client.println(" body { display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0;}");
|
|
||||||
client.println(".content {text-align: center;}");
|
|
||||||
|
|
||||||
client.println("</style>");
|
|
||||||
client.println("</head><body><div class=\"content\">");
|
|
||||||
|
|
||||||
client.println("<H2> Trochta.net:</H2>");
|
|
||||||
|
|
||||||
writeToLogAndIntoWebAsP(msg, "H3");
|
|
||||||
//nastav jestli je post
|
|
||||||
checkValue(request, PIN_OUT_2, "PIN2");
|
|
||||||
checkValue(request, PIN_OUT_3, "PIN3");
|
|
||||||
|
|
||||||
// Vypis aktualni hodnoty
|
|
||||||
writeToLogAndIntoWebAsP("Input:", ElmP);
|
|
||||||
|
|
||||||
for (int i = 0; i < numInputPins; i++) {
|
|
||||||
pinState *currentState = &inputStates[i];
|
|
||||||
writeToLogAndIntoWebAsP(ConvertStatusToString(currentState->pinNumber, false), ElmP);
|
|
||||||
}
|
|
||||||
|
|
||||||
writeToLogAndIntoWebAsP("Output:", ElmP);
|
|
||||||
writeToLogAndIntoWebAsP(ConvertStatusToString(PIN_OUT_2, true), ElmP);
|
|
||||||
writeToLogAndIntoWebAsP(ConvertStatusToString(PIN_OUT_3, true), ElmP);
|
|
||||||
|
|
||||||
writeToLogAndIntoWebAsP("GSM Number:" + gsmPostParams.mobileNumber, ElmP);
|
|
||||||
writeToLogAndIntoWebAsP("SMS:" + gsmPostParams.sms, ElmP);
|
|
||||||
|
|
||||||
writeToLogAndIntoWebAsP("<a href=\"SEND-SMS\">Send SMS</a>", "H4");
|
|
||||||
writeToLogAndIntoWebAsP("<a href=\"SAVE-EEPROM\">Save to EEPROM</a>", ElmP);
|
|
||||||
writeToLogAndIntoWebAsP("<a href=\"/\">Refresh</a>", ElmP);
|
|
||||||
// Send the time and the message that the page is loaded
|
|
||||||
client.println("</div></body></html>");
|
|
||||||
// Give the web browser time to receive the data
|
|
||||||
client.stop();
|
|
||||||
|
|
||||||
logDebug("Time: " + String(millis() / 1000));
|
|
||||||
|
|
||||||
if (request.indexOf("GET /SEND-SMS") != -1) {
|
|
||||||
SendSMS("Web Link (Test)");
|
|
||||||
}
|
|
||||||
// Zjkontroluje vstupni piny
|
|
||||||
|
|
||||||
delay(5);
|
|
||||||
}
|
|
||||||
|
|
||||||
iterationCounter++;
|
|
||||||
if (iterationCounter == INT_FAST16_MAX) iterationCounter = 0;
|
|
||||||
if (iterationCounter % 5 == 0) { // Check if 10 iterations have passed
|
|
||||||
checkInputPins(); // Call checkInputPins() every 10 iterations
|
|
||||||
}
|
|
||||||
|
|
||||||
delay(100);
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
#include <SoftwareSerial.h>
|
||||||
|
#include <EEPROM.h>
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <Ethernet.h>
|
||||||
|
#include <Utills.h>
|
||||||
|
#include <Device/GSMDevice.h>
|
||||||
|
#include <Data/PinTypeOut.h>
|
||||||
|
#include <Data/PinTypeIn.h>
|
||||||
|
#include <PinDefinitions.h>
|
||||||
|
|
||||||
|
// Devices
|
||||||
|
|
||||||
|
GSMDevice gsmDevice = GSMDevice(PinDefinitions::GSM_PIN_RX, PinDefinitions::GSM_PIN_TX, PinDefinitions::GSM_BAUD_RATE);
|
||||||
|
// Pin Input
|
||||||
|
GSMData gsmData = GSMData("GSM");
|
||||||
|
|
||||||
|
void setup()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user