22
33
44import devkor .com .teamcback .domain .ble .dto .request .UpdateBLEReq ;
5+ import devkor .com .teamcback .domain .ble .dto .response .BLETimePatternRes ;
56import devkor .com .teamcback .domain .ble .dto .response .GetBLERes ;
67import devkor .com .teamcback .domain .ble .dto .response .UpdateBLERes ;
78import devkor .com .teamcback .domain .ble .entity .BLEData ;
@@ -32,10 +33,21 @@ public class BLEService {
3233 private final BLEDataRepository bleDataRepository ;
3334 private final PlaceRepository placeRepository ;
3435
36+ // 평균 구해올 시간대 라벨
37+ private static final int [] TIME_SLOTS = {7 , 10 , 13 , 16 , 19 , 22 };
38+ //요일 라벨 (1=월요일, 7=일요일)
39+ private static final int [] DAY_OF_WEEKS = {1 , 2 , 3 , 4 , 5 , 6 , 7 };
40+
3541 @ Transactional
3642 public UpdateBLERes updateBLE (UpdateBLEReq updateBLEReq ) {
3743 BLEDevice bleDevice = bledeviceRepository .findByDeviceName (updateBLEReq .getDeviceName ());
38- BLEstatus status = getBlEstatus (updateBLEReq , bleDevice );
44+ int capacity = bleDevice .getCapacity ();
45+ int people = getBlEPeople (updateBLEReq .getLastCount (), bleDevice );
46+ double final_ratio = (double ) people / capacity ;
47+ BLEstatus status ;
48+ if (final_ratio < 0.3 ) status = BLEstatus .VACANT ;
49+ else if (final_ratio < 0.7 ) status = BLEstatus .AVAILABLE ;
50+ else status = BLEstatus .CROWDED ;
3951
4052 BLEData bleData = new BLEData ();
4153 bleData .setDevice (bleDevice );
@@ -47,21 +59,16 @@ public UpdateBLERes updateBLE(UpdateBLEReq updateBLEReq) {
4759 return new UpdateBLERes (bleData );
4860 }
4961
50- private BLEstatus getBlEstatus ( UpdateBLEReq updateBLEReq , BLEDevice bleDevice ) {
62+ private int getBlEPeople ( int lastCount , BLEDevice bleDevice ) {
5163 if (bleDevice == null ) throw new GlobalException (ResultCode .NOT_FOUND_DEVICE_NAME );
52- int capacity = bleDevice .getCapacity ();
53- int count = updateBLEReq .getLastCount ();
54- int ratio = bleDevice .getRatio ();
55- int defaultCount = bleDevice .getDefaultCount ();
56-
57- double people_count = (double ) (count - defaultCount ) / ratio ;
58- double final_ratio = people_count / capacity ;
64+ double ratio = bleDevice .getRatio ();
65+ double defaultCount = bleDevice .getDefaultCount ();
66+ return calculate_people (lastCount , ratio , defaultCount );
67+ }
5968
60- BLEstatus status ;
61- if (final_ratio < 0.3 ) status = BLEstatus .VACANT ;
62- else if (final_ratio < 0.7 ) status = BLEstatus .AVAILABLE ;
63- else status = BLEstatus .CROWDED ;
64- return status ;
69+ //count, ratio, defaultcount로 예측 인원 계산(int)
70+ private int calculate_people (int count , double ratio , double defaultCount ) {
71+ return (int ) Math .round (count * ratio + defaultCount );
6572 }
6673
6774 @ Transactional (readOnly = true )
@@ -76,7 +83,83 @@ public GetBLERes getBLE(Long placeId) {
7683 status = BLEstatus .FAILURE ;
7784 }
7885 else status = latest .getLastStatus ();
79- return new GetBLERes (device , latest , status );
86+ // 사람 수를 예측 후 10의 배수로 리턴
87+ int people = getBlEPeople (latest .getLastCount (), device );
88+ people = (int ) Math .round (people / 10.0 ) * 10 ;
89+ return new GetBLERes (device , latest , status , people );
90+ }
91+
92+ @ Transactional (readOnly = true )
93+ public BLETimePatternRes getBLETimePattern (Long placeId ) {
94+ //place, device 조회
95+ Place place = placeRepository .findById (placeId ).orElseThrow (() -> new GlobalException (NOT_FOUND_PLACE ));
96+ BLEDevice device = bledeviceRepository .findByPlace (place );
97+ if (device == null ) throw new GlobalException (ResultCode .NOT_FOUND_DEVICE );
98+ double ratio = device .getRatio ();
99+ double defaultCount = device .getDefaultCount ();
100+ //기간 설정: 1달
101+ LocalDateTime end = LocalDateTime .now ();
102+ LocalDateTime start = end .minusMonths (1 );
103+ //1달치 bledata 가져오기
104+ List <BLEData > dataList = bleDataRepository .findAllByDeviceAndLastTimeBetweenOrderByLastTimeAsc (device , start , end );
105+ //계산 위한 배열 준비
106+ // dayIndex: 0~6 (월~일), timeIndex: 0~6 (7,10,13,16,19,22)
107+ long [][] sum = new long [DAY_OF_WEEKS .length ][TIME_SLOTS .length ];
108+ long [][] count = new long [DAY_OF_WEEKS .length ][TIME_SLOTS .length ];
109+ // 시간대를 "가장 가까운 target 시간"으로 매핑하기 위해 분 단위로 처리
110+ int [] slotMinutes = new int [TIME_SLOTS .length ];
111+ for (int i = 0 ; i < TIME_SLOTS .length ; i ++) {
112+ slotMinutes [i ] = TIME_SLOTS [i ] * 60 ;
113+ }
114+ // BLEData를 요일/시간대 bucket에 넣어서 합/개수 집계
115+ for (BLEData d : dataList ) {
116+ if (d .getLastTime () == null ) continue ;
117+ if (d .getLastCount () == null ) continue ;
118+ LocalDateTime t = d .getLastTime ();
119+ // 요일 index (0~6) : DayOfWeek.getValue() 는 1~7(MON~SUN)
120+ int dayValue = t .getDayOfWeek ().getValue (); // 1~7
121+ int dayIndex = dayValue - 1 ;
122+ // 분 단위 시간 (0~1439)
123+ int minuteOfDay = t .getHour () * 60 + t .getMinute ();
124+ // 이 데이터가 들어갈 slot 찾기 (전후 30분 이내만 허용)
125+ int bestSlotIndex = -1 ;
126+ int bestDiff = Integer .MAX_VALUE ;
127+
128+ for (int i = 0 ; i < slotMinutes .length ; i ++) {
129+ int diff = Math .abs (minuteOfDay - slotMinutes [i ]);
130+
131+ // 전후 30분(= 60분 window) 안에 들어오는 경우만 고려
132+ if (diff <= 30 && diff < bestDiff ) {
133+ bestDiff = diff ;
134+ bestSlotIndex = i ;
135+ }
136+ }
137+ // 어떤 slot에도 해당되지 않으면 이 데이터는 버림
138+ if (bestSlotIndex == -1 ) {
139+ continue ;
140+ }
141+ // 합/개수 축적
142+ sum [dayIndex ][bestSlotIndex ] += calculate_people (d .getLastCount (), ratio , defaultCount );
143+ count [dayIndex ][bestSlotIndex ] += 1 ;
144+ }
145+ // 평균 계산 (반올림 후 int)
146+ int [][] averages = new int [DAY_OF_WEEKS .length ][TIME_SLOTS .length ];
147+ for (int di = 0 ; di < DAY_OF_WEEKS .length ; di ++) {
148+ for (int ti = 0 ; ti < TIME_SLOTS .length ; ti ++) {
149+ if (count [di ][ti ] == 0L ) {
150+ averages [di ][ti ] = 0 ; // 데이터 없으면 0
151+ } else {
152+ double avg = (double ) sum [di ][ti ] / (double ) count [di ][ti ];
153+ averages [di ][ti ] = (int ) Math .round (avg );
154+ }
155+ }
156+ }
157+ return new BLETimePatternRes (
158+ placeId ,
159+ TIME_SLOTS ,
160+ DAY_OF_WEEKS ,
161+ averages
162+ );
80163 }
81164
82165}
0 commit comments