diff --git a/src/Main.java b/src/Main.java
index 3cc656e..cb138c6 100644
--- a/src/Main.java
+++ b/src/Main.java
@@ -1,7 +1,10 @@
+import database.ContactInputData;
import database.Database;
import gpio.NanopiGpio;
import mqtt.MqttClient;
import org.tinylog.Logger;
+import pa.VX3K;
+import pa.VX3KPseudoContactInput;
//TIP To Run code, press or
// click the icon in the gutter.
@@ -10,13 +13,21 @@ public class Main {
private static MqttClient mqttClient;
private static NanopiGpio gpio;
private static Database db;
+ private static VX3K vx3K;
// Application entry point
public static void main(String[] args) {
Logger.info("Application started");
+
+ // initialize config
config = new config();
+
+ // initialize database
db = new Database();
//db.contactInputDataList.forEach(System.out::println);
+ // initialize VX3K
+ vx3K = new VX3K(config.getVX3KTargetIP(), config.getVX3KTargetPort());
+
// Initialize the GPIO pins
gpio = new NanopiGpio();
// cek di https://wiki.friendlyelec.com/wiki/index.php/NanoPi_Duo20
@@ -29,17 +40,41 @@ public class Main {
}, pinStatus -> {
// TODO Handle pin status updates here
Logger.info("Gpio {}, Description {}, status updated to {}", pinStatus.getGpioNumber(), pinStatus.getDescription(), pinStatus.getStatus());
- // MQTT publish pin status update
- if (mqttClient != null && mqttClient.isConnected()) mqttClient.Publish(config.getMQTT_Topic(), config.getMQTT_ClientID(),
- String.format("Gpio %d, Description %s, Status %d", pinStatus.getGpioNumber(), pinStatus.getDescription(), pinStatus.getStatus()),
- published -> {
- if (published) {
- Logger.info("Pin status update published successfully.");
+
+ ContactInputData cib = db.GetContactInputData(pinStatus.getDescription());
+ if (cib!=null){
+ if (cib.isEnableMQTT()){
+ // MQTT publish pin status update
+ if (mqttClient != null && mqttClient.isConnected()) mqttClient.Publish(config.getMQTT_Topic(), config.getMQTT_ClientID(),
+ String.format("Gpio %d, Description %s, Status %d", pinStatus.getGpioNumber(), pinStatus.getDescription(), pinStatus.getStatus()),
+ published -> {
+ if (published) {
+ Logger.info("Pin status update published successfully.");
+ } else {
+ Logger.error("Failed to publish pin status update.");
+ }
+ });
+ }
+ if (cib.isEnableEmail()){
+ // Email notification can be added here
+ }
+ if (cib.isEnableVX3K()){
+ // VX3K Broadcast here
+ VX3KPseudoContactInput cmd = new VX3KPseudoContactInput(cib.getVX3KFrameID(), cib.getVX3KContactID(), pinStatus.getStatus()==1);
+ vx3K.PseudoContactInput(cmd, result -> {
+ if (result.success()){
+ Logger.info("VX3K PseudoContactInput successfully executed.");
} else {
- Logger.error("Failed to publish pin status update.");
+ Logger.error("VX3K PseudoContactInput failed to execute, Message {}.", result.message());
}
});
- // Email notification can be added here
+ }
+ if (cib.isEnableModbus()){
+ // update Modbus Register here
+ }
+ }
+
+
},
diff --git a/src/Somecodes.java b/src/Somecodes.java
index 454659c..786e12c 100644
--- a/src/Somecodes.java
+++ b/src/Somecodes.java
@@ -1,7 +1,17 @@
import com.google.gson.Gson;
+
+
public class Somecodes {
public static String currentdirectory = System.getProperty("user.dir");
public static Gson gson = new Gson();
+
+
+
+
+
+
+
+
}
diff --git a/src/database/Database.java b/src/database/Database.java
index 33fc6bb..5ee3ce8 100644
--- a/src/database/Database.java
+++ b/src/database/Database.java
@@ -15,7 +15,6 @@ import java.util.List;
public class Database {
private static final String DB_NAME = "jdbc:sqlite:database.sqlite";
- private final int maxContactInputData = 16; // Maximum number of contact input data
public final List contactInputDataList = new ArrayList<>();
public Database(){
CreateContactInputDataTable();
@@ -83,6 +82,8 @@ public class Database {
return loadedData;
}
+
+
/**
* Load ContactInputData into the contactInputDataList.
* @param loadedData List of ContactInputData objects loaded from the database.
@@ -90,6 +91,8 @@ public class Database {
@SuppressWarnings("ExtractMethodRecommender")
private void LoadContactInputDataList(List loadedData){
contactInputDataList.clear();
+ // Maximum number of contact input data
+ int maxContactInputData = 16;
for (int i = 1; i <= maxContactInputData; i++){
final int contactID = i;
ContactInputData cid = loadedData.stream()
@@ -151,6 +154,24 @@ public class Database {
return false;
}
+ /**
+ * Get ContactInputData by ID
+ * @param contactID ID to get
+ * @return ContactInputData object if exists, or null if not exists
+ */
+ public ContactInputData GetContactInputData(int contactID){
+ return contactInputDataList.stream().filter(x -> x.getContactID() == contactID).findFirst().orElse(null);
+ }
+
+ /**
+ * Get ContactInputData by description
+ * @param description Description to get
+ * @return ContactInputData if exists, or null if not exists
+ */
+ public ContactInputData GetContactInputData(String description){
+ return contactInputDataList.stream().filter(x -> x.getDescription().equals(description)).findFirst().orElse(null);
+ }
+
/**
* Clear the content of a specific ContactInputData entry in the database.
* @param contactID The ID of the ContactInputData entry to be cleared.
diff --git a/src/pa/VX3K.java b/src/pa/VX3K.java
new file mode 100644
index 0000000..4d64cea
--- /dev/null
+++ b/src/pa/VX3K.java
@@ -0,0 +1,43 @@
+package pa;
+
+
+import lombok.NonNull;
+import org.tinylog.Logger;
+
+import java.net.InetSocketAddress;
+import java.nio.channels.SocketChannel;
+import java.util.function.Consumer;
+
+public class VX3K {
+ private final InetSocketAddress inetSocketAddress;
+
+ public VX3K(String ipaddress, int port){
+ this.inetSocketAddress = new InetSocketAddress(ipaddress, port);
+ }
+
+ public void PseudoContactInput(VX3KPseudoContactInput input, @NonNull Consumer<@NonNull VX3KCommandResult> callback){
+
+ try(SocketChannel channel = SocketChannel.open(inetSocketAddress)){
+ channel.write(input.getBuffer());
+ input.getBuffer().clear();
+ int read = channel.read(input.getBuffer());
+ if (read>0){
+ short command = input.getBuffer().getShort(0);
+ short responsecode = input.getBuffer().getShort(1);
+ if (command == input.getCommandID()){
+ if (responsecode == 0x0000){
+ callback.accept(new VX3KCommandResult(input.getCommandID(), true, "success"));
+ } else callback.accept(new VX3KCommandResult(input.getCommandID(), false , "Code:"+responsecode ));
+ } else callback.accept(new VX3KCommandResult(input.getCommandID(), false, "Invalid CommandID reply"));
+ } else callback.accept( new VX3KCommandResult(input.getCommandID(), false, "Read 0"));
+ } catch (Exception e){
+ Logger.error("PseudoContactInput failed, Message {}", e.getMessage());
+ callback.accept(new VX3KCommandResult(input.getCommandID(), false, "Exception"));
+ }
+
+ }
+
+
+
+
+}
diff --git a/src/pa/VX3KCommandResult.java b/src/pa/VX3KCommandResult.java
new file mode 100644
index 0000000..56900a4
--- /dev/null
+++ b/src/pa/VX3KCommandResult.java
@@ -0,0 +1,4 @@
+package pa;
+
+public record VX3KCommandResult(int command, boolean success, String message) {
+}
diff --git a/src/pa/VX3KPseudoContactInput.java b/src/pa/VX3KPseudoContactInput.java
new file mode 100644
index 0000000..80f9382
--- /dev/null
+++ b/src/pa/VX3KPseudoContactInput.java
@@ -0,0 +1,23 @@
+package pa;
+
+import lombok.Getter;
+
+import java.nio.ByteBuffer;
+
+public class VX3KPseudoContactInput{
+ private final @Getter int CommandID;
+ private final @Getter ByteBuffer buffer;
+ public VX3KPseudoContactInput(int FrameID, int contactID, boolean isON){
+ final int length = 8 + 6; // 8 bytes header + 6 bytes payload
+ CommandID = 0x1001;
+ buffer = ByteBuffer.allocate(length);
+ buffer.putShort((short) CommandID);
+ buffer.putShort((short) 0);
+ buffer.putShort((short) length);
+ buffer.putShort((short) 0x8000);
+ buffer.putShort((short) FrameID);
+ buffer.putShort((short) contactID);
+ buffer.putShort((short)(isON ? 1 : 0));
+ }
+
+}