diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml index 4efd5ca..67a7da1 100644 --- a/.idea/inspectionProfiles/Project_Default.xml +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -4,6 +4,7 @@ + + diff --git a/Html/html/index.html b/Html/html/index.html index 773df51..c038b9e 100644 --- a/Html/html/index.html +++ b/Html/html/index.html @@ -134,8 +134,8 @@
diff --git a/onnx/coco.names b/onnx/coco.names new file mode 100644 index 0000000..ca76c80 --- /dev/null +++ b/onnx/coco.names @@ -0,0 +1,80 @@ +person +bicycle +car +motorbike +aeroplane +bus +train +truck +boat +traffic light +fire hydrant +stop sign +parking meter +bench +bird +cat +dog +horse +sheep +cow +elephant +bear +zebra +giraffe +backpack +umbrella +handbag +tie +suitcase +frisbee +skis +snowboard +sports ball +kite +baseball bat +baseball glove +skateboard +surfboard +tennis racket +bottle +wine glass +cup +fork +knife +spoon +bowl +banana +apple +sandwich +orange +broccoli +carrot +hot dog +pizza +donut +cake +chair +sofa +pottedplant +bed +diningtable +toilet +tvmonitor +laptop +mouse +remote +keyboard +cell phone +microwave +oven +toaster +sink +refrigerator +book +clock +vase +scissors +teddy bear +hair drier +toothbrush diff --git a/onnx/yolov8n.onnx b/onnx/yolov8n.onnx new file mode 100644 index 0000000..ade7079 Binary files /dev/null and b/onnx/yolov8n.onnx differ diff --git a/pom.xml b/pom.xml index db1e03e..65fa25d 100644 --- a/pom.xml +++ b/pom.xml @@ -178,32 +178,6 @@ 5.1.2-1.5.8 linux-arm64 - com.corundumstudio.socketio netty-socketio diff --git a/src/main/java/Camera/GrabbingTask.java b/src/main/java/Camera/GrabbingTask.java index bf576c7..48d7629 100644 --- a/src/main/java/Camera/GrabbingTask.java +++ b/src/main/java/Camera/GrabbingTask.java @@ -9,6 +9,7 @@ import lombok.Getter; import lombok.Setter; import org.bytedeco.javacv.Frame; import org.bytedeco.javacv.FrameGrabber; +import org.bytedeco.opencv.opencv_core.Mat; import org.tinylog.Logger; public class GrabbingTask implements Runnable { @@ -23,6 +24,8 @@ public class GrabbingTask implements Runnable { @Setter private Consumer onLQFrameUpdate; @Setter private Consumer onHQBase64Update; @Setter private Consumer onLQBase64Update; + @Setter private Consumer onYoloUpdate; + @Setter private Consumer onYoloBase64Update; // status of capture fps @Getter private int CaptureFPS = 0; @@ -33,6 +36,8 @@ public class GrabbingTask implements Runnable { // for FPS calculation private int intendedFps = 10; + private final YoloDetector yolo; + @SuppressWarnings("SameParameterValue") private void updateMessage(String message) { if (onMessageUpdate != null) { @@ -40,9 +45,17 @@ public class GrabbingTask implements Runnable { } } + private void updateYoloBase64(String base64) { + if (onYoloBase64Update != null) { + onYoloBase64Update.accept(base64); + } + } - - + private void updateYoloFrame(Frame frame) { + if (onYoloUpdate != null) { + onYoloUpdate.accept(frame); + } + } private void updateHQBase64(String base64) { if (onHQBase64Update != null) { @@ -77,6 +90,7 @@ public class GrabbingTask implements Runnable { this.isGrabbing = isGrabbing; this.grabber = grabber; if (fps>0) intendedFps = fps; + yolo = new YoloDetector(); } @@ -94,6 +108,23 @@ public class GrabbingTask implements Runnable { } else updateMessage("processFrame have null frame"); } + //TODO masih trouble di sini + private void DetectYolo(Frame frame){ + if (frame!=null){ + try{ + Mat processed = yolo.Detect(frame); + Frame yoloFrame = SomeCodes.CoreMatConverter.convert(processed); + updateYoloFrame(yoloFrame); + updateYoloBase64(SomeCodes.FrameToBase64(yoloFrame)); + } catch (Exception e){ + System.out.println("error processing YOLO, Message : "+e.getMessage()); + updateYoloFrame(null); + updateYoloBase64(""); + } + } + + } + private void flush_grabber(){ try { if (grabber!=null) grabber.flush(); @@ -117,9 +148,13 @@ public class GrabbingTask implements Runnable { Thread.yield(); Frame frame = grabber.grab(); if (framecount0){ + Logger.info("CUDA enabled devices found: " + cudacount); + opencv_core.printCudaDeviceInfo(0); + } else { + Logger.info("No CUDA enabled devices found"); + } this.rtspUrl = "rtsp://" + ip + path; Logger.info("RtspGrabber created with url: " + rtspUrl); } @@ -62,6 +72,22 @@ public class RtspGrabber { return lastLQBase64; } + private synchronized void setLastYoloBase64(String base64){ + lastYoloBase64 = base64; + } + + public synchronized String getLastYoloBase64(){ + return lastYoloBase64; + } + + private synchronized void setLastYoloFrame(Frame frame){ + lastYoloFrame = frame; + } + + public synchronized Frame getLastYoloFrame(){ + return lastYoloFrame; + } + /** * Start grabbing frames from rtsp * @param useTcp Use tcp instead of udp @@ -143,6 +169,8 @@ public class RtspGrabber { }); tt.setOnHQBase64Update(this::setLastHQBase64); tt.setOnLQBase64Update(this::setLastLQBase64); + tt.setOnYoloUpdate(this::setLastYoloFrame); + tt.setOnYoloBase64Update(this::setLastYoloBase64); return tt; } } diff --git a/src/main/java/Camera/YoloDetector.java b/src/main/java/Camera/YoloDetector.java new file mode 100644 index 0000000..7bb1130 --- /dev/null +++ b/src/main/java/Camera/YoloDetector.java @@ -0,0 +1,167 @@ +package Camera; + +import Other.SomeCodes; +import lombok.Getter; +import org.bytedeco.javacv.Frame; +import org.bytedeco.opencv.global.opencv_dnn; +import org.bytedeco.opencv.global.opencv_imgproc; +import org.bytedeco.opencv.opencv_core.Mat; +import org.bytedeco.opencv.opencv_core.Rect; +import org.bytedeco.opencv.opencv_core.Scalar; +import org.bytedeco.opencv.opencv_core.Size; +import org.bytedeco.opencv.opencv_dnn.*; +import org.opencv.core.MatOfFloat; +import org.opencv.core.MatOfInt; +import org.opencv.core.MatOfRect2d; +import org.opencv.dnn.Dnn; + + +import java.io.BufferedReader; +import java.io.FileReader; +import java.nio.FloatBuffer; +import java.util.ArrayList; +import java.util.List; + +import static org.bytedeco.opencv.global.opencv_core.CV_32F; + +public class YoloDetector { + private Net net; + private @Getter boolean NetLoaded; + private List classes ; + // YOLO expect image in 640 x 640 + private final int input_width = 640; + private final int input_height = 640; + // minimum confidence for detections + private final float confidence_threshold = 0.5f; + // Non-maximum suppression threshold + private final float nms_threshold = 0.4f; + + public YoloDetector() { + NetLoaded = false; + net = null; + classes = null; + String onnxfile = SomeCodes.ExtractResource("/yolov8n.onnx", SomeCodes.currentDirectory); + String namesfile = SomeCodes.ExtractResource("/coco.names", SomeCodes.currentDirectory); + if (SomeCodes.ValidFile(onnxfile)){ + if (SomeCodes.ValidFile(namesfile)){ + net = opencv_dnn.readNetFromONNX(onnxfile); + net.setPreferableBackend(Dnn.DNN_BACKEND_OPENCV); + net.setPreferableTarget(Dnn.DNN_TARGET_CPU); + + classes = new ArrayList<>(); + try(BufferedReader br = new BufferedReader(new FileReader(namesfile))) { + String line; + while ((line = br.readLine()) != null) { + classes.add(line); + } + } catch (Exception e){ + System.out.println("Error: reading names file"); + } + + if (!net.empty()){ + if (!classes.isEmpty()){ + NetLoaded = true; + } else System.out.println("Error: names file is empty"); + } else System.out.println("Error: net is empty"); + } else System.out.println("Error: names file not found"); + } else System.out.println("Error: onnx file not found"); + } + + public Mat Detect(Frame frame){ + Mat mat = SomeCodes.CoreMatConverter.convertToMat(frame); + return Detect(mat); + + } + + public Mat Detect(Mat frame){ + if (NetLoaded){ + Mat blob = opencv_dnn.blobFromImage(frame, 1.0/255.0, new Size(input_width, input_height), new Scalar(0) , true, false, CV_32F); + net.setInput(blob); + + Mat detections = net.forward(); + return detections; + } else { + System.out.println("Error: Net not loaded"); + return new Mat(); + } + } + + private Mat ProcessDetection(Mat frame, Mat output){ + int rows = output.rows(); + int cols = output.cols(); + List boxes = new ArrayList<>(); + List confidences = new ArrayList<>(); + List classIds = new ArrayList<>(); + + for(int i=0;i= confidence_threshold){ + FloatBuffer data = row.getFloatBuffer(); + int classid = 0; + float maxscore = 0; + for(int j = 5; j< cols; j++){ + float score = data.get(j); + if (score > maxscore){ + maxscore = score; + classid = j-5; + } + } + if (maxscore>= confidence_threshold){ + int x = (int)(data.get(0) * frame.cols()); + int y = (int)(data.get(1) * frame.rows()); + int width = (int)(data.get(2) * frame.cols()); + int height = (int)(data.get(3) * frame.rows()); + + boxes.add(new Rect(x-width/2, y-height/2, width, height)); + confidences.add(maxscore); + classIds.add(classid); + } + } + } + + Rect[] rr = new Rect[boxes.size()]; + for(int ii = 0; ii list){ + org.opencv.core.Rect2d[] arr = new org.opencv.core.Rect2d[list.size()]; + for(int i=0;i list){ + float[] arr = new float[list.size()]; + for(int i=0;i=0){ + opened = true; + return true; + } + } + return false; + } + + public void Close_Bus(){ + if (opened){ + if (i2c_handle>=0){ + C.close(i2c_handle); + i2c_handle = -1; + } + opened = false; + } + } +} diff --git a/src/main/java/SBC/I2C_Device.java b/src/main/java/SBC/I2C_Device.java new file mode 100644 index 0000000..9fdd061 --- /dev/null +++ b/src/main/java/SBC/I2C_Device.java @@ -0,0 +1,147 @@ +package SBC; + +import lombok.Getter; + +@SuppressWarnings("unused") +public class I2C_Device { + + + Linux_C_lib C = Linux_C_lib.INSTANCE; + private @Getter int bus_handle; + private @Getter int device_address; + private @Getter int dev_handle; + private @Getter boolean opened = false; + + /** + * Create I2C Device + * @param bus_handle I2C Bus Handle, from opening I2C_Bus + * @param device_address I2C Device Address + */ + public I2C_Device(int bus_handle, int device_address){ + opened = false; + if (bus_handle<0 || device_address<0) return; + this.bus_handle = bus_handle; + this.device_address = device_address; + } + + /** + * Open I2C Device in Slave mode + * @return true if successfully opened + */ + public boolean Open_Slave(){ + boolean sucess = false; + dev_handle = C.ioctl(bus_handle, I2C_Flags.I2C_SLAVE, device_address); + if (dev_handle>=0){ + sucess = true; + } + opened = sucess; + return opened; + } + + /** + * Open I2C Device in Slave mode with Force + * @return true if successfully opened + */ + public boolean Open_SlaveForce(){ + boolean sucess = false; + dev_handle = C.ioctl(bus_handle, I2C_Flags.I2C_SLAVE_FORCE, device_address); + if (dev_handle>=0){ + C.ioctl(bus_handle,I2C_Flags.I2C_RETRIES, 3); + C.ioctl(bus_handle,I2C_Flags.I2C_TIMEOUT, 1000); + sucess = true; + } + opened = sucess; + return opened; + } + + /** + * Open I2C Device in Read Write mode + * @return true if successfully opened + */ + public boolean Open_RDWR(){ + boolean sucess = false; + dev_handle = C.ioctl(bus_handle, I2C_Flags.I2C_RDWR, device_address); + if (dev_handle>=0){ + sucess = true; + } + opened = sucess; + return opened; + } + + /** + * Open I2C Device in SMBus mode + * @return true if successfully opened + */ + public boolean Open_SMBus(){ + boolean sucess = false; + dev_handle = C.ioctl(bus_handle, I2C_Flags.I2C_SMBUS, device_address); + if (dev_handle>=0){ + sucess = true; + } + opened = sucess; + return opened; + } + + /** + * Close I2C Device + */ + public void Close(){ + C.close(dev_handle); + opened = false; + dev_handle = -1; + } + + /** + * Write Bytes to I2C Device + * @param data bytes to write + * @return number of bytes written + */ + public int WriteBytes(byte[] data){ + if (bus_handle<0 || dev_handle<0 || device_address<0) return -1; + return C.write(bus_handle, data, data.length); + } + + /** + * Write Byte to I2C Device + * @param register_address register address + * @param data byte to write + * @return number of bytes written + */ + public int WriteBytes(int register_address, byte data){ + byte[] cmd = new byte[2]; + cmd[0] = (byte) register_address; + cmd[1] = data; + return WriteBytes(cmd); + } + + /** + * Write Bytes to I2C Device + * @param register_address register address + * @param data bytes to write + * @return number of bytes written + */ + public int WriteBytes(int register_address, byte[] data){ + byte[] cmd = new byte[data.length+1]; + cmd[0] = (byte) register_address; + System.arraycopy(data, 0, cmd, 1, data.length); + return WriteBytes(cmd); + } + + /** + * Read Bytes from I2C Device + * @param readsize number of bytes to read + * @return bytes read + */ + public byte[] ReadBytes(int readsize){ + if (bus_handle<0 || dev_handle<0 || device_address<0) return null; + byte[] data = new byte[readsize]; + int read = C.read(bus_handle, data, readsize); + if (read<0) return null; + if (read getFieldOrder() { + return Arrays.asList(// + "tv_sec",// + "tv_usec"// + ); + } + + public timeval(long second, long usecond) { + tv_sec = new NativeLong(second); + tv_usec = new NativeLong(usecond); + } + } +} diff --git a/src/main/java/SBC/PCF8574.java b/src/main/java/SBC/PCF8574.java new file mode 100644 index 0000000..9d991c9 --- /dev/null +++ b/src/main/java/SBC/PCF8574.java @@ -0,0 +1,159 @@ +package SBC; + +import lombok.Getter; + +@SuppressWarnings("unused") +public class PCF8574 extends I2C_Device{ + + private byte data = 0x00; + private final @Getter String[] pinNames = new String[8]; + + /** + * Create new PCF8574 + * @param bus_number I2C Bus Number + * @param address PCF8574 Address + */ + public PCF8574(int bus_number, int address){ + super(bus_number, address); + for(int i=0; i<8; i++){ + pinNames[i] = i+""; + } + } + + /** + * Set new Pin Name + * @param pin pin number, 0-7 + * @param name new name + */ + public void setPinName(int pin, String name){ + if (pin<0 || pin>7) return; + pinNames[pin] = name; + } + + /** + * Get Pin Name + * @param pin pin number, 0-7 + * @return pin name, or null if not available + */ + public String getPinName(int pin){ + if (pin<0 || pin>7) return null; + return pinNames[pin]; + } + + /** + * Set All Pins High + * @return true if successful + */ + public boolean AllOn(){ + if (super.isOpened()){ + if (super.WriteBytes(new byte[]{(byte)0xFF})>0){ + data = (byte)0xFF; + return true; + } + } + return false; + } + + /** + * Set all Pins Low + * @return true if successful + */ + public boolean AllOff(){ + if (super.isOpened()){ + if (super.WriteBytes(new byte[]{(byte)0x00})>0){ + data = (byte)0x00; + return true; + } + } + return false; + } + + /** + * Set Pin by Pin Name + * @param pinName pin name + * @return true if successful + */ + public boolean SetPin(String pinName){ + for(int i=0; i<8; i++){ + if (pinNames[i].equals(pinName)){ + return SetPin(i); + } + } + return false; + } + + + + /** + * Set Pin High + * @param pin pin number 0-7 + * @return true if successful + */ + public boolean SetPin(int pin){ + if (pin<0 || pin>7) return false; + if (super.isOpened()){ + byte temp = (byte) (data | (1<0; + } + return false; + } + + /** + * Clear Pin by Pin Name + * @param pinName pin name + * @return true if successful + */ + public boolean ClearPin(String pinName){ + for(int i=0; i<8; i++){ + if (pinNames[i].equals(pinName)){ + return ClearPin(i); + } + } + return false; + } + + /** + * Set Pin Low + * @param pin pin number 0-7 + * @return true if successful + */ + public boolean ClearPin(int pin){ + if (pin<0 || pin>7) return false; + if (super.isOpened()){ + byte temp = (byte) (data & ~(1<0; + } + return false; + } + + + /** + * Read Pin by Pin Name + * @param pinName pin name + * @return 1 if high, 0 if low, -1 if error + */ + public int ReadPin(String pinName){ + for(int i=0; i<8; i++){ + if (pinNames[i].equals(pinName)){ + return ReadPin(i); + } + } + return -1; + } + + + /** + * Read Pin + * @param pin pin to read, 0 - 7 + * @return 1 if high, 0 if low, -1 if error + */ + public int ReadPin(int pin){ + if (pin<0 || pin>7) return -1; + if (super.isOpened()){ + byte[] buffer = super.ReadBytes(1); + byte masker = (byte) (1< 0 ? 1 : 0; + } + return -1; + } +} diff --git a/src/main/java/id/co/gtc/Main.java b/src/main/java/id/co/gtc/Main.java index 7ce72e1..86c30fb 100644 --- a/src/main/java/id/co/gtc/Main.java +++ b/src/main/java/id/co/gtc/Main.java @@ -11,6 +11,7 @@ import Other.SomeCodes; import SBC.*; import Web.*; import com.google.gson.JsonObject; +import com.sun.jna.Platform; import org.bytedeco.opencv.global.opencv_core; import org.tinylog.Logger; @@ -45,6 +46,9 @@ public class Main { private static ExecutorService gpioExecutor = null; + private static I2C_BUS i2c_bus = null; + private static PCF8574 pcf8574 = null; + // Application start from here public static void main(String[] args) { Runtime.getRuntime().addShutdownHook(new Thread(() -> { @@ -70,10 +74,16 @@ public class Main { if (Max485Direction!=null) { Logger.info("GPIO pin {} unexport : {}", Max485Direction.pin, GPIO.UnexportPin(Max485Direction)); } + if (pcf8574!=null){ + pcf8574.Close(); + } })); - init_gpio(); + System.out.println("Current Directory : "+currentDirectory); + + //init_gpio(); + init_pcf8574(); init_system_monitoring(); init_properties(); @@ -81,20 +91,54 @@ public class Main { init_Vapix(); init_audio(); + init_pantiltcontroller(); init_webserver(); init_rtspgrabber(); } + private static void init_pcf8574(){ + if (Platform.isLinux()){ + i2c_bus = new I2C_BUS(7); + if (i2c_bus.Open_Bus()){ + Logger.info("I2C Bus opened"); + pcf8574 = new PCF8574(i2c_bus.getI2c_handle(), 0x27); + if (pcf8574.Open_Slave()){ + System.out.println("PCF8574 opened"); + pcf8574.AllOff(); + pcf8574.setPinName(0, "Amplifier Power"); + pcf8574.setPinName(1, "Led Web"); + pcf8574.setPinName(2, "Led IP Camera"); + pcf8574.setPinName(3, "Led Pan Tilt"); + pcf8574.setPinName(4, "Max485 Direction"); + gpioExecutor = Executors.newVirtualThreadPerTaskExecutor(); + + + } else { + System.out.println("Failed to open PCF8574"); + } + } else { + System.out.println("Failed to open I2C Bus"); + } + } else System.out.println("PCF8574 not supported on this platform"); + } + private static void init_gpio(){ - if (GPIO.HaveGPIO()){ - gpioExecutor = Executors.newVirtualThreadPerTaskExecutor(); - AmplifierPower = InitializePin(JetsonOrinPins.Pin13, true); - LedWeb = InitializePin(JetsonOrinPins.Pin15, true); - LedIpCamera = InitializePin(JetsonOrinPins.Pin19, true); - LedPanTilt = InitializePin(JetsonOrinPins.Pin21, true); - Max485Direction = InitializePin(JetsonOrinPins.Pin23, true); - } + if (Platform.isLinux()){ + if (GPIO.HaveGPIO()){ + gpioExecutor = Executors.newVirtualThreadPerTaskExecutor(); + AmplifierPower = InitializePin(JetsonOrinPins.Pin13, true); + LedWeb = InitializePin(JetsonOrinPins.Pin15, true); + LedIpCamera = InitializePin(JetsonOrinPins.Pin19, true); + LedPanTilt = InitializePin(JetsonOrinPins.Pin21, true); + Max485Direction = InitializePin(JetsonOrinPins.Pin23, true); + GPIO.SetValue(AmplifierPower,false); + GPIO.SetValue(LedWeb,false); + GPIO.SetValue(LedIpCamera,false); + GPIO.SetValue(LedPanTilt,false); + GPIO.SetValue(Max485Direction,false); + } + } else System.out.println("GPIO not supported on this platform"); } @@ -121,17 +165,65 @@ public class Main { public static void Max485Direction(boolean isTransmit){ if (Max485Direction!=null){ GPIO.SetValue(Max485Direction, isTransmit); + } else if (pcf8574!=null && pcf8574.isOpened()){ + if (isTransmit){ + pcf8574.SetPin("Max485 Direction"); + } else { + pcf8574.ClearPin("Max485 Direction"); + } } } // dipanggil di PanTiltController, maka perlu public dan static public static void Blink_LedPanTilt(){ - Blink(LedPanTilt); + if (LedPanTilt!=null){ + Blink(LedPanTilt); + } else if (pcf8574!=null && pcf8574.isOpened()){ + Blink("Led Pan Tilt"); + } + } + + public static void Blink_LedWeb(){ + if (LedWeb!=null){ + Blink(LedWeb); + } else if (pcf8574!=null && pcf8574.isOpened()){ + Blink("Led Web"); + } + } + + public static void Blink_LedIpCamera(){ + if (LedIpCamera!=null){ + Blink(LedIpCamera); + } else if (pcf8574!=null && pcf8574.isOpened()){ + Blink("Led IP Camera"); + } } private static void AmplifierControl(boolean isON){ if (AmplifierPower!=null){ GPIO.SetValue(AmplifierPower, isON); + } else if (pcf8574!=null && pcf8574.isOpened()){ + if (isON){ + pcf8574.SetPin("Amplifier Power"); + } else { + pcf8574.ClearPin("Amplifier Power"); + } + } + } + + private static void Blink(String pinName){ + if (pcf8574!=null && pcf8574.isOpened()){ + if (gpioExecutor!=null){ + gpioExecutor.submit(()->{ + pcf8574.SetPin(pinName); + try { + Thread.sleep(20); + } catch (InterruptedException ignored) { + } + pcf8574.ClearPin(pinName); + }); + } + } } @@ -227,10 +319,16 @@ public class Main { private static void init_Vapix(){ Properties config = SomeCodes.LoadProperties("config.properties"); + System.out.println("Saved Configuration for Camera"); String ip = config.getProperty("Camera_ip"); String port = config.getProperty("Camera_port"); String username = config.getProperty("Camera_user"); String password = config.getProperty("Camera_password"); + System.out.println("Camera IP : "+ip); + System.out.println("Camera Port : "+port); + System.out.println("Camera Username : "+username); + System.out.println("Camera Password : "+password); + if (ValidString(ip)){ if (ValidPortNumber(port)){ if (ValidString(username)){ @@ -246,7 +344,7 @@ public class Main { } else Logger.error("PTZ Disabled"); Logger.info("Max Zoom: "+vapixProtocol.GetPTZMaxZoom()); Logger.info("Min Zoom: "+vapixProtocol.GetPTZMinZoom()); - Blink(LedIpCamera); + Blink_LedIpCamera(); } else Logger.error("Failed to query camera"); } else Logger.error("Camera IP is not reachable"); } else Logger.error("Camera Password is not valid string"); @@ -255,15 +353,42 @@ public class Main { } else Logger.error( "Camera IP is not valid string"); } + private static void test_pantiltcontroller(){ + System.out.println("Pan Tilt Controller Test"); + panTiltController.PanLeft((byte)0x20); + System.out.println("Pan Left"); + Sleep(2000); + panTiltController.PanRight((byte)0x20); + System.out.println("Pan Right"); + Sleep(2000); + panTiltController.StopMovement(); + System.out.println("Stop Movement"); + panTiltController.TiltUp((byte)0x20); + System.out.println("Tilt Up"); + Sleep(2000); + panTiltController.TiltDown((byte)0x20); + System.out.println("Tilt Down"); + Sleep(2000); + panTiltController.StopMovement(); + System.out.println("Stop Movement"); + panTiltController.GoToPreset((byte)0); + System.out.println("Go To Preset 0"); + } + private static void init_pantiltcontroller() { Properties config = SomeCodes.LoadProperties("config.properties"); String portname = config.getProperty("SerialPort"); String baudrate = config.getProperty("SerialBaudRate"); String PanTiltID = config.getProperty("PanTiltID"); + Logger.info("Saved Configuration for Pan Tilt Controller"); + Logger.info("Serial Port : "+portname); + Logger.info("Serial Baud Rate : "+baudrate); + Logger.info("Pan Tilt ID : "+PanTiltID); if (ValidString(portname)){ if (ValidInteger(baudrate)){ if (ValidInteger(PanTiltID)){ panTiltController = new PanTiltController(portname, Integer.parseInt(baudrate), Integer.parseInt(PanTiltID)); + if (panTiltController.isOpen()) test_pantiltcontroller(); } } else Logger.error("Invalid PTZ Baudrate"); } else Logger.error("Invalid PTZ Port"); @@ -277,16 +402,18 @@ public class Main { Properties config = SomeCodes.LoadProperties("config.properties"); String targetip = config.getProperty("Camera_ip"); String rtsppath = config.getProperty("Camera_Rtsp_path"); + System.out.println("Camera IP : "+targetip); + System.out.println("Camera Rtsp Path : "+rtsppath); rtspGrabber = null; if (ValidString(targetip)){ if (ValidString(rtsppath)){ if (IpIsReachable(targetip)){ - Logger.info("Camera IP is reachable"); + Logger.info("Camera IP : "+targetip+" is reachable"); rtspGrabber = new RtspGrabber(targetip, rtsppath); rtspGrabber.Start(true, 1920, 1080); - } else Logger.error("Camera IP is not reachable"); - } else Logger.error("Camera Path is not valid string"); - } else Logger.error("Camera IP is not valid string"); + } else System.out.println("Camera IP : "+targetip+" is not reachable"); + } else System.out.println("Camera Path : "+rtsppath+" is not valid string"); + } else System.out.println("Camera IP : "+targetip+" is not valid string"); } private static void init_audio() { @@ -309,16 +436,19 @@ public class Main { @Override public void onPlaybackStart(AudioFileProperties prop) { Logger.info("Playback started for {}", prop.filename); + AmplifierControl(true); } @Override public void onPlaybackFinished(AudioFileProperties prop) { Logger.info("Playback finished for {}", prop.filename); + AmplifierControl(false); } @Override public void onPlaybackFailure(AudioFileProperties prop, String reason) { Logger.error("Playback failed for {}: {}", prop.filename, reason); + AmplifierControl(false); } @Override @@ -335,7 +465,7 @@ public class Main { @Override public WebsocketReply onWebsocketCommand(WebsocketCommand command) { - Blink(LedWeb); + Blink_LedWeb(); byte speed; String cmd = command.command.toUpperCase().trim(); switch (cmd){ @@ -361,10 +491,10 @@ public class Main { return new WebsocketReply("STOP MOVEMENT", ""); // Audio Related Commands case "MUTE": - audioPlayer.Mute(); + if (audioPlayer!=null) audioPlayer.Mute(); return new WebsocketReply("MUTE", ""); case "UNMUTE": - audioPlayer.Unmute(); + if (audioPlayer!=null) audioPlayer.Unmute(); return new WebsocketReply("UNMUTE", ""); case "SET VOLUME" : int volume=-1; @@ -374,11 +504,11 @@ public class Main { if (volume>100) volume = 100; } if (volume>=0){ - audioPlayer.setPlaybackvolume(volume); + if (audioPlayer!=null) audioPlayer.setPlaybackvolume(volume); return new WebsocketReply("SET VOLUME", String.valueOf(volume)); } else return new WebsocketReply("SET VOLUME", "Invalid Volume Value"); case "GET VOLUME" : - int vol = audioPlayer.getPlaybackvolume(); + int vol = audioPlayer!=null ? audioPlayer.getPlaybackvolume() : 0; return new WebsocketReply("GET VOLUME", String.valueOf(vol)); case "PLAY AUDIO" : if (ValidInteger(command.data)){ @@ -391,7 +521,7 @@ public class Main { if (afp!=null){ audioFileProperties = afp; audioPlayer.PlayAudioFile(afp, true, pe); - AmplifierControl(true); + //AmplifierControl(true); return new WebsocketReply("PLAY AUDIO", afp.filename); } else return new WebsocketReply("PLAY AUDIO", "Failed to open audio file "+filename); @@ -403,18 +533,18 @@ public class Main { audioPlayer.CloseAudioFile(audioFileProperties); // close previous audio file String filename = audioFileProperties.filename; audioFileProperties = null; - AmplifierControl(false); + //AmplifierControl(false); return new WebsocketReply("STOP AUDIO", filename); } else return new WebsocketReply("STOP AUDIO", "No audioFileProperties"); // ZOOM Related Commands case "GET MAX ZOOM": if (vapixProtocol!=null){ - Blink(LedIpCamera); + Blink_LedIpCamera(); return new WebsocketReply("GET MAX ZOOM", String.valueOf(vapixProtocol.GetPTZMaxZoom())); } else return new WebsocketReply("GET MAX ZOOM", "VapixProtocol not initialized"); case "GET ZOOM": if (vapixProtocol!=null){ - Blink(LedIpCamera); + Blink_LedIpCamera(); return new WebsocketReply("GET ZOOM", String.valueOf(vapixProtocol.GetCurrentZoomValue())); } else return new WebsocketReply("GET ZOOM", "VapixProtocol not initialized"); case "SET ZOOM": @@ -424,7 +554,7 @@ public class Main { if (zoomvapixProtocol.GetPTZMaxZoom()) zoom = vapixProtocol.GetPTZMaxZoom(); if (vapixProtocol.Zoom(1, zoom)){ - Blink(LedIpCamera); + Blink_LedIpCamera(); return new WebsocketReply("ZOOM", String.valueOf(zoom)); } else return new WebsocketReply("ZOOM", "Failed to zoom"); } else return new WebsocketReply("ZOOM", "Invalid Zoom Value"); @@ -432,15 +562,21 @@ public class Main { // Live Streaming Related Commands case "GET BASE64": if (rtspGrabber!=null){ - if (Objects.equals(command.data,"HQ")) - return new WebsocketReply("GET BASE64", "data:image/jpeg;base64,"+ rtspGrabber.getLastHQBase64(), rtspGrabber.HQStreamingStatus()); - else - return new WebsocketReply("GET BASE64", "data:image/jpeg;base64,"+ rtspGrabber.getLastLQBase64(), rtspGrabber.LQStreamingStatus()); + switch (command.data){ + case "HQ": + return new WebsocketReply("GET BASE64", "data:image/jpeg;base64,"+ rtspGrabber.getLastHQBase64(), rtspGrabber.HQStreamingStatus()); + case "LQ": + return new WebsocketReply("GET BASE64", "data:image/jpeg;base64,"+ rtspGrabber.getLastLQBase64(), rtspGrabber.LQStreamingStatus()); + case "YOLO": + return new WebsocketReply("GET BASE64", "data:image/jpeg;base64,"+ rtspGrabber.getLastYoloBase64(), rtspGrabber.HQStreamingStatus()); + default: + return new WebsocketReply("GET BASE64", "RTSP Grabber not initialized"); + } } else return new WebsocketReply("GET BASE64", "RTSP Grabber not initialized"); case "GET RESOLUTION": if (vapixProtocol!=null){ int[] res = vapixProtocol.GetCurrentResolution(1); - Blink(LedIpCamera); + Blink_LedIpCamera(); return new WebsocketReply("GET RESOLUTION", String.format("%dx%d", res[0], res[1])); } else return new WebsocketReply("GET RESOLUTION", "VapixProtocol not initialized"); case "GET AUDIOFILES":