shjung преди 3 години
родител
ревизия
efe5d5c98d

+ 2 - 2
src/main/java/com/its/api/bis/service/BitService.java

@@ -130,7 +130,7 @@ public class BitService {
         Map<String, SttsCommErrDto> resultMap = new HashMap<>();
 
         LocalDateTime fromDt = LocalDate.now().atTime(0, 0, 0);
-        log.error("{}", fromDt);
+        //log.error("{}", fromDt);
         List<Bit> ctlrList = this.repo.findAllList();
         List<BitStatusHistory> sttsList = this.sttsHsRepo.findAllStts(fromDt);
         List<SttsHsErrCntInf> errList = this.sttsHsRepo.findAllCommErrorCount(fromDt);
@@ -203,7 +203,7 @@ public class BitService {
         List<FcltSttsDto> sttsDtoList = new ArrayList<>();
         List<Bit> ctlrList = this.repo.findAllList();
         LocalDateTime fromDt = LocalDate.now().atTime(0, 0, 0);
-        log.error("{}", fromDt);
+        //log.error("{}", fromDt);
         List<BitStatusHistory> sttsList = this.sttsHsRepo.findAllStts(fromDt);
 
         // 전체 BIT 상태정보 초기화

+ 10 - 3
src/main/java/com/its/api/its/controller/cctv/CctvCommonController.java

@@ -1,15 +1,16 @@
 package com.its.api.its.controller.cctv;
 
+import com.its.api.its.model.dto.cctv.CctvControlDto;
 import com.its.api.its.model.dto.cctv.TbCctvCtlrDto;
+import com.its.api.its.service.cctv.CctvControlService;
 import com.its.api.its.service.cctv.TbCctvCtlrService;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.RequiredArgsConstructor;
 import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
 
+import javax.validation.Valid;
 import java.util.List;
 
 @Api(tags = "11.CCTV-0.공통")
@@ -20,6 +21,7 @@ import java.util.List;
 public class CctvCommonController {
 
     private final TbCctvCtlrService service;
+    private final CctvControlService controlService;
 
     @ApiOperation(value = "CCTV 목록 조회(TB_CCTV_CTLR)", response = TbCctvCtlrDto.class, responseContainer = "ArrayList")
     @GetMapping(value = "/cctv-list", produces = {"application/json; charset=utf8"})
@@ -27,4 +29,9 @@ public class CctvCommonController {
         return this.service.findAllList();
     }
 
+    @ApiOperation(value = "CCTV PTZ 제어", response = CctvControlDto.CctvControlPtzRes.class)
+    @PostMapping(value = "/control/ptz/{id}", produces = {"application/json; charset=utf8"})
+    public CctvControlDto.CctvControlPtzRes controlPtz(@PathVariable("id") Long id, @RequestBody @Valid final CctvControlDto.CctvControlPtzReq req) {
+        return this.controlService.controlPtz(id, req);
+    }
 }

+ 83 - 0
src/main/java/com/its/api/its/model/dto/cctv/CctvControlDto.java

@@ -0,0 +1,83 @@
+package com.its.api.its.model.dto.cctv;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.*;
+
+import javax.validation.constraints.PositiveOrZero;
+import java.io.Serializable;
+
+/**
+ * CCTV 제어기 DTO Class
+ */
+@Data
+@Builder
+@ApiModel("CctvControlDto(CCTV 제어 정보")
+public class CctvControlDto implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    @ApiModel("CctvControlPtzReq(CCTV PTZ 제어 정보)")
+    @Getter
+    @Setter
+    @ToString
+    @NoArgsConstructor(access = AccessLevel.PROTECTED)
+    public static class CctvControlPtzReq {
+
+        @ApiModelProperty("제어 명령(tilt-up, tilt-down, pan-left, pan-right, zoom-in, zoom-out, focus-in, focus-out, up-left, up-right, down-left, down-right)")
+        @JsonProperty("command")
+        private String command;
+
+        @ApiModelProperty("제어 명령 제어(start, stop)")
+        @JsonProperty("action")
+        private String action;
+
+        @ApiModelProperty("CCTV 제어기 ID, Nullable = Y, VARCHAR(30)")  // Y VARCHAR(30)
+        @JsonProperty("speed")
+        @PositiveOrZero
+        private Integer speed;
+
+        @ApiModelProperty("로그인 사용자 ID")
+        @JsonProperty("user_id")
+        private String userId;
+
+        @Builder
+        public CctvControlPtzReq(String command, String action, Integer speed, String user_id) {
+            this.command = command;
+            this.action = action;
+            this.speed = speed;
+            this.userId = user_id;
+        }
+    }
+    @ApiModel("CctvControlPtzRes(CCTV PTZ 제어 응답)")
+    @Getter
+    @Setter
+    @ToString
+    @NoArgsConstructor(access = AccessLevel.PROTECTED)
+    public static class CctvControlPtzRes {
+
+        @ApiModelProperty("제어 명령(tilt-up, tilt-down, pan-left, pan-right, zoom-in, zoom-out, focus-in, focus-out, up-left, up-right, down-left, down-right)")
+        @JsonProperty("command")
+        private String command;
+
+        @ApiModelProperty("제어 명령 제어(start, stop)")
+        @JsonProperty("action")
+        private String action;
+
+        @ApiModelProperty("제어결과")
+        @JsonProperty("result")
+        private Integer result;
+
+        @ApiModelProperty("제어결과메시지")
+        @JsonProperty("message")
+        private String message;
+
+        @Builder
+        public CctvControlPtzRes(String command, String action, Integer result, String message) {
+            this.command = command;
+            this.action = action;
+            this.result = result;
+            this.message = message;
+        }
+    }
+}

+ 5 - 0
src/main/java/com/its/api/its/repository/cctv/TbCctvCtlrRepository.java

@@ -4,9 +4,11 @@ import com.its.api.its.model.entity.cctv.TbCctvCtlr;
 import org.springframework.data.jpa.repository.JpaRepository;
 import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
 import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
 import org.springframework.stereotype.Repository;
 
 import java.util.List;
+import java.util.Optional;
 
 @Repository
 public interface TbCctvCtlrRepository extends JpaRepository<TbCctvCtlr, Long>, JpaSpecificationExecutor<TbCctvCtlr> {
@@ -14,6 +16,9 @@ public interface TbCctvCtlrRepository extends JpaRepository<TbCctvCtlr, Long>, J
     @Query("select p from TbCctvCtlr p left outer join fetch p.state")
     List<TbCctvCtlr> findAll();
 
+    @Query("select p from TbCctvCtlr p left outer join fetch p.state where p.cctvMngmNmbr = :id")
+    Optional<TbCctvCtlr> findOne(@Param("id") Long id);
+
     @Query("select p from TbCctvCtlr p left outer join fetch p.state where p.delYn = 'N'")
     List<TbCctvCtlr> findAllList();
 

+ 134 - 0
src/main/java/com/its/api/its/service/cctv/CctvControlService.java

@@ -0,0 +1,134 @@
+package com.its.api.its.service.cctv;
+
+import com.its.api.its.model.dto.cctv.CctvControlDto;
+import com.its.api.its.model.entity.cctv.TbCctvCtlr;
+import com.its.api.its.repository.cctv.TbCctvCtlrRepository;
+import com.its.api.utils.SysUtils;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang.StringUtils;
+import org.springframework.stereotype.Service;
+
+import java.io.*;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.NoSuchElementException;
+
+@Slf4j
+@RequiredArgsConstructor
+@Service
+public class CctvControlService {
+
+    private final TbCctvCtlrRepository repo;
+    private final CctvControlZenoService zenoControl;
+
+    // 데이터 1건 조회, 없으면 exception
+    private TbCctvCtlr requireOne(Long id) {
+        //return this.repo.findById(id)
+        //        .orElseThrow(() -> new NoSuchElementException("데이터가 존재하지 않습니다: " + id));
+        return this.repo.findOne(id)
+                .orElseThrow(() -> new NoSuchElementException("데이터가 존재하지 않습니다: " + id));
+    }
+
+    public CctvControlDto.CctvControlPtzRes controlPtzProbeDigital(String ipAddr, String userId, String userPswd, CctvControlDto.CctvControlPtzReq req) {
+        CctvControlDto.CctvControlPtzRes result = new CctvControlDto.CctvControlPtzRes(req.getCommand(), req.getAction(), 0, "success");
+        return result;
+    }
+
+    public static class ZenoCommand {
+        private byte[] cmd;
+        public ZenoCommand(byte[] cmd) {
+            this.cmd = cmd;
+        }
+        public byte[] getCmd() {
+            if (this.cmd == null) {
+                return null;
+            }
+            byte cmd[] = new byte[this.cmd.length];
+            System.arraycopy(this.cmd, 0, cmd, 0, this.cmd.length);
+            return cmd;
+        }
+    }
+
+    public byte[] getZenoCommand(CctvControlDto.CctvControlPtzReq req) {
+        return this.zenoControl.getCmd(req.getCommand(), req.getAction(), req.getSpeed());
+    }
+    public CctvControlDto.CctvControlPtzRes controlPtzZeno(String ipAddr, String userId, String userPswd, CctvControlDto.CctvControlPtzReq req) {
+        CctvControlDto.CctvControlPtzRes result = new CctvControlDto.CctvControlPtzRes(req.getCommand(), req.getAction(), 0, "success");
+
+        String apiUrl = "http://" + ipAddr + "/cgi-bin/admin/uartctrl.cgi";
+        byte[] controlData = getZenoCommand(req);
+        log.error("{}, {}", apiUrl, SysUtils.byteArrayToHex(controlData));
+        try {
+            URL url = new URL(apiUrl);
+            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+            connection.setConnectTimeout(5000); //서버에 연결되는 Timeout 시간 설정
+            connection.setReadTimeout(5000); // InputStream 읽어 오는 Timeout 시간 설정
+            //connection.addRequestProperty("x-api-key", RestTestCommon.API_KEY); //key값 설정
+
+            connection.setDoOutput(true); //POST 데이터를 OutputStream으로 넘겨 주겠다는 설정
+            connection.setRequestMethod("POST");
+
+            //json 으로 message 를 전달하고자 할 때
+            connection.setRequestProperty("Content-Type", "application/json");
+            connection.setDoInput(true);
+
+            connection.setUseCaches(false);
+            connection.setDefaultUseCaches(false);
+
+            PrintWriter writer = null;
+            OutputStream output = connection.getOutputStream();
+            writer = new PrintWriter(new OutputStreamWriter(output, "utf-8"), true);
+
+
+            // Send binary file.
+            /*writer.append("--" + boundary).append("\r\n");
+            writer.append("Content-Disposition: form-data; name=\"binaryFile\"; filename=\"" + binaryFile.getName() + "\"").append("\r\n");
+            writer.append("Content-Type: " + URLConnection.guessContentTypeFromName(binaryFile.getName()).append("\r\n");
+            writer.append("Content-Transfer-Encoding: binary").append("\r\n");
+            writer.append("\r\n").flush();
+*/
+            OutputStreamWriter wr = new OutputStreamWriter(connection.getOutputStream());
+            wr.flush();
+
+            StringBuilder sb = new StringBuilder();
+            if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
+                //Stream을 처리해줘야 하는 귀찮음이 있음.
+                BufferedReader br = new BufferedReader(
+                        new InputStreamReader(connection.getInputStream(), "utf-8"));
+                String line;
+                while ((line = br.readLine()) != null) {
+                    sb.append(line).append("\n");
+                }
+                br.close();
+                System.out.println("" + sb.toString());
+            } else {
+                System.out.println(connection.getResponseMessage());
+            }
+        } catch (Exception e){
+            log.error("{}", e);
+        }
+
+        return result;
+    }
+
+    /**
+     * CCTV PTZ 컨트롤
+     * @param id
+     * @param req
+     * @return
+     */
+    public CctvControlDto.CctvControlPtzRes controlPtz(Long id, CctvControlDto.CctvControlPtzReq req) {
+        log.info("{}", req);
+        TbCctvCtlr cctv = this.requireOne(id);
+        if (StringUtils.equals("1", cctv.getCctvType())) {
+            // 제노 CCTV
+            return this.controlPtzZeno(cctv.getCctvCtlrIp(), "root", "pass", req);
+        }
+        else if (StringUtils.equals("2", cctv.getCctvType())) {
+            // 프로브디지털
+            return this.controlPtzProbeDigital(cctv.getCctvCtlrIp(), "admin", "1234", req);
+        }
+        return new CctvControlDto.CctvControlPtzRes(req.getCommand(), req.getAction(), 1, "unknown cctv type");
+    }
+}

+ 77 - 0
src/main/java/com/its/api/its/service/cctv/CctvControlZenoService.java

@@ -0,0 +1,77 @@
+package com.its.api.its.service.cctv;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang.StringUtils;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.PostConstruct;
+import java.util.HashMap;
+import java.util.Map;
+
+@Slf4j
+@RequiredArgsConstructor
+@Service
+public class CctvControlZenoService {
+
+    Map<String, ZenoCommand> startCmd = new HashMap<>();
+    Map<String, ZenoCommand> stopCmd = new HashMap<>();
+
+    @PostConstruct
+    void init() {
+        this.startCmd.put("tilt-up",   new ZenoCommand(new byte[]{ 0x10, (byte)0xFF, 0x01, 0x00,       0x08, 0x00,       0x28, 0x31 }));
+        this.startCmd.put("tilt-down", new ZenoCommand(new byte[]{ 0x10, (byte)0xFF, 0x01, 0x00,       0x10, 0x00,       0x28, 0x31 }));
+        this.startCmd.put("pan-left",  new ZenoCommand(new byte[]{ 0x10, (byte)0xFF, 0x01, 0x00,       0x04, 0x00,       0x28, 0x31 }));
+        this.startCmd.put("pan-right", new ZenoCommand(new byte[]{ 0x10, (byte)0xFF, 0x01, 0x00,       0x02, 0x00,       0x28, 0x31 }));
+        this.startCmd.put("zoom-in",   new ZenoCommand(new byte[]{ 0x50, (byte)0xFF, 0x01, 0x00,       0x20, 0x00, (byte)0xFF, 0x31 }));
+        this.startCmd.put("zoom-out",  new ZenoCommand(new byte[]{ 0x50, (byte)0xFF, 0x01, 0x00,       0x08, 0x00, (byte)0xFF, 0x31 }));
+        this.startCmd.put("focus-in",  new ZenoCommand(new byte[]{ 0x50, (byte)0xFF, 0x01, 0x00, (byte)0x80, 0x00, (byte)0xFF, 0x31 }));
+        this.startCmd.put("focus-out", new ZenoCommand(new byte[]{ 0x50, (byte)0xFF, 0x01, 0x01,       0x00, 0x00, (byte)0xFF, 0x31 }));
+
+        this.stopCmd.put("tilt-up",   new ZenoCommand(new byte[]{ 0x10, (byte)0xFF, 0x01, 0x00, 0x00, 0x00,       0x00, 0x01 }));
+        this.stopCmd.put("tilt-down", new ZenoCommand(new byte[]{ 0x10, (byte)0xFF, 0x01, 0x00, 0x00, 0x00,       0x00, 0x01 }));
+        this.stopCmd.put("pan-left",  new ZenoCommand(new byte[]{ 0x10, (byte)0xFF, 0x01, 0x00, 0x00, 0x00,       0x00, 0x01 }));
+        this.stopCmd.put("pan-right", new ZenoCommand(new byte[]{ 0x10, (byte)0xFF, 0x01, 0x00, 0x00, 0x00,       0x00, 0x01 }));
+        this.stopCmd.put("zoom-in",   new ZenoCommand(new byte[]{ 0x50, (byte)0xFF, 0x01, 0x00, 0x00, 0x00, (byte)0xFF, 0x01 }));
+        this.stopCmd.put("zoom-out",  new ZenoCommand(new byte[]{ 0x50, (byte)0xFF, 0x01, 0x00, 0x00, 0x00, (byte)0xFF, 0x01 }));
+        this.stopCmd.put("focus-in",  new ZenoCommand(new byte[]{ 0x50, (byte)0xFF, 0x01, 0x00, 0x08, 0x00, (byte)0xFF, 0x31 }));
+        this.stopCmd.put("focus-out", new ZenoCommand(new byte[]{ 0x50, (byte)0xFF, 0x01, 0x00, 0x08, 0x00, (byte)0xFF, 0x31 }));
+    }
+
+    public byte[] getCmd(String control, String action, int value) {
+        if (StringUtils.equalsIgnoreCase("start", action)) {
+            ZenoCommand command = this.startCmd.get(control);
+            if (command != null) {
+                return command.getCmd();
+            }
+        } else if (StringUtils.equalsIgnoreCase("stop", action)) {
+            ZenoCommand command = this.stopCmd.get(control);
+            if (command != null) {
+                return command.getCmd();
+            }
+        }
+        return null;
+    }
+
+    public static class ZenoCommand {
+        private byte[] cmd;
+        public ZenoCommand(byte[] cmd) {
+            this.cmd = cmd;
+        }
+        public byte[] getCmd() {
+            if (this.cmd == null) {
+                return null;
+            }
+            byte cmd[] = new byte[this.cmd.length];
+            System.arraycopy(this.cmd, 0, cmd, 0, this.cmd.length);
+
+            int cs = 0;
+            for (int ii = 2; ii < cmd.length-2; ii++) {
+                cs += cmd[ii];
+            }
+            cmd[cmd.length-1] = (byte)cs;
+            return cmd;
+        }
+    }
+
+}

+ 1 - 1
src/main/java/com/its/api/scheduler/job/CctvPsetScnrJobThread.java

@@ -54,7 +54,7 @@ public class CctvPsetScnrJobThread {
             }
 
             // 제어를 시작한다.
-log.error("Control: {}, {}, {}, {}", obj.getCctvMngmNmbr(), obj.getStrtHms(), obj.getPsetNmbr(), currCtrlDt);
+            log.info("Control: {}, {}, {}, {}", obj.getCctvMngmNmbr(), obj.getStrtHms(), obj.getPsetNmbr(), currCtrlDt);
 
             TbCctvScnr scnr = TbCctvScnr.builder()
                     .cctvMngmNmbr(obj.getCctvMngmNmbr())