diff --git a/.idea/libraries/digitalpetri_modbus_master_tcp.xml b/.idea/libraries/digitalpetri_modbus_master_tcp.xml
deleted file mode 100644
index 067876d..0000000
--- a/.idea/libraries/digitalpetri_modbus_master_tcp.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/digitalpetri_modbus_tcp.xml b/.idea/libraries/digitalpetri_modbus_tcp.xml
new file mode 100644
index 0000000..cc61f4a
--- /dev/null
+++ b/.idea/libraries/digitalpetri_modbus_tcp.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/sun_mail_jakarta.xml b/.idea/libraries/sun_mail_jakarta.xml
new file mode 100644
index 0000000..20a025d
--- /dev/null
+++ b/.idea/libraries/sun_mail_jakarta.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/FA_Gateway_Java.iml b/FA_Gateway_Java.iml
index eecfc80..1404e67 100644
--- a/FA_Gateway_Java.iml
+++ b/FA_Gateway_Java.iml
@@ -8,12 +8,13 @@
-
+
+
\ No newline at end of file
diff --git a/lib/jakarta.activation-1.2.1.jar b/lib/jakarta.activation-1.2.1.jar
new file mode 100644
index 0000000..fa6aad2
Binary files /dev/null and b/lib/jakarta.activation-1.2.1.jar differ
diff --git a/lib/jakarta.activation-2.0.1.jar b/lib/jakarta.activation-2.0.1.jar
new file mode 100644
index 0000000..521c7c4
Binary files /dev/null and b/lib/jakarta.activation-2.0.1.jar differ
diff --git a/lib/jakarta.mail-1.6.3.jar b/lib/jakarta.mail-1.6.3.jar
new file mode 100644
index 0000000..71ac5b9
Binary files /dev/null and b/lib/jakarta.mail-1.6.3.jar differ
diff --git a/lib/jakarta.mail-2.0.1.jar b/lib/jakarta.mail-2.0.1.jar
new file mode 100644
index 0000000..17e07cc
Binary files /dev/null and b/lib/jakarta.mail-2.0.1.jar differ
diff --git a/lib/modbus-2.1.0.jar b/lib/modbus-2.1.0.jar
new file mode 100644
index 0000000..a997135
Binary files /dev/null and b/lib/modbus-2.1.0.jar differ
diff --git a/lib/modbus-slave-tcp-1.2.2.jar b/lib/modbus-slave-tcp-1.2.2.jar
new file mode 100644
index 0000000..835c0b6
Binary files /dev/null and b/lib/modbus-slave-tcp-1.2.2.jar differ
diff --git a/lib/modbus-tcp-2.1.0.jar b/lib/modbus-tcp-2.1.0.jar
new file mode 100644
index 0000000..a626fea
Binary files /dev/null and b/lib/modbus-tcp-2.1.0.jar differ
diff --git a/lib/netty-buffer-4.1.116.Final.jar b/lib/netty-buffer-4.1.116.Final.jar
new file mode 100644
index 0000000..b6f71eb
Binary files /dev/null and b/lib/netty-buffer-4.1.116.Final.jar differ
diff --git a/lib/netty-channel-fsm-1.0.0.jar b/lib/netty-channel-fsm-1.0.0.jar
new file mode 100644
index 0000000..8067c49
Binary files /dev/null and b/lib/netty-channel-fsm-1.0.0.jar differ
diff --git a/lib/netty-codec-4.1.116.Final.jar b/lib/netty-codec-4.1.116.Final.jar
new file mode 100644
index 0000000..bf763bf
Binary files /dev/null and b/lib/netty-codec-4.1.116.Final.jar differ
diff --git a/lib/netty-common-4.1.116.Final.jar b/lib/netty-common-4.1.116.Final.jar
new file mode 100644
index 0000000..ee26424
Binary files /dev/null and b/lib/netty-common-4.1.116.Final.jar differ
diff --git a/lib/netty-handler-4.1.105.Final.jar b/lib/netty-handler-4.1.105.Final.jar
new file mode 100644
index 0000000..959cfd7
Binary files /dev/null and b/lib/netty-handler-4.1.105.Final.jar differ
diff --git a/lib/netty-handler-4.1.116.Final.jar b/lib/netty-handler-4.1.116.Final.jar
new file mode 100644
index 0000000..b0dc2b7
Binary files /dev/null and b/lib/netty-handler-4.1.116.Final.jar differ
diff --git a/lib/netty-resolver-4.1.116.Final.jar b/lib/netty-resolver-4.1.116.Final.jar
new file mode 100644
index 0000000..9dd8a80
Binary files /dev/null and b/lib/netty-resolver-4.1.116.Final.jar differ
diff --git a/lib/netty-transport-4.1.116.Final.jar b/lib/netty-transport-4.1.116.Final.jar
new file mode 100644
index 0000000..4afc4cc
Binary files /dev/null and b/lib/netty-transport-4.1.116.Final.jar differ
diff --git a/lib/netty-transport-native-unix-common-4.1.105.Final.jar b/lib/netty-transport-native-unix-common-4.1.105.Final.jar
new file mode 100644
index 0000000..5523194
Binary files /dev/null and b/lib/netty-transport-native-unix-common-4.1.105.Final.jar differ
diff --git a/lib/netty-transport-native-unix-common-4.1.116.Final.jar b/lib/netty-transport-native-unix-common-4.1.116.Final.jar
new file mode 100644
index 0000000..75f9010
Binary files /dev/null and b/lib/netty-transport-native-unix-common-4.1.116.Final.jar differ
diff --git a/lib/slf4j-api-2.0.16.jar b/lib/slf4j-api-2.0.16.jar
new file mode 100644
index 0000000..cbb5448
Binary files /dev/null and b/lib/slf4j-api-2.0.16.jar differ
diff --git a/lib/strict-machine-1.0.0.jar b/lib/strict-machine-1.0.0.jar
new file mode 100644
index 0000000..16b4526
Binary files /dev/null and b/lib/strict-machine-1.0.0.jar differ
diff --git a/src/Main.java b/src/Main.java
index cb138c6..9ca833f 100644
--- a/src/Main.java
+++ b/src/Main.java
@@ -1,6 +1,8 @@
import database.ContactInputData;
import database.Database;
import gpio.NanopiGpio;
+import mail.SMTPSender;
+import modbus.ModbusTCPServer;
import mqtt.MqttClient;
import org.tinylog.Logger;
import pa.VX3K;
@@ -14,6 +16,8 @@ public class Main {
private static NanopiGpio gpio;
private static Database db;
private static VX3K vx3K;
+ private static SMTPSender mailsender;
+ private static ModbusTCPServer modbusServer;
// Application entry point
public static void main(String[] args) {
Logger.info("Application started");
@@ -28,6 +32,12 @@ public class Main {
// initialize VX3K
vx3K = new VX3K(config.getVX3KTargetIP(), config.getVX3KTargetPort());
+ // initialize Email Sender
+ mailsender = new SMTPSender(config.getEmail_SMTPServer(), config.getEmail_SMTPPort(), true, config.getEmail_SMTPUsername(), config.getEmail_SMTPPassword());
+
+ modbusServer = new ModbusTCPServer(config.getModbus_MasterIP(), config.getModbus_Port(), 1000);
+ modbusServer.Start();
+
// Initialize the GPIO pins
gpio = new NanopiGpio();
// cek di https://wiki.friendlyelec.com/wiki/index.php/NanoPi_Duo20
@@ -38,7 +48,6 @@ public class Main {
Logger.error("GPIO pins closed or failed to open.");
}
}, pinStatus -> {
- // TODO Handle pin status updates here
Logger.info("Gpio {}, Description {}, status updated to {}", pinStatus.getGpioNumber(), pinStatus.getDescription(), pinStatus.getStatus());
ContactInputData cib = db.GetContactInputData(pinStatus.getDescription());
@@ -57,6 +66,15 @@ public class Main {
}
if (cib.isEnableEmail()){
// Email notification can be added here
+ String subject = String.format("Fire Alarm Gateway - Pin %d Status Update", pinStatus.getGpioNumber());
+ String body = String.format("Pin %d with description '%s' has changed status to %d.", pinStatus.getGpioNumber(), pinStatus.getDescription(), pinStatus.getStatus());
+ mailsender.SendEmail(config.getEmail_SMTPFrom(), cib.getEmailRecipient(), subject, body, sent -> {
+ if (sent) {
+ Logger.info("Email notification sent successfully.");
+ } else {
+ Logger.error("Failed to send email notification.");
+ }
+ });
}
if (cib.isEnableVX3K()){
// VX3K Broadcast here
@@ -70,7 +88,9 @@ public class Main {
});
}
if (cib.isEnableModbus()){
- // update Modbus Register here
+ if (modbusServer!=null){
+ modbusServer.SetRegister(cib.getContactID(), pinStatus.getStatus());
+ }
}
}
@@ -108,6 +128,7 @@ public class Main {
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
if (gpio!=null && gpio.IsOpened()) gpio.Close();
if (mqttClient!=null && mqttClient.isConnected()) mqttClient.Disconnect();
+ if (modbusServer!=null && modbusServer.isRunning()) modbusServer.Stop();
}));
}
}
\ No newline at end of file
diff --git a/src/mail/SMTPSender.java b/src/mail/SMTPSender.java
new file mode 100644
index 0000000..b74d760
--- /dev/null
+++ b/src/mail/SMTPSender.java
@@ -0,0 +1,63 @@
+package mail;
+
+import jakarta.mail.*;
+import jakarta.mail.internet.InternetAddress;
+import jakarta.mail.internet.MimeMessage;
+import lombok.NonNull;
+
+import java.util.Properties;
+import java.util.function.Consumer;
+
+public class SMTPSender {
+ final Properties props;
+ final String username;
+ final String password;
+
+ /**
+ * Constructor for SMTPSender
+ * @param smtpHost the SMTP server host
+ * @param port the SMTP server port
+ * @param useSSL true to use SSL, false to use STARTTLS
+ * @param username the username for SMTP authentication
+ * @param password the password for SMTP authentication
+ */
+ public SMTPSender(String smtpHost, int port, boolean useSSL, String username, String password){
+ props = new Properties();
+ props.put("mail.smtp.auth", "true");
+ props.put("mail.smtp.starttls.enable", String.valueOf(useSSL)); // Enable STARTTLS
+ props.put("mail.smtp.host", smtpHost);
+ props.put("mail.smtp.port", String.valueOf(port));
+ this.username = username;
+ this.password = password;
+ }
+
+ /**
+ * Sends an email using the configured SMTP settings.
+ *
+ * @param fromEmail the sender's email address
+ * @param toEmail the recipient's email address
+ * @param Subject the subject of the email
+ * @param body the body of the email
+ * @param success a callback that receives true if the email was sent successfully, false otherwise
+ */
+ public void SendEmail(String fromEmail, String toEmail, String Subject, String body, @NonNull Consumer<@NonNull Boolean> success){
+ try{
+ Session session = Session.getInstance(props, new Authenticator() {
+ protected PasswordAuthentication getPasswordAuthentication() {
+ return new PasswordAuthentication(username, password);
+ }
+ });
+ Message message = new MimeMessage(session);
+ message.setFrom(new InternetAddress(fromEmail));
+ message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(toEmail));
+ message.setSubject(Subject);
+ message.setText(body);
+
+ Transport.send(message);
+ success.accept(true);
+ } catch (Exception e){
+ success.accept(false);
+ }
+
+ }
+}
diff --git a/src/modbus/ModbusTCPServer.java b/src/modbus/ModbusTCPServer.java
new file mode 100644
index 0000000..3b61500
--- /dev/null
+++ b/src/modbus/ModbusTCPServer.java
@@ -0,0 +1,107 @@
+package modbus;
+
+import com.digitalpetri.modbus.exceptions.ModbusResponseException;
+import com.digitalpetri.modbus.exceptions.UnknownUnitIdException;
+import com.digitalpetri.modbus.pdu.ReadHoldingRegistersRequest;
+import com.digitalpetri.modbus.pdu.ReadHoldingRegistersResponse;
+import com.digitalpetri.modbus.server.ModbusRequestContext;
+import com.digitalpetri.modbus.server.ModbusServices;
+import com.digitalpetri.modbus.server.ModbusTcpServer;
+import com.digitalpetri.modbus.tcp.server.NettyTcpServerTransport;
+import lombok.Getter;
+import org.tinylog.Logger;
+
+import java.nio.ByteBuffer;
+import java.nio.ShortBuffer;
+import java.util.concurrent.atomic.AtomicIntegerArray;
+
+
+public class ModbusTCPServer {
+ private @Getter boolean isRunning = false;
+ private ModbusTcpServer server;
+
+ private final NettyTcpServerTransport transport;
+ private final ModbusServices services;
+ private final AtomicIntegerArray holdingregister;
+
+ /**
+ * Creates a Modbus TCP server that listens on the specified bind address and port.
+ *
+ * @param bindAddress the IP address to bind the server to
+ * @param port the port number to listen on
+ * @param holdingRegisterSize size of the holding register array
+ */
+ public ModbusTCPServer(String bindAddress, int port, int holdingRegisterSize) {
+ this.holdingregister = new AtomicIntegerArray(holdingRegisterSize);
+ transport = NettyTcpServerTransport.create(cfg ->{
+ cfg.bindAddress = bindAddress;
+ cfg.port = port;
+ });
+ services = new ModbusServices() {
+ @SuppressWarnings("RedundantThrows")
+ @Override
+ public ReadHoldingRegistersResponse readHoldingRegisters(ModbusRequestContext context, int unitId, ReadHoldingRegistersRequest request) throws ModbusResponseException, UnknownUnitIdException {
+ ByteBuffer result = ByteBuffer.allocate(request.quantity()*2);
+ ShortBuffer xx = result.asShortBuffer();
+ for (int i = 0; i < request.quantity(); i++) {
+ int value = holdingregister.get(request.address() + i);
+ xx.put((short) value);
+ }
+ return new ReadHoldingRegistersResponse(result.array());
+ }
+ };
+ }
+
+ /**
+ * Sets the value of a holding register at the specified address.
+ * @param address the address of the holding register (0-based index)
+ * @param value the value to set (should be in the range of a 16-bit integer)
+ */
+ public void SetRegister(int address, int value) {
+ if (address < 0 || address >= holdingregister.length()) {
+ throw new IndexOutOfBoundsException("Address out of bounds: " + address);
+ }
+ holdingregister.set(address, (short) value);
+ }
+
+ /**
+ * Start the Modbus TCP server.
+ * @return true if the server started successfully, false otherwise.
+ */
+ public boolean Start(){
+ isRunning = false;
+ try{
+ var newserver = ModbusTcpServer.create(transport, services);
+ newserver.start();
+ server = newserver;
+ isRunning = true;
+ Logger.info("Modbus TCP server started");
+ } catch (Exception e){
+ Logger.error("Failed to start Modbus TCP server: {}", e.getMessage());
+ }
+ return isRunning;
+ }
+
+ /**
+ * Stop the Modbus TCP server.
+ */
+ public void Stop(){
+ if (isRunning){
+ if (server!=null){
+ try {
+ server.stop();
+ Logger.info("Modbus TCP server stopped successfully.");
+ } catch (Exception e) {
+ Logger.error("Failed to stop Modbus TCP server: {}", e.getMessage());
+ }
+ server = null;
+ } else {
+ Logger.warn("Modbus TCP server instance is null, cannot stop.");
+ }
+
+ } else {
+ Logger.warn("Modbus TCP server is not running.");
+ }
+ isRunning = false;
+ }
+}