Commit 8cd3ffc6 authored by Ishankha K.C's avatar Ishankha K.C

Merge branch 'feature/chamode_dev' into 'master'

Feature/chamode dev

See merge request !9
parents 21ccb03a 5e9b943d
...@@ -47,7 +47,9 @@ public class SecurityConfig { ...@@ -47,7 +47,9 @@ public class SecurityConfig {
"/webjars/**", "/webjars/**",
"/swagger-ui.html", "/swagger-ui.html",
"/emotional/video-process", "/emotional/video-process",
"/test/**" "/test/**",
"/activity-logs/add",
"/baby/**"
}; };
@Bean @Bean
......
package com.kaluwa.enterprises.babycarebackendservice.config; package com.kaluwa.enterprises.babycarebackendservice.config;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.kaluwa.enterprises.babycarebackendservice.dao.DevicesDao;
import com.kaluwa.enterprises.babycarebackendservice.dto.ActivityLogDto; import com.kaluwa.enterprises.babycarebackendservice.dto.ActivityLogDto;
import com.kaluwa.enterprises.babycarebackendservice.model.Devices;
import com.kaluwa.enterprises.babycarebackendservice.service.ActivityLogService; import com.kaluwa.enterprises.babycarebackendservice.service.ActivityLogService;
import com.kaluwa.enterprises.babycarebackendservice.socketHandlers.EmotionPrediction; import com.kaluwa.enterprises.babycarebackendservice.socketHandlers.EmotionPrediction;
import org.springframework.beans.factory.annotation.Autowired; import lombok.Setter;
import org.springframework.scheduling.annotation.Scheduled; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.BinaryMessage;
import org.springframework.web.socket.TextMessage; import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession; import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.client.standard.StandardWebSocketClient; import org.springframework.web.socket.client.standard.StandardWebSocketClient;
import org.springframework.web.socket.handler.TextWebSocketHandler; import org.springframework.web.socket.handler.TextWebSocketHandler;
import java.util.concurrent.Executors; import java.io.IOException;
import java.util.concurrent.ScheduledExecutorService; import java.util.List;
import java.util.concurrent.TimeUnit; import java.util.concurrent.ConcurrentHashMap;
import static com.kaluwa.enterprises.babycarebackendservice.config.WebSocketConfig.VideoFrameHandler.sendTextMessageToClient;
import static com.kaluwa.enterprises.babycarebackendservice.constants.Configs.WEBSOCKET_URL; import static com.kaluwa.enterprises.babycarebackendservice.constants.Configs.WEBSOCKET_URL;
import static com.kaluwa.enterprises.babycarebackendservice.constants.LogTypes.EMOTION; import static com.kaluwa.enterprises.babycarebackendservice.constants.LogTypes.EMOTION;
@Slf4j
public class WebSocketClient { public class WebSocketClient {
private WebSocketSession session; private ConcurrentHashMap<String, WebSocketSession> activeSessions = new ConcurrentHashMap<>();
private static final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
private ActivityLogService activityLogService; private ActivityLogService activityLogService;
private DevicesDao devicesDao;
// Method to set the VideoFrameHandler reference
@Setter
private WebSocketConfig.VideoFrameHandler videoFrameHandler; // Reference to VideoFrameHandler
public WebSocketClient(ActivityLogService activityLogService) { public WebSocketClient(ActivityLogService activityLogService, DevicesDao devicesDao) {
this.activityLogService = activityLogService; this.activityLogService = activityLogService;
connectToWebSocket(); this.devicesDao = devicesDao;
connectionLooper(); // Connect to WebSocket when the application starts
} }
private void connectToWebSocket() { private void connectToWebSocket() {
List<Devices> devices = devicesDao.findAll();
for (Devices device : devices) {
if (!activeSessions.containsKey(device.getDeviceUid())) {
connectToWebSocket(device.getDeviceUid());
}
}
}
public void connectionLooper() {
new Thread(() -> {
// run until activeSessions.deviceIds = devicesDao.deviceIds
while (true) {
List<Devices> devices = devicesDao.findAll();
for (Devices device : devices) {
if (!activeSessions.containsKey(device.getDeviceUid())) {
connectToWebSocket(device.getDeviceUid());
}
}
try { try {
this.session = new StandardWebSocketClient() Thread.sleep(10000); // Check every 10 seconds
.doHandshake(new MyWebSocketHandler(this), WEBSOCKET_URL) } catch (InterruptedException e) {
.get(); log.error("Error in connectionLooper: {}", e.getMessage());
System.out.println("Connected to WebSocket!"); }
} catch (Exception e) {
System.out.println("Failed to connect to WebSocket, scheduling reconnection...");
scheduleReconnection();
} }
}).start();
} }
public void sendBytesToWebSocket(byte[] bytes) { public void clientConnectToWebSocket(String deviceId) {
// Check if the session is already active
if (activeSessions.containsKey(deviceId)) {
log.info("WebSocket connection already active for device: {}", deviceId);
}
}
public void connectToWebSocket(String deviceId) {
try { try {
session.sendMessage(new BinaryMessage(bytes)); WEBSOCKET_URL = WEBSOCKET_URL.replace("{device_id}", deviceId);
WebSocketSession session = new StandardWebSocketClient()
.doHandshake(new MyWebSocketHandler(this), WEBSOCKET_URL)
.get();
activeSessions.put(deviceId, session); // Store the session
log.info("Connected to WebSocket for device: {}", deviceId);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); log.error("Failed to connect to WebSocket for device: {}", deviceId);
} }
} }
private void scheduleReconnection() { public void disconnectWebSocket(String deviceId) {
scheduler.schedule(this::connectToWebSocket, 2, TimeUnit.MINUTES); WebSocketSession session = activeSessions.remove(deviceId); // Remove session from the map
if (session != null && session.isOpen()) {
try {
session.close(); // Gracefully close the session
log.info("WebSocket connection closed successfully for device: {}", deviceId);
} catch (IOException e) {
log.error("Error while closing WebSocket session for device: {}, Error: {}", deviceId, e.getMessage());
} }
} else {
@Scheduled(fixedDelay = 60000) // Check every 1 minutes log.error("No active WebSocket connection to close for device: {}", deviceId);
private void checkConnection() {
if (session == null || !session.isOpen()) {
System.out.println("WebSocket connection is closed. Reconnecting...");
connectToWebSocket();
} }
} }
static ObjectMapper objectMapper = new ObjectMapper(); static ObjectMapper objectMapper = new ObjectMapper();
public static EmotionPrediction[] predictions; public static EmotionPrediction[] predictions;
@Slf4j
static class MyWebSocketHandler extends TextWebSocketHandler { static class MyWebSocketHandler extends TextWebSocketHandler {
private final WebSocketClient webSocketClient; private final WebSocketClient webSocketClient;
...@@ -77,6 +113,13 @@ public class WebSocketClient { ...@@ -77,6 +113,13 @@ public class WebSocketClient {
@Override @Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
String deviceId = null;
for (String key : webSocketClient.activeSessions.keySet()) {
if (webSocketClient.activeSessions.get(key).getId().equals(session.getId())) {
deviceId = key;
break;
}
}
// This method will be called when the server sends a text message // This method will be called when the server sends a text message
// Deserialize JSON array of objects into an array of Java objects // Deserialize JSON array of objects into an array of Java objects
predictions = objectMapper.readValue(message.getPayload(), EmotionPrediction[].class); predictions = objectMapper.readValue(message.getPayload(), EmotionPrediction[].class);
...@@ -86,22 +129,30 @@ public class WebSocketClient { ...@@ -86,22 +129,30 @@ public class WebSocketClient {
System.out.println("Last emotion prediction: " + lastPrediction); System.out.println("Last emotion prediction: " + lastPrediction);
// Save the last prediction to the database // Save the last prediction to the database
if (lastPrediction.getEmotion() != null && !lastPrediction.getEmotion().isEmpty()) { if (lastPrediction.getEmotion() != null && !lastPrediction.getEmotion().isEmpty() && !lastPrediction.getError()) {
ActivityLogDto activityLogDto = new ActivityLogDto(); ActivityLogDto activityLogDto = new ActivityLogDto();
activityLogDto.setActivityLogType(EMOTION); activityLogDto.setActivityLogType(EMOTION);
activityLogDto.setActivityLogDescription(lastPrediction.getEmotion()); activityLogDto.setActivityLogDescription(lastPrediction.getEmotion());
webSocketClient.activityLogService.saveActivityLog(activityLogDto); webSocketClient.activityLogService.saveActivityLog(activityLogDto);
} }
// Send the last prediction to the client // Send the last prediction to the client using VideoFrameHandler
sendTextMessageToClient(lastPrediction); if (webSocketClient.videoFrameHandler != null && deviceId != null) {
webSocketClient.videoFrameHandler.sendTextMessageToClient(deviceId, lastPrediction);
}
} }
} }
@Override @Override
public void afterConnectionClosed(WebSocketSession session, org.springframework.web.socket.CloseStatus status) { public void afterConnectionClosed(WebSocketSession session, org.springframework.web.socket.CloseStatus status) {
System.out.println("WebSocket connection closed. Status: " + status); for (String key : webSocketClient.activeSessions.keySet()) {
webSocketClient.scheduleReconnection(); if (webSocketClient.activeSessions.get(key).getId().equals(session.getId())) {
webSocketClient.activeSessions.remove(key); // Remove session from the map
log.info("Connection closed with device: {}", key);
break;
}
}
log.info("WebSocket connection closed. Status: {}", status);
} }
} }
} }
...@@ -2,6 +2,7 @@ package com.kaluwa.enterprises.babycarebackendservice.config; ...@@ -2,6 +2,7 @@ package com.kaluwa.enterprises.babycarebackendservice.config;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.kaluwa.enterprises.babycarebackendservice.dao.ActivityLogDao; import com.kaluwa.enterprises.babycarebackendservice.dao.ActivityLogDao;
import com.kaluwa.enterprises.babycarebackendservice.dao.DevicesDao;
import com.kaluwa.enterprises.babycarebackendservice.model.ActivityLog; import com.kaluwa.enterprises.babycarebackendservice.model.ActivityLog;
import com.kaluwa.enterprises.babycarebackendservice.service.ActivityLogService; import com.kaluwa.enterprises.babycarebackendservice.service.ActivityLogService;
import com.kaluwa.enterprises.babycarebackendservice.socketHandlers.EmotionPrediction; import com.kaluwa.enterprises.babycarebackendservice.socketHandlers.EmotionPrediction;
...@@ -24,36 +25,51 @@ import org.springframework.web.socket.handler.BinaryWebSocketHandler; ...@@ -24,36 +25,51 @@ import org.springframework.web.socket.handler.BinaryWebSocketHandler;
import springfox.documentation.spring.web.json.Json; import springfox.documentation.spring.web.json.Json;
import java.io.IOException; import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
import static com.kaluwa.enterprises.babycarebackendservice.constants.Configs.SERVER_WS_PATH_TO_ANDROID;
@Configuration @Configuration
@Slf4j @Slf4j
public class WebSocketConfig implements WebSocketConfigurer { public class WebSocketConfig implements WebSocketConfigurer {
private final ActivityLogService activityLogService; private final ActivityLogService activityLogService;
private final DevicesDao devicesDao;
public WebSocketConfig(ActivityLogService activityLogService) { public WebSocketConfig(ActivityLogService activityLogService, DevicesDao devicesDao) {
this.activityLogService = activityLogService; this.activityLogService = activityLogService;
this.devicesDao = devicesDao;
} }
@Override @Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(new VideoFrameHandler(), "/emotional/video-process").setAllowedOrigins("*"); VideoFrameHandler videoFrameHandler = new VideoFrameHandler(customWebSocketClient());
customWebSocketClient().setVideoFrameHandler(videoFrameHandler);
registry.addHandler(videoFrameHandler, SERVER_WS_PATH_TO_ANDROID);
} }
@Bean @Bean
@Qualifier("customWebsocketClient") @Qualifier("customWebsocketClient")
public WebSocketClient customWebSocketClient() { public WebSocketClient customWebSocketClient() {
return new WebSocketClient(activityLogService); return new WebSocketClient(activityLogService, devicesDao);
} }
@Component @Component
class VideoFrameHandler extends BinaryWebSocketHandler { class VideoFrameHandler extends BinaryWebSocketHandler {
private static WebSocketSession currentSession; private ConcurrentHashMap<String, WebSocketSession> activeSessions = new ConcurrentHashMap<>();
private final WebSocketClient webSocketClient;
@Autowired
public VideoFrameHandler(WebSocketClient webSocketClient) {
this.webSocketClient = webSocketClient;
}
@Override @Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception { public void afterConnectionEstablished(WebSocketSession session) throws Exception {
currentSession = session; // Store the current session String deviceId = getDeviceIdFromSession(session);
log.info("Connection established with client: {}", session); activeSessions.put(deviceId, session); // Store the session in the map
webSocketClient.clientConnectToWebSocket(deviceId);
log.info("Connection established with client for device: {}", deviceId);
super.afterConnectionEstablished(session); super.afterConnectionEstablished(session);
} }
...@@ -63,22 +79,29 @@ public class WebSocketConfig implements WebSocketConfigurer { ...@@ -63,22 +79,29 @@ public class WebSocketConfig implements WebSocketConfigurer {
// Process the binary data as needed // Process the binary data as needed
// Send binary data back to the client // Send binary data back to the client
sendBinaryMessageToClient(binaryData); sendBinaryMessageToClient(session, binaryData);
// Optionally, send a text message // Optionally, send a text message
EmotionPrediction emotionPrediction = new EmotionPrediction(); // Empty object EmotionPrediction emotionPrediction = new EmotionPrediction(); // Empty object
sendTextMessageToClient(emotionPrediction);
String deviceId = getDeviceIdFromSession(session);
sendTextMessageToClient(deviceId, emotionPrediction);
} }
@Override @Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception { public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
if (currentSession == session) { String deviceId = getDeviceIdFromSession(session);
currentSession = null; // Reset session variable activeSessions.remove(deviceId); // Remove session from the map
} // webSocketClient.disconnectWebSocket(deviceId);
log.info("Connection closed with client: {}", session); log.info("Connection closed with client: {}", session);
super.afterConnectionClosed(session, status); super.afterConnectionClosed(session, status);
} }
private String getDeviceIdFromSession(WebSocketSession session) {
String uri = session.getUri().toString();
return uri.substring(uri.lastIndexOf('/') + 1); // Extract device_id from the URI path
}
@Override @Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) { protected void handleTextMessage(WebSocketSession session, TextMessage message) {
super.handleTextMessage(session, message); super.handleTextMessage(session, message);
...@@ -90,28 +113,29 @@ public class WebSocketConfig implements WebSocketConfigurer { ...@@ -90,28 +113,29 @@ public class WebSocketConfig implements WebSocketConfigurer {
} }
// Method to send a binary message back to the client // Method to send a binary message back to the client
public void sendBinaryMessageToClient(byte[] bytes) { public void sendBinaryMessageToClient(WebSocketSession session, byte[] bytes) {
try { try {
if (currentSession != null && currentSession.isOpen()) { if (session.isOpen()) {
currentSession.sendMessage(new BinaryMessage(bytes)); session.sendMessage(new BinaryMessage(bytes));
System.out.println("Sent binary message to client: " + bytes.length); log.info("Sent binary message to client: {}", bytes.length);
} }
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); log.error("Error sending binary message: {}", e.getMessage());
} }
} }
// Method to send a text message back to the client // Method to send a text message back to the client
public static void sendTextMessageToClient(EmotionPrediction emotionPrediction) { public void sendTextMessageToClient(String deviceId, EmotionPrediction emotionPrediction) {
try { try {
if (currentSession != null && currentSession.isOpen()) { WebSocketSession session = activeSessions.get(deviceId);
if (session != null && session.isOpen()) {
ObjectMapper objectMapper = new ObjectMapper(); ObjectMapper objectMapper = new ObjectMapper();
String json = objectMapper.writeValueAsString(emotionPrediction); String json = objectMapper.writeValueAsString(emotionPrediction);
currentSession.sendMessage(new TextMessage(json)); session.sendMessage(new TextMessage(json));
System.out.println("Sent text message to client: " + json); log.info("Sent text message to client: {}", json);
} }
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); log.error("Error sending text message: {}", e.getMessage());
} }
} }
} }
......
package com.kaluwa.enterprises.babycarebackendservice.constants; package com.kaluwa.enterprises.babycarebackendservice.constants;
public class Configs { public class Configs {
public static final String WEBSOCKET_URL = "ws://localhost:8000/ws/emotion"; public static String WEBSOCKET_URL = "ws://localhost:8000/ws/emotion/{device_id}";
public static final String SERVER_WS_PATH_TO_ANDROID = "/emotional/video-process/{device_id}";
public static final String DEVICE_URL_FORMAT = "http://%s/%s";
} }
...@@ -3,5 +3,9 @@ package com.kaluwa.enterprises.babycarebackendservice.constants; ...@@ -3,5 +3,9 @@ package com.kaluwa.enterprises.babycarebackendservice.constants;
public class LogTypes { public class LogTypes {
public static final String EMOTION = "EMOTION"; public static final String EMOTION = "EMOTION";
public static final String FLASH_LIGHT = "FLASH_LIGHT";
public static final String C_SWING = "C_SWING";
public static final String C_MOTION = "C_MOTION";
public static final String C_WET = "C_WET";
} }
...@@ -7,5 +7,6 @@ public class TableNames { ...@@ -7,5 +7,6 @@ public class TableNames {
public final static String DOCUMENT_TABLE = "documents"; public final static String DOCUMENT_TABLE = "documents";
public final static String ACTIVITY_LOG_TABLE = "activity_logs"; public final static String ACTIVITY_LOG_TABLE = "activity_logs";
public final static String CONTACT_INFO_TABLE = "contact_info"; public final static String CONTACT_INFO_TABLE = "contact_info";
public final static String DEVICES_TABLE = "devices";
} }
...@@ -9,4 +9,6 @@ import java.util.List; ...@@ -9,4 +9,6 @@ import java.util.List;
@Repository @Repository
public interface ActivityLogDao extends JpaRepository<ActivityLog, Long> { public interface ActivityLogDao extends JpaRepository<ActivityLog, Long> {
List<ActivityLog> findAllByOrderByActivityLogIdDesc(); List<ActivityLog> findAllByOrderByActivityLogIdDesc();
List<ActivityLog> findTop5ByActivityLogTypeOrderByActivityLogIdDesc(String activityLogType);
} }
\ No newline at end of file
package com.kaluwa.enterprises.babycarebackendservice.dao; package com.kaluwa.enterprises.babycarebackendservice.dao;
import com.kaluwa.enterprises.babycarebackendservice.dto.BabyDto;
import com.kaluwa.enterprises.babycarebackendservice.model.Baby; import com.kaluwa.enterprises.babycarebackendservice.model.Baby;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Optional;
@Repository @Repository
public interface BabyDao extends JpaRepository<Baby, Long> { public interface BabyDao extends JpaRepository<Baby, Long> {
boolean existsByDeviceUidAndBabyIdNot(String deviceUid, Long babyId);
boolean existsByDeviceUid(String deviceUid);
List<Baby> findByUserUserId(Long userId);
Optional<Baby> findByDeviceUid(String deviceId);
} }
package com.kaluwa.enterprises.babycarebackendservice.dao;
import com.kaluwa.enterprises.babycarebackendservice.model.Devices;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.Optional;
public interface DevicesDao extends JpaRepository<Devices, Long> {
boolean existsByDeviceUid(String deviceUid);
Optional<Devices> findByDeviceUid(String deviceUid);
}
\ No newline at end of file
...@@ -26,6 +26,7 @@ public class BabyDto { ...@@ -26,6 +26,7 @@ public class BabyDto {
@NotNull(message = "Baby's gender is required") @NotNull(message = "Baby's gender is required")
@NotEmpty(message = "Baby's gender is required") @NotEmpty(message = "Baby's gender is required")
private String sex; private String sex;
private String deviceUid;
private String status = STATUS_NEW; private String status = STATUS_NEW;
private Boolean isActive; private Boolean isActive;
private Float weight; private Float weight;
...@@ -56,6 +57,7 @@ public class BabyDto { ...@@ -56,6 +57,7 @@ public class BabyDto {
private String uniqKey; private String uniqKey;
private UserDto user; private UserDto user;
private byte[] imageData; private byte[] imageData;
private boolean wet;
@NotNull(message = "Logged user id is required") @NotNull(message = "Logged user id is required")
@NotEmpty(message = "Logged user id is required") @NotEmpty(message = "Logged user id is required")
......
package com.kaluwa.enterprises.babycarebackendservice.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@AllArgsConstructor
@NoArgsConstructor
@Data
public class FlashlightResponseDto {
private String status;
private String message;
}
package com.kaluwa.enterprises.babycarebackendservice.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class SwingRequestDto {
private boolean start;
private String speed; // LOW, MEDIUM, HIGH
}
package com.kaluwa.enterprises.babycarebackendservice.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@AllArgsConstructor
@NoArgsConstructor
@Data
public class SwingResponseDto {
private String status;
}
...@@ -22,6 +22,7 @@ public class Baby { ...@@ -22,6 +22,7 @@ public class Baby {
private String lastName; private String lastName;
private LocalDate dob; private LocalDate dob;
private String sex; private String sex;
private String deviceUid;
private String status; private String status;
private Boolean isActive; private Boolean isActive;
private Float weight; private Float weight;
...@@ -50,6 +51,7 @@ public class Baby { ...@@ -50,6 +51,7 @@ public class Baby {
private String secondaryEmergencyContactNumber; private String secondaryEmergencyContactNumber;
private String notes; private String notes;
private String uniqKey; private String uniqKey;
private boolean wet;
@ManyToOne(fetch = FetchType.LAZY) @ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "userId", referencedColumnName = "userId", nullable = false) @JoinColumn(name = "userId", referencedColumnName = "userId", nullable = false)
private User user; private User user;
......
package com.kaluwa.enterprises.babycarebackendservice.model;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import static com.kaluwa.enterprises.babycarebackendservice.constants.TableNames.DEVICES_TABLE;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table(name = DEVICES_TABLE)
public class Devices {
@Id
@GeneratedValue(strategy= GenerationType.AUTO)
private Long deviceId;
private String deviceUid;
private String camIp;
private String devIp;
}
...@@ -4,11 +4,9 @@ import com.kaluwa.enterprises.babycarebackendservice.dto.ActivityLogDto; ...@@ -4,11 +4,9 @@ import com.kaluwa.enterprises.babycarebackendservice.dto.ActivityLogDto;
import com.kaluwa.enterprises.babycarebackendservice.dto.ResponseDto; import com.kaluwa.enterprises.babycarebackendservice.dto.ResponseDto;
import com.kaluwa.enterprises.babycarebackendservice.service.ActivityLogService; import com.kaluwa.enterprises.babycarebackendservice.service.ActivityLogService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List; import java.util.List;
...@@ -24,9 +22,11 @@ public class ActivityLogController { ...@@ -24,9 +22,11 @@ public class ActivityLogController {
} }
@GetMapping @GetMapping
public ResponseEntity<List<ActivityLogDto>> getAllActivityLogs() { public ResponseEntity<List<ActivityLogDto>> getAllActivityLogs(
@RequestParam(value = "activityLogType", required = false) String activityLogType
) {
log.info("Inside activity log controller getAllActivityLogs method"); log.info("Inside activity log controller getAllActivityLogs method");
return activityLogService.getAllActivityLogs(); return activityLogService.getAllActivityLogs(activityLogType);
} }
@DeleteMapping @DeleteMapping
...@@ -35,4 +35,10 @@ public class ActivityLogController { ...@@ -35,4 +35,10 @@ public class ActivityLogController {
return activityLogService.clearNotifications(); return activityLogService.clearNotifications();
} }
@PostMapping("/add")
public ResponseEntity<ActivityLogDto> saveActivityLog(@RequestBody ActivityLogDto activityLogDto) {
log.info("Inside activity log controller saveActivityLog method");
return new ResponseEntity<>(activityLogService.saveActivityLog(activityLogDto), HttpStatus.CREATED);
}
} }
...@@ -28,9 +28,11 @@ public class BabyController { ...@@ -28,9 +28,11 @@ public class BabyController {
} }
@GetMapping() @GetMapping()
public ResponseEntity<List<BabyDto>> getAllbabies() { public ResponseEntity<List<BabyDto>> getAllbabies(
@RequestParam(value = "userId", required = false) Long userId
) {
log.info("Inside baby controller getAllbabies method"); log.info("Inside baby controller getAllbabies method");
return ResponseEntity.ok(babyService.getAllBabies()); return ResponseEntity.ok(babyService.getAllBabies(userId));
} }
@GetMapping("/{babyId}") @GetMapping("/{babyId}")
...@@ -50,4 +52,10 @@ public class BabyController { ...@@ -50,4 +52,10 @@ public class BabyController {
log.info("Inside baby controller deleteBaby method"); log.info("Inside baby controller deleteBaby method");
return ResponseEntity.ok(babyService.deleteBaby(babyId)); return ResponseEntity.ok(babyService.deleteBaby(babyId));
} }
@GetMapping("/byDeviceId/{deviceId}")
public ResponseEntity<BabyDto> getBabyByDeviceId(@PathVariable String deviceId) {
log.info("Inside baby controller getBabyByDeviceId method");
return ResponseEntity.ok(babyService.getBabyByDeviceId(deviceId));
}
} }
package com.kaluwa.enterprises.babycarebackendservice.rest;
import com.kaluwa.enterprises.babycarebackendservice.dto.ResponseDto;
import com.kaluwa.enterprises.babycarebackendservice.dto.SwingRequestDto;
import com.kaluwa.enterprises.babycarebackendservice.service.DeviceService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/device")
@Slf4j
public class DeviceController {
private final DeviceService deviceService;
public DeviceController(DeviceService deviceService) {
this.deviceService = deviceService;
}
// flash light control
@GetMapping("/flashlight/{deviceUid}/{status}")
public ResponseEntity<ResponseDto> flashlight(@PathVariable String deviceUid, @PathVariable String status) {
log.info("Inside DeviceController: flashlight method");
return deviceService.flashlight(deviceUid, status);
}
// c swing control
@PostMapping("/swing/{deviceUid}")
public ResponseEntity<ResponseDto> swing(@PathVariable String deviceUid, @RequestBody SwingRequestDto swingRequest) {
log.info("Inside DeviceController: swing method");
return deviceService.swing(deviceUid, swingRequest);
}
}
...@@ -10,7 +10,7 @@ public interface ActivityLogService { ...@@ -10,7 +10,7 @@ public interface ActivityLogService {
ActivityLogDto saveActivityLog(ActivityLogDto activityLogDto); ActivityLogDto saveActivityLog(ActivityLogDto activityLogDto);
ResponseEntity<List<ActivityLogDto>> getAllActivityLogs(); ResponseEntity<List<ActivityLogDto>> getAllActivityLogs(String activityLogType);
ResponseEntity<ResponseDto> clearNotifications(); ResponseEntity<ResponseDto> clearNotifications();
} }
...@@ -8,11 +8,13 @@ import java.util.List; ...@@ -8,11 +8,13 @@ import java.util.List;
public interface BabyService { public interface BabyService {
BabyDto createBaby(BabyDto babyDto); BabyDto createBaby(BabyDto babyDto);
List<BabyDto> getAllBabies(); List<BabyDto> getAllBabies(Long userId);
BabyDto getBabyById(Long babyId); BabyDto getBabyById(Long babyId);
BabyDto updateBaby(Long babyId, BabyDto babyDto); BabyDto updateBaby(Long babyId, BabyDto babyDto);
ResponseDto deleteBaby(Long babyId); ResponseDto deleteBaby(Long babyId);
BabyDto getBabyByDeviceId(String deviceId);
} }
package com.kaluwa.enterprises.babycarebackendservice.service;
import com.kaluwa.enterprises.babycarebackendservice.dto.ResponseDto;
import com.kaluwa.enterprises.babycarebackendservice.dto.SwingRequestDto;
import org.springframework.http.ResponseEntity;
public interface DeviceService {
ResponseEntity<ResponseDto> flashlight(String deviceUid, String status);
ResponseEntity<ResponseDto> swing(String deviceUid, SwingRequestDto swingRequest);
}
...@@ -39,10 +39,14 @@ public class ActivityLogServiceImpl implements ActivityLogService { ...@@ -39,10 +39,14 @@ public class ActivityLogServiceImpl implements ActivityLogService {
} }
@Override @Override
public ResponseEntity<List<ActivityLogDto>> getAllActivityLogs() { public ResponseEntity<List<ActivityLogDto>> getAllActivityLogs(String activityLogType) {
log.info("Inside getAllActivityLogs method in ActivityLogServiceImpl"); log.info("Inside getAllActivityLogs method in ActivityLogServiceImpl");
try { try {
if (activityLogType != null && !activityLogType.isEmpty()) {
return ResponseEntity.ok(activityLogMapper.listToDto(activityLogDao.findTop5ByActivityLogTypeOrderByActivityLogIdDesc(activityLogType)));
} else {
return ResponseEntity.ok(activityLogMapper.listToDto(activityLogDao.findAllByOrderByActivityLogIdDesc())); return ResponseEntity.ok(activityLogMapper.listToDto(activityLogDao.findAllByOrderByActivityLogIdDesc()));
}
} catch (Exception e) { } catch (Exception e) {
log.error("Error occurred while fetching activity logs: {}", e.getMessage()); log.error("Error occurred while fetching activity logs: {}", e.getMessage());
e.printStackTrace(); e.printStackTrace();
......
package com.kaluwa.enterprises.babycarebackendservice.service.impl; package com.kaluwa.enterprises.babycarebackendservice.service.impl;
import com.kaluwa.enterprises.babycarebackendservice.dao.BabyDao; import com.kaluwa.enterprises.babycarebackendservice.dao.BabyDao;
import com.kaluwa.enterprises.babycarebackendservice.dao.DevicesDao;
import com.kaluwa.enterprises.babycarebackendservice.dao.DocumentDao; import com.kaluwa.enterprises.babycarebackendservice.dao.DocumentDao;
import com.kaluwa.enterprises.babycarebackendservice.dto.BabyDto; import com.kaluwa.enterprises.babycarebackendservice.dto.BabyDto;
import com.kaluwa.enterprises.babycarebackendservice.dto.ResponseDto; import com.kaluwa.enterprises.babycarebackendservice.dto.ResponseDto;
...@@ -11,13 +12,8 @@ import com.kaluwa.enterprises.babycarebackendservice.model.Document; ...@@ -11,13 +12,8 @@ import com.kaluwa.enterprises.babycarebackendservice.model.Document;
import com.kaluwa.enterprises.babycarebackendservice.service.BabyService; import com.kaluwa.enterprises.babycarebackendservice.service.BabyService;
import com.kaluwa.enterprises.babycarebackendservice.service.DocumentService; import com.kaluwa.enterprises.babycarebackendservice.service.DocumentService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
...@@ -32,12 +28,14 @@ public class BabyServiceImpl implements BabyService { ...@@ -32,12 +28,14 @@ public class BabyServiceImpl implements BabyService {
private final BabyMapper babyMapper; private final BabyMapper babyMapper;
private final DocumentDao documentDao; private final DocumentDao documentDao;
private final DocumentService documentService; private final DocumentService documentService;
private final DevicesDao devicesDao;
public BabyServiceImpl(BabyDao babyDao, BabyMapper babyMapper, DocumentDao documentDao, DocumentService documentService) { public BabyServiceImpl(BabyDao babyDao, BabyMapper babyMapper, DocumentDao documentDao, DocumentService documentService, DevicesDao devicesDao) {
this.babyDao = babyDao; this.babyDao = babyDao;
this.babyMapper = babyMapper; this.babyMapper = babyMapper;
this.documentDao = documentDao; this.documentDao = documentDao;
this.documentService = documentService; this.documentService = documentService;
this.devicesDao = devicesDao;
} }
@Override @Override
...@@ -45,6 +43,27 @@ public class BabyServiceImpl implements BabyService { ...@@ -45,6 +43,27 @@ public class BabyServiceImpl implements BabyService {
log.info("Inside baby service createBaby method"); log.info("Inside baby service createBaby method");
try { try {
babyDto.setUniqKey(uniqKeyGenerator()); babyDto.setUniqKey(uniqKeyGenerator());
if (!babyDto.getDeviceUid().isEmpty() && !devicesDao.existsByDeviceUid(babyDto.getDeviceUid())) {
throw new BadRequestAlertException("Device is not registered in the system by uid " + babyDto.getDeviceUid(), "baby", "baby.error");
}
if (!babyDto.getDeviceUid().isEmpty() && devicesDao.existsByDeviceUid(babyDto.getDeviceUid())) {
if (babyDao.existsByDeviceUid(babyDto.getDeviceUid())) {
throw new BadRequestAlertException("Device is already assigned to another baby", "baby", "baby.error");
}
}
if (babyDto.getFirstName().isEmpty()) {
throw new BadRequestAlertException("Baby's first name is required", "baby", "baby.error");
}
if (babyDto.getDob() == null) {
throw new BadRequestAlertException("Baby's date of birth is required", "baby", "baby.error");
}
if (babyDto.getSex().isEmpty()) {
throw new BadRequestAlertException("Baby's gender is required", "baby", "baby.error");
}
if (babyDto.getUserId() == null) {
throw new BadRequestAlertException("User id is required", "baby", "baby.error");
}
babyDto.setWet(false);
return babyMapper.toDto(babyDao.save(babyMapper.toEntity(babyDto))); return babyMapper.toDto(babyDao.save(babyMapper.toEntity(babyDto)));
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
...@@ -53,11 +72,15 @@ public class BabyServiceImpl implements BabyService { ...@@ -53,11 +72,15 @@ public class BabyServiceImpl implements BabyService {
} }
@Override @Override
public List<BabyDto> getAllBabies() { public List<BabyDto> getAllBabies(Long userId) {
log.info("Inside baby service getAllBabies method"); log.info("Inside baby service getAllBabies method");
try { try {
List<BabyDto> babyList = babyMapper.toDtoList(babyDao.findAll()); List<BabyDto> babyList;
if (userId != null) {
babyList = babyMapper.toDtoList(babyDao.findByUserUserId(userId));
} else {
babyList = babyMapper.toDtoList(babyDao.findAll());
babyList.forEach(babyDto -> { babyList.forEach(babyDto -> {
Optional<Document> documentOp = documentDao.findByTableNameAndUniqKeyAndDocumentType(BABY_TABLE, babyDto.getUniqKey(), IMAGE); Optional<Document> documentOp = documentDao.findByTableNameAndUniqKeyAndDocumentType(BABY_TABLE, babyDto.getUniqKey(), IMAGE);
documentOp.ifPresent(document -> { documentOp.ifPresent(document -> {
...@@ -67,7 +90,7 @@ public class BabyServiceImpl implements BabyService { ...@@ -67,7 +90,7 @@ public class BabyServiceImpl implements BabyService {
} }
}); });
}); });
}
return babyList; return babyList;
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
...@@ -98,13 +121,34 @@ public class BabyServiceImpl implements BabyService { ...@@ -98,13 +121,34 @@ public class BabyServiceImpl implements BabyService {
Optional<Baby> babyOp = babyDao.findById(babyId); Optional<Baby> babyOp = babyDao.findById(babyId);
if (babyDto.getBabyId() == null) { if (babyDto.getBabyId() == null) {
throw new BadRequestAlertException("Baby id is required", "baby", "baby.error"); throw new BadRequestAlertException("Baby id is required", "baby", "baby.error");
} else if (!babyId.equals(babyDto.getBabyId())) { }
if (!babyId.equals(babyDto.getBabyId())) {
throw new BadRequestAlertException("Baby id mismatch", "baby", "baby.error"); throw new BadRequestAlertException("Baby id mismatch", "baby", "baby.error");
} else if (babyOp.isEmpty()) { }
if (babyOp.isEmpty()) {
throw new BadRequestAlertException("Baby not found", "baby", "baby.error"); throw new BadRequestAlertException("Baby not found", "baby", "baby.error");
} else {
return babyMapper.toDto(babyDao.save(babyMapper.toEntity(babyDto)));
} }
if (!babyDto.getDeviceUid().isEmpty() && !devicesDao.existsByDeviceUid(babyDto.getDeviceUid())) {
throw new BadRequestAlertException("Device is not registered in the system by uid " + babyDto.getDeviceUid(), "baby", "baby.error");
}
if (!babyDto.getDeviceUid().isEmpty() && devicesDao.existsByDeviceUid(babyDto.getDeviceUid())) {
if (babyDao.existsByDeviceUidAndBabyIdNot(babyDto.getDeviceUid(), babyId)) {
throw new BadRequestAlertException("Device is already assigned to another baby", "baby", "baby.error");
}
}
if (babyDto.getFirstName().isEmpty()) {
throw new BadRequestAlertException("Baby's first name is required", "baby", "baby.error");
}
if (babyDto.getDob() == null) {
throw new BadRequestAlertException("Baby's date of birth is required", "baby", "baby.error");
}
if (babyDto.getSex().isEmpty()) {
throw new BadRequestAlertException("Baby's gender is required", "baby", "baby.error");
}
if (babyDto.getUserId() == null) {
throw new BadRequestAlertException("User id is required", "baby", "baby.error");
}
return babyMapper.toDto(babyDao.save(babyMapper.toEntity(babyDto)));
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
throw new BadRequestAlertException(e.getMessage(), "baby", "baby.error"); throw new BadRequestAlertException(e.getMessage(), "baby", "baby.error");
...@@ -132,4 +176,20 @@ public class BabyServiceImpl implements BabyService { ...@@ -132,4 +176,20 @@ public class BabyServiceImpl implements BabyService {
throw new BadRequestAlertException(e.getMessage(), "baby", "baby.error"); throw new BadRequestAlertException(e.getMessage(), "baby", "baby.error");
} }
} }
@Override
public BabyDto getBabyByDeviceId(String deviceId) {
log.info("Inside baby service getBabyByDeviceId method");
try {
Optional<Baby> babyOp = babyDao.findByDeviceUid(deviceId);
if (babyOp.isEmpty()) {
throw new BadRequestAlertException("Baby not found", "baby", "baby.error");
} else {
return babyMapper.toDto(babyOp.get());
}
} catch (Exception e) {
e.printStackTrace();
throw new BadRequestAlertException(e.getMessage(), "baby", "baby.error");
}
}
} }
package com.kaluwa.enterprises.babycarebackendservice.service.impl;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.kaluwa.enterprises.babycarebackendservice.dao.DevicesDao;
import com.kaluwa.enterprises.babycarebackendservice.dto.*;
import com.kaluwa.enterprises.babycarebackendservice.error.BadRequestAlertException;
import com.kaluwa.enterprises.babycarebackendservice.model.Devices;
import com.kaluwa.enterprises.babycarebackendservice.service.ActivityLogService;
import com.kaluwa.enterprises.babycarebackendservice.service.DeviceService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import java.util.Optional;
import static com.kaluwa.enterprises.babycarebackendservice.constants.Configs.DEVICE_URL_FORMAT;
import static com.kaluwa.enterprises.babycarebackendservice.constants.LogTypes.C_SWING;
import static com.kaluwa.enterprises.babycarebackendservice.constants.LogTypes.FLASH_LIGHT;
@Service
@Slf4j
public class DeviceServiceImpl implements DeviceService {
private final DevicesDao devicesDao;
private final ActivityLogService activityLogService;
private final RestTemplate restTemplate = new RestTemplate();
public DeviceServiceImpl(DevicesDao devicesDao, ActivityLogService activityLogService) {
this.devicesDao = devicesDao;
this.activityLogService = activityLogService;
}
@Override
public ResponseEntity<ResponseDto> flashlight(String deviceUid, String status) {
log.info("Inside DeviceService: flashlight method");
try {
Optional<Devices> devices = devicesDao.findByDeviceUid(deviceUid);
if (devices.isEmpty()) {
throw new BadRequestAlertException("Device is not registered in the system by deviceUid: " + deviceUid, "DeviceService", "flashlight");
}
// status only accepts ON or OFF
if (!status.equalsIgnoreCase("ON") && !status.equalsIgnoreCase("OFF")) {
throw new BadRequestAlertException("Invalid status: " + status, "DeviceService", "flashlight");
}
String deviceCamIp = devices.get().getCamIp();
String url = String.format(DEVICE_URL_FORMAT+"/flashlight/%s", deviceCamIp, deviceUid, status);
// Making the HTTP get for entity call
ResponseEntity<FlashlightResponseDto> response = restTemplate.getForEntity(url, FlashlightResponseDto.class);
if (response.getStatusCode() == HttpStatus.OK) {
ActivityLogDto activityLogDto = new ActivityLogDto();
activityLogDto.setActivityLogType(FLASH_LIGHT);
activityLogDto.setActivityLogDescription(response.getBody().getMessage());
activityLogService.saveActivityLog(activityLogDto);
return ResponseEntity.ok(new ResponseDto(Long.parseLong("200"), response.getBody().getMessage()));
} else {
throw new BadRequestAlertException("No response from device flashlight endpoint", "DeviceService", "flashlight");
}
} catch (Exception e) {
log.error("Error in DeviceService: flashlight method", e);
e.printStackTrace();
throw new BadRequestAlertException(e.getMessage(), "DeviceService", "flashlight");
}
}
@Override
public ResponseEntity<ResponseDto> swing(String deviceUid, SwingRequestDto swingRequest) {
log.info("Inside DeviceService: swing method");
try {
Optional<Devices> devices = devicesDao.findByDeviceUid(deviceUid);
if (devices.isEmpty()) {
throw new BadRequestAlertException("Device is not registered in the system by deviceUid: " + deviceUid, "DeviceService", "flashlight");
}
// check if swing speed is between LOW, MEDIUM, HIGH
if (!swingRequest.getSpeed().equalsIgnoreCase("LOW") && !swingRequest.getSpeed().equalsIgnoreCase("MEDIUM") && !swingRequest.getSpeed().equalsIgnoreCase("HIGH")) {
throw new BadRequestAlertException("Invalid swing speed: " + swingRequest.getSpeed(), "DeviceService", "swing");
}
swingRequest.setSpeed(swingRequest.getSpeed().toLowerCase());
String devIp = devices.get().getDevIp();
String url = String.format(DEVICE_URL_FORMAT+"/oscillate", devIp, deviceUid);
// Convert swingRequest to JSON and set up headers
ObjectMapper objectMapper = new ObjectMapper();
String jsonRequest = objectMapper.writeValueAsString(swingRequest);
// Create HttpHeaders
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
// Create HttpEntity with the request body and headers
HttpEntity<String> requestEntity = new HttpEntity<>(jsonRequest, headers);
// Making the HTTP post call
ResponseEntity<SwingResponseDto> response = restTemplate.postForEntity(url, requestEntity, SwingResponseDto.class);
// Check if the response is not null and has a body
if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
ActivityLogDto activityLogDto = new ActivityLogDto();
activityLogDto.setActivityLogType(C_SWING);
activityLogDto.setActivityLogDescription(response.getBody().getStatus());
activityLogService.saveActivityLog(activityLogDto);
return ResponseEntity.ok(new ResponseDto(Long.parseLong("200"), response.getBody().getStatus()));
} else if (response.getStatusCode() == HttpStatus.OK) {
// Handle the case where the response is OK but the body is null
throw new BadRequestAlertException("Received empty response from device swing endpoint", "DeviceService", "swing");
} else {
// Handle unexpected status codes
throw new BadRequestAlertException("Unexpected response from device swing endpoint: " + response.getStatusCode(), "DeviceService", "swing");
}
} catch (Exception e) {
log.error("Error in DeviceService: swing method", e);
e.printStackTrace();
throw new BadRequestAlertException(e.getMessage(), "DeviceService", "swing");
}
}
}
...@@ -10,4 +10,5 @@ import lombok.NoArgsConstructor; ...@@ -10,4 +10,5 @@ import lombok.NoArgsConstructor;
public class EmotionPrediction { public class EmotionPrediction {
private String emotion; private String emotion;
private BoundingBox bounding_box; private BoundingBox bounding_box;
private Boolean error;
} }
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment