From bbc27a64fbd27df1e3a32288e97bc4d2b7105da3 Mon Sep 17 00:00:00 2001 From: minnnseokk Date: Tue, 29 Apr 2025 10:25:52 +0900 Subject: [PATCH 01/15] =?UTF-8?q?fix=20|=20sprint1=20|=20FRB-107=20|=20?= =?UTF-8?q?=EC=8B=9C=EB=AE=AC=EB=A0=88=EC=9D=B4=ED=84=B0=20=EC=9D=B8?= =?UTF-8?q?=ED=84=B0=ED=8E=98=EC=9D=B4=EC=8A=A4=20=EC=9E=84=ED=8F=AC?= =?UTF-8?q?=ED=8A=B8=20=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95=20|=20?= =?UTF-8?q?=EC=A0=95=EB=AF=BC=EC=84=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- service/simulation/CurrentSimulator.py | 4 ++-- service/simulation/ExampleSimulator.py | 2 +- service/simulation/HumiditySimulator.py | 4 ++-- service/simulation/HumidityTempSimulator.py | 4 ++-- service/simulation/SimulatorInterface.py | 6 ------ service/simulation/TempSimulator.py | 4 ++-- service/simulation/VibrationSimulator.py | 4 ++-- service/simulation/factory.py | 2 +- 8 files changed, 12 insertions(+), 18 deletions(-) delete mode 100644 service/simulation/SimulatorInterface.py diff --git a/service/simulation/CurrentSimulator.py b/service/simulation/CurrentSimulator.py index 7e8027b..6510552 100644 --- a/service/simulation/CurrentSimulator.py +++ b/service/simulation/CurrentSimulator.py @@ -1,6 +1,6 @@ -from .SimulatorInterface import SimulatorInterface +from .SimulatorInterface2 import SimulatorInterface2 from simulate_type.simulate_list import generate_current_data -class CurrentSimulator(SimulatorInterface): +class CurrentSimulator(SimulatorInterface2): def generate_data(self, idx: int) -> dict: return generate_current_data(idx) \ No newline at end of file diff --git a/service/simulation/ExampleSimulator.py b/service/simulation/ExampleSimulator.py index b8fe08c..754817e 100644 --- a/service/simulation/ExampleSimulator.py +++ b/service/simulation/ExampleSimulator.py @@ -1,4 +1,4 @@ -from .SimulationInterface2 import SimulatorInterface2 +from .SimulatorInterface2 import SimulatorInterface2 from simulate_type.simulate_list import generate_temp_data import random diff --git a/service/simulation/HumiditySimulator.py b/service/simulation/HumiditySimulator.py index 8e23260..8a5a84f 100644 --- a/service/simulation/HumiditySimulator.py +++ b/service/simulation/HumiditySimulator.py @@ -1,6 +1,6 @@ -from .SimulatorInterface import SimulatorInterface +from .SimulatorInterface2 import SimulatorInterface2 from simulate_type.simulate_list import generate_humidity_data -class HumiditySimulator(SimulatorInterface): +class HumiditySimulator(SimulatorInterface2): def generate_data(self, idx: int) -> dict: return generate_humidity_data(idx) \ No newline at end of file diff --git a/service/simulation/HumidityTempSimulator.py b/service/simulation/HumidityTempSimulator.py index e1fb2a4..8199580 100644 --- a/service/simulation/HumidityTempSimulator.py +++ b/service/simulation/HumidityTempSimulator.py @@ -1,7 +1,7 @@ -from .SimulatorInterface import SimulatorInterface +from .SimulatorInterface2 import SimulatorInterface2 from simulate_type.simulate_list import generate_humidity_temp_data -class HumidityTempSimulator(SimulatorInterface): +class HumidityTempSimulator(SimulatorInterface2): def generate_data(self, idx: int) -> dict: """ Generate a single data entry containing both humidity and temperature. diff --git a/service/simulation/SimulatorInterface.py b/service/simulation/SimulatorInterface.py deleted file mode 100644 index 9639cbc..0000000 --- a/service/simulation/SimulatorInterface.py +++ /dev/null @@ -1,6 +0,0 @@ -from abc import ABC, abstractmethod - -class SimulatorInterface(ABC): - @abstractmethod - def generate_data(self, idx: int) -> dict: - pass \ No newline at end of file diff --git a/service/simulation/TempSimulator.py b/service/simulation/TempSimulator.py index a33ebe6..cb74d57 100644 --- a/service/simulation/TempSimulator.py +++ b/service/simulation/TempSimulator.py @@ -1,6 +1,6 @@ -from .SimulatorInterface import SimulatorInterface +from .SimulatorInterface2 import SimulatorInterface2 from simulate_type.simulate_list import generate_temp_data -class TempSimulator(SimulatorInterface): +class TempSimulator(SimulatorInterface2): def generate_data(self, idx: int) -> dict: return generate_temp_data(idx) \ No newline at end of file diff --git a/service/simulation/VibrationSimulator.py b/service/simulation/VibrationSimulator.py index 608cdea..a587b79 100644 --- a/service/simulation/VibrationSimulator.py +++ b/service/simulation/VibrationSimulator.py @@ -1,6 +1,6 @@ -from .SimulatorInterface import SimulatorInterface +from .SimulatorInterface2 import SimulatorInterface2 from simulate_type.simulate_list import generate_vibration_data -class VibrationSimulator(SimulatorInterface): +class VibrationSimulator(SimulatorInterface2): def generate_data(self, idx: int) -> dict: return generate_vibration_data(idx) \ No newline at end of file diff --git a/service/simulation/factory.py b/service/simulation/factory.py index 2237459..bd1005a 100644 --- a/service/simulation/factory.py +++ b/service/simulation/factory.py @@ -7,7 +7,7 @@ from mqtt_util.publish import AwsMQTT from typing import List # from .SimulatorInterface import SimulatorInterface -from .SimulationInterface2 import SimulatorInterface2 +from .SimulatorInterface2 import SimulatorInterface2 def get_simulator(simulator_type: str, idx: int, space_id: str, manufacture_id: str, interval: int = 5, msg_count: int = 10, conn:AwsMQTT=None)-> List[SimulatorInterface2]: simulator_entity_list = [] From 849028156eb22a466a197ac398d6cac507202b1e Mon Sep 17 00:00:00 2001 From: minnnseokk Date: Tue, 29 Apr 2025 15:41:14 +0900 Subject: [PATCH 02/15] =?UTF-8?q?=20feat=20|=20sprint1=20|=20FRB-101=20|?= =?UTF-8?q?=20=EC=8B=9C=EB=AE=AC=EB=A0=88=EC=9D=B4=ED=84=B0=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EC=B6=94=EA=B0=80,=20=EB=8D=B0=EC=9D=B4=ED=84=B0?= =?UTF-8?q?=20=ED=98=95=EC=8B=9D=20=EC=B5=9C=EC=A2=85=20=EC=A0=95=EC=9D=98?= =?UTF-8?q?=20|=20=EC=A0=95=EB=AF=BC=EC=84=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- service/simulation/CurrentSimulator.py | 46 ++++++++++++++++++++++- service/simulation/DustSimulator.py | 47 +++++++++++++++++++++++ service/simulation/ExampleSimulator.py | 10 +++-- service/simulation/VibrationSimulator.py | 48 +++++++++++++++++++++++- service/simulation/factory.py | 14 ++++--- service/simulation/simulateTest.py | 2 +- 6 files changed, 152 insertions(+), 15 deletions(-) create mode 100644 service/simulation/DustSimulator.py diff --git a/service/simulation/CurrentSimulator.py b/service/simulation/CurrentSimulator.py index 6510552..11418ae 100644 --- a/service/simulation/CurrentSimulator.py +++ b/service/simulation/CurrentSimulator.py @@ -1,6 +1,48 @@ from .SimulatorInterface2 import SimulatorInterface2 from simulate_type.simulate_list import generate_current_data +import random class CurrentSimulator(SimulatorInterface2): - def generate_data(self, idx: int) -> dict: - return generate_current_data(idx) \ No newline at end of file + def __init__(self, idx: int, space_id:str, manufacture_id:str, interval:int = 5, msg_count:int = 10, conn=None): + # 시뮬레이터에서 공통적으로 사용하는 속성 + super().__init__( + idx=idx, + space_id=space_id, + manufacture_id=manufacture_id, + interval=interval, + msg_count=msg_count, + conn=conn + ) + # 시뮬레이터 마다 개별적으로 사용하는 속성(토픽, 수집 데이터 초기값) + self.sensor_id = f"UA10C-CUR-2406089{idx}" # 센서 ID + self.type = "current" # 센서 타입 + self.shadow_regist_topic_name = f"$aws/things/Sensor/shadow/name/{self.sensor_id}/update" + self.shadow_desired_topic_name = f"$aws/things/Sensor/shadow/name/{self.sensor_id}/update/desired" + self.topic_name = f"sensor/{space_id}/{manufacture_id}/{self.sensor_id}/{self.type}" + self.target_current = None # 초기값 설정(shadow 용) + + # 데이터 생성 로직 정의 + def _generate_data(self) -> dict: + return { + "zoneId": self.space_id, + "equipId": self.manufacture_id, + "sensorId": self.sensor_id, + "sensorType": self.type, + "val": round(random.uniform(0.1 + self.idx, 10.0 + self.idx), 2) + } + + ################################################ + # 제어 로직을 정의 ( shadow의 desired 상태를 구독하여 제어하는 로직을 구현할 예정) + # sprint 2 에서 더 구체화 예정 + ################################################ + def _apply_desired_state(self, desired_state): + """ + Shadow의 desired 상태를 받아서 센서에 적용 + 예) {"target_Vibration": 25.0} 이런 명령을 받아 적용 + """ + target_current = desired_state.get("target_current") + if target_current is not None: + self.target_current = target_current + print(f"Desired state applied: {self.sensor_id} - Target Current: {self.target_current}") + else: + print(f"No target current provided for {self.sensor_id}.") \ No newline at end of file diff --git a/service/simulation/DustSimulator.py b/service/simulation/DustSimulator.py new file mode 100644 index 0000000..8fe2ea3 --- /dev/null +++ b/service/simulation/DustSimulator.py @@ -0,0 +1,47 @@ +from .SimulatorInterface2 import SimulatorInterface2 +import random + +class DustSimulator(SimulatorInterface2): + def __init__(self, idx: int, space_id:str, manufacture_id:str, interval:int = 5, msg_count:int = 10, conn=None): + # 시뮬레이터에서 공통적으로 사용하는 속성 + super().__init__( + idx=idx, + space_id=space_id, + manufacture_id=manufacture_id, + interval=interval, + msg_count=msg_count, + conn=conn + ) + # 시뮬레이터 마다 개별적으로 사용하는 속성(토픽, 수집 데이터 초기값) + self.sensor_id = f"UA10D-DST-2406089{idx}" # 센서 ID + self.type = "dust" # 센서 타입 + self.shadow_regist_topic_name = f"$aws/things/Sensor/shadow/name/{self.sensor_id}/update" + self.shadow_desired_topic_name = f"$aws/things/Sensor/shadow/name/{self.sensor_id}/update/desired" + self.topic_name = f"sensor/{space_id}/{manufacture_id}/{self.sensor_id}/{self.type}" + self.target_current = None # 초기값 설정(shadow 용) + + # 데이터 생성 로직 정의 + def _generate_data(self) -> dict: + return { + "zoneId": self.space_id, + "equipId": self.manufacture_id, + "sensorId": self.sensor_id, + "sensorType": self.type, + "val": round(random.uniform(5.0 + self.idx, 50.0 + self.idx), 2) + } + + ################################################ + # 제어 로직을 정의 ( shadow의 desired 상태를 구독하여 제어하는 로직을 구현할 예정) + # sprint 2 에서 더 구체화 예정 + ################################################ + def _apply_desired_state(self, desired_state): + """ + Shadow의 desired 상태를 받아서 센서에 적용 + 예) {"target_Vibration": 25.0} 이런 명령을 받아 적용 + """ + target_current = desired_state.get("target_current") + if target_current is not None: + self.target_current = target_current + print(f"Desired state applied: {self.sensor_id} - Target Current: {self.target_current}") + else: + print(f"No target current provided for {self.sensor_id}.") \ No newline at end of file diff --git a/service/simulation/ExampleSimulator.py b/service/simulation/ExampleSimulator.py index 754817e..a48625d 100644 --- a/service/simulation/ExampleSimulator.py +++ b/service/simulation/ExampleSimulator.py @@ -38,16 +38,18 @@ def __init__(self, idx: int, space_id:str, manufacture_id:str, interval:int = 5, # 예) 온도, 습도, 진동, 전류 등등 ################################################ def _generate_data(self) -> dict: - """ 데이터 생성 메서드 """ return { - "id": self.sensor_id, - "type": self.type, - "temperature": round(random.uniform(20.0 + self.idx, 30.0 + self.idx), 2) + "zoneId": self.space_id, + "equipId": self.manufacture_id, + "sensorId": self.sensor_id, + "sensorType": self.type, + "val": round(random.uniform(20.0 + self.idx, 30.0 + self.idx), 2) } ################################################ # 제어 로직을 정의 ( shadow의 desired 상태를 구독하여 제어하는 로직을 구현할 예정) + # sprint 2 에서 더 구체화 예정 ################################################ def _apply_desired_state(self, desired_state): """ diff --git a/service/simulation/VibrationSimulator.py b/service/simulation/VibrationSimulator.py index a587b79..1723700 100644 --- a/service/simulation/VibrationSimulator.py +++ b/service/simulation/VibrationSimulator.py @@ -1,6 +1,50 @@ from .SimulatorInterface2 import SimulatorInterface2 from simulate_type.simulate_list import generate_vibration_data +import random class VibrationSimulator(SimulatorInterface2): - def generate_data(self, idx: int) -> dict: - return generate_vibration_data(idx) \ No newline at end of file + def __init__(self, idx: int, space_id:str, manufacture_id:str, interval:int = 5, msg_count:int = 10, conn=None): + # 시뮬레이터에서 공통적으로 사용하는 속성 + super().__init__( + idx=idx, + space_id=space_id, + manufacture_id=manufacture_id, + interval=interval, + msg_count=msg_count, + conn=conn + ) + # 시뮬레이터 마다 개별적으로 사용하는 속성(토픽, 수집 데이터 초기값) + self.sensor_id = f"UA10V-VIB-2406089{idx}" # Sensor ID + self.type = "vibration" # Sensor type + self.shadow_regist_topic_name = f"$aws/things/Sensor/shadow/name/{self.sensor_id}/update" + self.shadow_desired_topic_name = f"$aws/things/Sensor/shadow/name/{self.sensor_id}/update/desired" + self.topic_name = f"sensor/{space_id}/{manufacture_id}/{self.sensor_id}/{self.type}" + self.target_vibration = None # Initial value for shadow) + + # 데이터 생성 로직을 정의 (시뮬레이터 마다 다르게 구현) + def _generate_data(self) -> dict: + return { + "zoneId": self.space_id, + "equipId": self.manufacture_id, + "sensorId": self.sensor_id, + "sensorType": self.type, + "val": round(random.uniform(0.1 + self.idx, 10.0 + self.idx), 2) + } + + + ################################################ + # 제어 로직을 정의 ( shadow의 desired 상태를 구독하여 제어하는 로직을 구현할 예정) + # sprint 2 에서 더 구체화 예정 + ################################################ + def _apply_desired_state(self, desired_state): + """ + Shadow의 desired 상태를 받아서 센서에 적용 + 예) {"target_Vibration": 25.0} 이런 명령을 받아 적용 + """ + target_vibration = desired_state.get("target_vibration") + if target_vibration is not None: + self.target_vibration = target_vibration + print(f"Desired state applied: {self.sensor_id} - Target Vibration: {self.target_vibration}") + else: + print(f"No target vibration provided for {self.sensor_id}.") + \ No newline at end of file diff --git a/service/simulation/factory.py b/service/simulation/factory.py index bd1005a..f94b3cb 100644 --- a/service/simulation/factory.py +++ b/service/simulation/factory.py @@ -1,8 +1,8 @@ from service.simulation import TempSimulator from service.simulation.HumiditySimulator import HumiditySimulator -from service.simulation.HumidityTempSimulator import HumidityTempSimulator from service.simulation.VibrationSimulator import VibrationSimulator from service.simulation.CurrentSimulator import CurrentSimulator +from service.simulation.DustSimulator import DustSimulator from service.simulation.ExampleSimulator import ExampleSimulator from mqtt_util.publish import AwsMQTT from typing import List @@ -15,13 +15,15 @@ def get_simulator(simulator_type: str, idx: int, space_id: str, manufacture_id: if simulator_type == "temp": simulator_entity_list.append(TempSimulator(i, space_id, manufacture_id, interval, msg_count, conn)) elif simulator_type == "humidity": - simulator_entity_list.append(HumiditySimulator()) - elif simulator_type == "humidity_temp": - simulator_entity_list.append(HumidityTempSimulator()) + simulator_entity_list.append(HumiditySimulator(i, space_id, manufacture_id, interval, msg_count, conn)) + # elif simulator_type == "humidity_temp": + # simulator_entity_list.append(HumidityTempSimulator(i, space_id, manufacture_id, interval, msg_count, conn)) elif simulator_type == "vibration": - simulator_entity_list.append(VibrationSimulator()) + simulator_entity_list.append(VibrationSimulator(i, space_id, manufacture_id, interval, msg_count, conn)) elif simulator_type == "current": - simulator_entity_list.append(CurrentSimulator()) + simulator_entity_list.append(CurrentSimulator(i, space_id, manufacture_id, interval, msg_count, conn)) + elif simulator_type == "dust": + simulator_entity_list.append(DustSimulator(i, space_id, manufacture_id, interval, msg_count, conn)) elif simulator_type == "example": simulator_entity_list.append(ExampleSimulator(i, space_id, manufacture_id, interval, msg_count, conn)) else: diff --git a/service/simulation/simulateTest.py b/service/simulation/simulateTest.py index 6dc949a..8483958 100644 --- a/service/simulation/simulateTest.py +++ b/service/simulation/simulateTest.py @@ -62,7 +62,7 @@ def main(): parser.add_argument("--interval", type=float, default=5.0, help="Interval between data entries in seconds.") parser.add_argument("--manufacture_id", type=str, default="SBID-001", help="Manufacture ID.") parser.add_argument("--space_id", type=str, default="PID-001", help="Space ID.") - parser.add_argument("--simulator", type=str, choices=["temp", "humidity","humidity_temp", "vibration", "current" ], default="example", help="Type of data simulator.") + parser.add_argument("--simulator", type=str, choices=["temp", "humidity", "vibration", "current" , "dust" ], default="example", help="Type of data simulator.") parser.add_argument("--sensor_num", type=int, default=2, help="Number of sensors to simulate.") args = parser.parse_args() From ed7487f666b9b2ce427d5fea5eb4a975ffd78ff6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B4=91=EB=B6=80=EC=9E=85=EB=8B=88=EB=8B=A4?= Date: Tue, 29 Apr 2025 15:41:34 +0900 Subject: [PATCH 03/15] =?UTF-8?q?feat=20|=20sprint1=20|=20FRB-101=20|=20?= =?UTF-8?q?=EC=98=A8=EC=8A=B5=EB=8F=84=20=EC=8B=9C=EB=AE=AC=EB=A0=88?= =?UTF-8?q?=EC=9D=B4=ED=84=B0=20=EC=B6=94=EA=B0=80=20|=20=EA=B9=80?= =?UTF-8?q?=EC=9A=B0=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- service/simulation/HumiditySimulator.py | 63 +++++++++++++++++++- service/simulation/HumidityTempSimulator.py | 66 +++++++++++++++++++-- service/simulation/TempSimulator.py | 66 +++++++++++++++++++-- simulate_type/simulate_list.py | 8 +-- 4 files changed, 187 insertions(+), 16 deletions(-) diff --git a/service/simulation/HumiditySimulator.py b/service/simulation/HumiditySimulator.py index 8a5a84f..2007be8 100644 --- a/service/simulation/HumiditySimulator.py +++ b/service/simulation/HumiditySimulator.py @@ -1,6 +1,65 @@ from .SimulatorInterface2 import SimulatorInterface2 from simulate_type.simulate_list import generate_humidity_data +import random class HumiditySimulator(SimulatorInterface2): - def generate_data(self, idx: int) -> dict: - return generate_humidity_data(idx) \ No newline at end of file + def __init__(self, idx: int, space_id:str, manufacture_id:str, interval:int = 5, msg_count:int = 10, conn=None): + ######################################### + # 시뮬레이터에서 공통적으로 사용하는 속성 + ######################################### + super().__init__( + idx=idx, + space_id=space_id, + manufacture_id=manufacture_id, + interval=interval, + msg_count=msg_count, + conn=conn + ) + + ######################################### + # 시뮬레이터 마다 개별적으로 사용하는 속성(토픽, 수집 데이터 초기값) + ######################################### + + self.sensor_id = f"UA10H-SUP-2406089{idx}" # 센서 ID + self.type = "humid" # 센서 타입 + # shadow 등록용 토픽 + self.shadow_regist_topic_name = f"$aws/things/sensor/shadow/name/{self.sensor_id}/update" + + # shadow 제어 명령 구독용 토픽 + self.shadow_desired_topic_name = f"$aws/things/sensor/shadow/name/{self.sensor_id}/update/desired" + + # 센서 데이터 publish용 토픽 + self.topic_name = f"{space_id}/{manufacture_id}/{self.sensor_id}/{self.type}" + + self.target_temperature = None # 초기값 설정(shadow 용) + + ################################################z + # 데이터 생성 로직을 정의 (시뮬레이터 마다 다르게 구현) + # 예) 온도, 습도, 진동, 전류 등등 + ################################################ + def _generate_data(self) -> dict: + """ 데이터 생성 메서드 """ + return { + "zoneId": self.space_id, + "equipId": self.manufacture_id, + "sensorId": self.sensor_id, + "sensorType": self.type, + "val": round(random.uniform(20.0 + self.idx, 80.0 + self.idx), 2) + } + + ################################################ + # 제어 로직을 정의 ( shadow의 desired 상태를 구독하여 제어하는 로직을 구현할 예정) + ################################################ + def _apply_desired_state(self, desired_state): + """ + Shadow의 desired 상태를 받아서 센서에 적용 + 예) {"target_humidity": 25.0} 이런 명령을 받아 적용 + """ + target_humidity = desired_state.get("target_humidity") + if target_humidity is not None: + self.target_humidity = target_humidity + print(f"Desired state applied: {self.sensor_id} - Target humidity: {self.target_humidity}") + else: + print(f"No target humidity provided for {self.sensor_id}.") + + \ No newline at end of file diff --git a/service/simulation/HumidityTempSimulator.py b/service/simulation/HumidityTempSimulator.py index 8199580..8a8154d 100644 --- a/service/simulation/HumidityTempSimulator.py +++ b/service/simulation/HumidityTempSimulator.py @@ -1,9 +1,63 @@ from .SimulatorInterface2 import SimulatorInterface2 -from simulate_type.simulate_list import generate_humidity_temp_data +import random -class HumidityTempSimulator(SimulatorInterface2): - def generate_data(self, idx: int) -> dict: - """ - Generate a single data entry containing both humidity and temperature. +class humidTempSimulator(SimulatorInterface2): + def __init__(self, idx: int, space_id:str, manufacture_id:str, interval:int = 5, msg_count:int = 10, conn=None): + ######################################### + # 시뮬레이터에서 공통적으로 사용하는 속성 + ######################################### + super().__init__( + idx=idx, + space_id=space_id, + manufacture_id=manufacture_id, + interval=interval, + msg_count=msg_count, + conn=conn + ) + + ######################################### + # 시뮬레이터 마다 개별적으로 사용하는 속성(토픽, 수집 데이터 초기값) + ######################################### + + self.sensor_id = f"UA10H-CHS-2406089{idx}" # 센서 ID + self.type = "temp_humid" # 센서 타입 + # shadow 등록용 토픽 + self.shadow_regist_topic_name = f"$aws/things/KWYTEST/shadow/name/{self.sensor_id}/update" + + # shadow 제어 명령 구독용 토픽 + self.shadow_desired_topic_name = f"$aws/things/KWYTEST/shadow/name/{self.sensor_id}/update/desired" + + # 센서 데이터 publish용 토픽 + self.topic_name = f"{space_id}/{manufacture_id}/{self.sensor_id}/{self.type}" + + self.target_temperature = None # 초기값 설정(shadow 용) + + ################################################ + # 데이터 생성 로직을 정의 (시뮬레이터 마다 다르게 구현) + # 예) 온도, 습도, 진동, 전류 등등 + ################################################ + def _generate_data(self) -> dict: + """ 데이터 생성 메서드 """ + return { + "id": self.sensor_id, + "type": self.type, + "temperature": round(random.uniform(20.0 + self.idx, 30.0 + self.idx), 2) + } + + + ################################################ + # 제어 로직을 정의 ( shadow의 desired 상태를 구독하여 제어하는 로직을 구현할 예정) + ################################################ + def _apply_desired_state(self, desired_state): + """ + Shadow의 desired 상태를 받아서 센서에 적용 + 예) {"target_temperature": 25.0} 이런 명령을 받아 적용 """ - return generate_humidity_temp_data(idx) \ No newline at end of file + target_temperature = desired_state.get("target_temperature") + if target_temperature is not None: + self.target_temperature = target_temperature + print(f"Desired state applied: {self.sensor_id} - Target Temperature: {self.target_temperature}") + else: + print(f"No target temperature provided for {self.sensor_id}.") + + \ No newline at end of file diff --git a/service/simulation/TempSimulator.py b/service/simulation/TempSimulator.py index cb74d57..a0b4871 100644 --- a/service/simulation/TempSimulator.py +++ b/service/simulation/TempSimulator.py @@ -1,6 +1,64 @@ from .SimulatorInterface2 import SimulatorInterface2 -from simulate_type.simulate_list import generate_temp_data +import random -class TempSimulator(SimulatorInterface2): - def generate_data(self, idx: int) -> dict: - return generate_temp_data(idx) \ No newline at end of file +class humidSimulator(SimulatorInterface2): + def __init__(self, idx: int, space_id:str, manufacture_id:str, interval:int = 5, msg_count:int = 10, conn=None): + ######################################### + # 시뮬레이터에서 공통적으로 사용하는 속성 + ######################################### + super().__init__( + idx=idx, + space_id=space_id, + manufacture_id=manufacture_id, + interval=interval, + msg_count=msg_count, + conn=conn + ) + + ######################################### + # 시뮬레이터 마다 개별적으로 사용하는 속성(토픽, 수집 데이터 초기값) + ######################################### + + self.sensor_id = f"UA10H-SUP-2406089{idx}" # 센서 ID + self.type = "temp" # 센서 타입 + # shadow 등록용 토픽 + self.shadow_regist_topic_name = f"$aws/things/sensor/shadow/name/{self.sensor_id}/update" + + # shadow 제어 명령 구독용 토픽 + self.shadow_desired_topic_name = f"$aws/things/sensor/shadow/name/{self.sensor_id}/update/desired" + + # 센서 데이터 publish용 토픽 + self.topic_name = f"sensor/{space_id}/{manufacture_id}/{self.sensor_id}/{self.type}" + + self.target_temperature = None # 초기값 설정(shadow 용) + + ################################################z + # 데이터 생성 로직을 정의 (시뮬레이터 마다 다르게 구현) + # 예) 온도, 습도, 진동, 전류 등등 + ################################################ + def _generate_data(self) -> dict: + """ 데이터 생성 메서드 """ + return { + "zoneId": self.space_id, + "equipId": self.manufacture_id, + "sensorId": self.sensor_id, + "sensorType": self.type, + "val": round(random.uniform(20.0 + self.idx, 80.0 + self.idx), 2) + } + + ################################################ + # 제어 로직을 정의 ( shadow의 desired 상태를 구독하여 제어하는 로직을 구현할 예정) + ################################################ + def _apply_desired_state(self, desired_state): + """ + Shadow의 desired 상태를 받아서 센서에 적용 + 예) {"target_humid": 25.0} 이런 명령을 받아 적용 + """ + target_humid = desired_state.get("target_humid") + if target_humid is not None: + self.target_humid = target_humid + print(f"Desired state applied: {self.sensor_id} - Target humid: {self.target_humid}") + else: + print(f"No target humid provided for {self.sensor_id}.") + + \ No newline at end of file diff --git a/simulate_type/simulate_list.py b/simulate_type/simulate_list.py index cf34b3d..0ffded1 100644 --- a/simulate_type/simulate_list.py +++ b/simulate_type/simulate_list.py @@ -10,20 +10,20 @@ def generate_temp_data(sensor_idx): } # 습도 센서 -def generate_humidity_data(sensor_idx): +def generate_humid_data(sensor_idx): return { "id": f"UA10H-CHS-2406089{sensor_idx}", "type": "SUP", - "humidity": round(random.uniform(20.0 + sensor_idx, 80.0 + sensor_idx), 2) + "humid": round(random.uniform(20.0 + sensor_idx, 80.0 + sensor_idx), 2) } # 온습도 센서 -def generate_humidity_temp_data(sensor_idx): +def generate_humid_temp_data(sensor_idx): return { "id": f"UA10H-CHS-2406089{sensor_idx}", "type": "ON-SUP", "temperature": round(random.uniform(20.0 + sensor_idx, 30.0 + sensor_idx), 2), - "humidity": round(random.uniform(20.0 + sensor_idx, 80.0 + sensor_idx), 2) + "humid": round(random.uniform(20.0 + sensor_idx, 80.0 + sensor_idx), 2) } From f9e3e791f883f147f02c65dcc00f4800ce0c605c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B4=91=EB=B6=80=EC=9E=85=EB=8B=88=EB=8B=A4?= Date: Tue, 29 Apr 2025 16:11:12 +0900 Subject: [PATCH 04/15] =?UTF-8?q?feat=20|=20sprint1=20|=20FRB-101=20|=20VO?= =?UTF-8?q?C=20=EC=8B=9C=EB=AE=AC=EB=A0=88=EC=9D=B4=ED=84=B0=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20|=20=EA=B9=80=EC=9A=B0=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- service/simulation/ExampleSimulator.py | 2 +- service/simulation/HumiditySimulator.py | 5 +-- service/simulation/HumidityTempSimulator.py | 2 +- service/simulation/TempSimulator.py | 2 +- service/simulation/VocSimulator.py | 47 +++++++++++++++++++++ service/simulation/factory.py | 3 ++ service/simulation/simulateTest.py | 2 +- 7 files changed, 56 insertions(+), 7 deletions(-) create mode 100644 service/simulation/VocSimulator.py diff --git a/service/simulation/ExampleSimulator.py b/service/simulation/ExampleSimulator.py index a48625d..6ff504a 100644 --- a/service/simulation/ExampleSimulator.py +++ b/service/simulation/ExampleSimulator.py @@ -29,7 +29,7 @@ def __init__(self, idx: int, space_id:str, manufacture_id:str, interval:int = 5, self.shadow_desired_topic_name = f"$aws/things/KWYTEST/shadow/name/{self.sensor_id}/update/desired" # 센서 데이터 publish용 토픽 - self.topic_name = f"{space_id}/{manufacture_id}/{self.sensor_id}/{self.type}" + self.topic_name = f"sensor/{space_id}/{manufacture_id}/{self.sensor_id}/{self.type}" self.target_temperature = None # 초기값 설정(shadow 용) diff --git a/service/simulation/HumiditySimulator.py b/service/simulation/HumiditySimulator.py index 2007be8..116185f 100644 --- a/service/simulation/HumiditySimulator.py +++ b/service/simulation/HumiditySimulator.py @@ -1,5 +1,4 @@ from .SimulatorInterface2 import SimulatorInterface2 -from simulate_type.simulate_list import generate_humidity_data import random class HumiditySimulator(SimulatorInterface2): @@ -20,7 +19,7 @@ def __init__(self, idx: int, space_id:str, manufacture_id:str, interval:int = 5, # 시뮬레이터 마다 개별적으로 사용하는 속성(토픽, 수집 데이터 초기값) ######################################### - self.sensor_id = f"UA10H-SUP-2406089{idx}" # 센서 ID + self.sensor_id = f"UA10H-HUM-2406089{idx}" # 센서 ID self.type = "humid" # 센서 타입 # shadow 등록용 토픽 self.shadow_regist_topic_name = f"$aws/things/sensor/shadow/name/{self.sensor_id}/update" @@ -29,7 +28,7 @@ def __init__(self, idx: int, space_id:str, manufacture_id:str, interval:int = 5, self.shadow_desired_topic_name = f"$aws/things/sensor/shadow/name/{self.sensor_id}/update/desired" # 센서 데이터 publish용 토픽 - self.topic_name = f"{space_id}/{manufacture_id}/{self.sensor_id}/{self.type}" + self.topic_name = f"sensor/{space_id}/{manufacture_id}/{self.sensor_id}/{self.type}" self.target_temperature = None # 초기값 설정(shadow 용) diff --git a/service/simulation/HumidityTempSimulator.py b/service/simulation/HumidityTempSimulator.py index 8a8154d..d118046 100644 --- a/service/simulation/HumidityTempSimulator.py +++ b/service/simulation/HumidityTempSimulator.py @@ -28,7 +28,7 @@ def __init__(self, idx: int, space_id:str, manufacture_id:str, interval:int = 5, self.shadow_desired_topic_name = f"$aws/things/KWYTEST/shadow/name/{self.sensor_id}/update/desired" # 센서 데이터 publish용 토픽 - self.topic_name = f"{space_id}/{manufacture_id}/{self.sensor_id}/{self.type}" + self.topic_name = f"sensor/{space_id}/{manufacture_id}/{self.sensor_id}/{self.type}" self.target_temperature = None # 초기값 설정(shadow 용) diff --git a/service/simulation/TempSimulator.py b/service/simulation/TempSimulator.py index a0b4871..8637e53 100644 --- a/service/simulation/TempSimulator.py +++ b/service/simulation/TempSimulator.py @@ -19,7 +19,7 @@ def __init__(self, idx: int, space_id:str, manufacture_id:str, interval:int = 5, # 시뮬레이터 마다 개별적으로 사용하는 속성(토픽, 수집 데이터 초기값) ######################################### - self.sensor_id = f"UA10H-SUP-2406089{idx}" # 센서 ID + self.sensor_id = f"UA10T-TEM-2406089{idx}" # 센서 ID self.type = "temp" # 센서 타입 # shadow 등록용 토픽 self.shadow_regist_topic_name = f"$aws/things/sensor/shadow/name/{self.sensor_id}/update" diff --git a/service/simulation/VocSimulator.py b/service/simulation/VocSimulator.py new file mode 100644 index 0000000..a2978de --- /dev/null +++ b/service/simulation/VocSimulator.py @@ -0,0 +1,47 @@ +from .SimulatorInterface2 import SimulatorInterface2 +import random + +class VocSimulator(SimulatorInterface2): + def __init__(self, idx: int, space_id:str, manufacture_id:str, interval:int = 5, msg_count:int = 10, conn=None): + # 시뮬레이터에서 공통적으로 사용하는 속성 + super().__init__( + idx=idx, + space_id=space_id, + manufacture_id=manufacture_id, + interval=interval, + msg_count=msg_count, + conn=conn + ) + # 시뮬레이터 마다 개별적으로 사용하는 속성(토픽, 수집 데이터 초기값) + self.sensor_id = f"UA10V-VOC-2406089{idx}" # 센서 ID + self.type = "voc" # 센서 타입 + self.shadow_regist_topic_name = f"$aws/things/Sensor/shadow/name/{self.sensor_id}/update" + self.shadow_desired_topic_name = f"$aws/things/Sensor/shadow/name/{self.sensor_id}/update/desired" + self.topic_name = f"sensor/{space_id}/{manufacture_id}/{self.sensor_id}/{self.type}" + self.target_current = None # 초기값 설정(shadow 용) + + # 데이터 생성 로직 정의 + def _generate_data(self) -> dict: + return { + "zoneId": self.space_id, + "equipId": self.manufacture_id, + "sensorId": self.sensor_id, + "sensorType": self.type, + "val": round(random.uniform(5.0 + self.idx, 50.0 + self.idx), 2) + } + + ################################################ + # 제어 로직을 정의 ( shadow의 desired 상태를 구독하여 제어하는 로직을 구현할 예정) + # sprint 2 에서 더 구체화 예정 + ################################################ + def _apply_desired_state(self, desired_state): + """ + Shadow의 desired 상태를 받아서 센서에 적용 + 예) {"target_Vibration": 25.0} 이런 명령을 받아 적용 + """ + target_current = desired_state.get("target_current") + if target_current is not None: + self.target_current = target_current + print(f"Desired state applied: {self.sensor_id} - Target Current: {self.target_current}") + else: + print(f"No target current provided for {self.sensor_id}.") \ No newline at end of file diff --git a/service/simulation/factory.py b/service/simulation/factory.py index f94b3cb..b3edd05 100644 --- a/service/simulation/factory.py +++ b/service/simulation/factory.py @@ -4,6 +4,7 @@ from service.simulation.CurrentSimulator import CurrentSimulator from service.simulation.DustSimulator import DustSimulator from service.simulation.ExampleSimulator import ExampleSimulator +from service.simulation.VocSimulator import VocSimulator from mqtt_util.publish import AwsMQTT from typing import List # from .SimulatorInterface import SimulatorInterface @@ -26,6 +27,8 @@ def get_simulator(simulator_type: str, idx: int, space_id: str, manufacture_id: simulator_entity_list.append(DustSimulator(i, space_id, manufacture_id, interval, msg_count, conn)) elif simulator_type == "example": simulator_entity_list.append(ExampleSimulator(i, space_id, manufacture_id, interval, msg_count, conn)) + elif simulator_type == "voc": + simulator_entity_list.append(VocSimulator(i, space_id, manufacture_id, interval, msg_count, conn)) else: raise ValueError(f"Unknown simulator type: {simulator_type}") return simulator_entity_list \ No newline at end of file diff --git a/service/simulation/simulateTest.py b/service/simulation/simulateTest.py index 8483958..40d43e7 100644 --- a/service/simulation/simulateTest.py +++ b/service/simulation/simulateTest.py @@ -62,7 +62,7 @@ def main(): parser.add_argument("--interval", type=float, default=5.0, help="Interval between data entries in seconds.") parser.add_argument("--manufacture_id", type=str, default="SBID-001", help="Manufacture ID.") parser.add_argument("--space_id", type=str, default="PID-001", help="Space ID.") - parser.add_argument("--simulator", type=str, choices=["temp", "humidity", "vibration", "current" , "dust" ], default="example", help="Type of data simulator.") + parser.add_argument("--simulator", type=str, choices=["temp", "humidity", "vibration", "current" , "dust","voc" ], default="example", help="Type of data simulator.") parser.add_argument("--sensor_num", type=int, default=2, help="Number of sensors to simulate.") args = parser.parse_args() From 10c2c825fd1324010f1f8590d904619fd0e9fd24 Mon Sep 17 00:00:00 2001 From: minnnseokk Date: Tue, 29 Apr 2025 17:51:52 +0900 Subject: [PATCH 05/15] =?UTF-8?q?feat=20=20=20=20|=20sprint1=20|=20FRB-121?= =?UTF-8?q?=20|=20=EC=84=BC=EC=84=9C=20=EC=8A=A4=EB=A0=88=EB=93=9C=20?= =?UTF-8?q?=ED=98=95=EC=8B=9D,=20json=20=ED=8C=8C=EC=9D=BC=EB=A1=9C=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC=20|=20=EC=A0=95=EB=AF=BC=EC=84=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- service/simulation/HumiditySimulator.py | 46 +++++++- service/simulation/HumidityTempSimulator.py | 16 +-- service/simulation/simulateTest.py | 114 +++++++++----------- service/simulation/simulation_cconfig.json | 44 ++++++++ 4 files changed, 144 insertions(+), 76 deletions(-) create mode 100644 service/simulation/simulation_cconfig.json diff --git a/service/simulation/HumiditySimulator.py b/service/simulation/HumiditySimulator.py index 8a5a84f..743b52e 100644 --- a/service/simulation/HumiditySimulator.py +++ b/service/simulation/HumiditySimulator.py @@ -1,6 +1,48 @@ from .SimulatorInterface2 import SimulatorInterface2 from simulate_type.simulate_list import generate_humidity_data +import random class HumiditySimulator(SimulatorInterface2): - def generate_data(self, idx: int) -> dict: - return generate_humidity_data(idx) \ No newline at end of file + def __init__(self, idx: int, space_id:str, manufacture_id:str, interval:int = 5, msg_count:int = 10, conn=None): + # 시뮬레이터에서 공통적으로 사용하는 속성 + super().__init__( + idx=idx, + space_id=space_id, + manufacture_id=manufacture_id, + interval=interval, + msg_count=msg_count, + conn=conn + ) + # 시뮬레이터 마다 개별적으로 사용하는 속성(토픽, 수집 데이터 초기값) + self.sensor_id = f"UA10H-HUM-2406089{idx}" # 센서 ID + self.type = "humidity" # 센서 타입 + self.shadow_regist_topic_name = f"$aws/things/Sensor/shadow/name/{self.sensor_id}/update" + self.shadow_desired_topic_name = f"$aws/things/Sensor/shadow/name/{self.sensor_id}/update/desired" + self.topic_name = f"{space_id}/{manufacture_id}/{self.sensor_id}/{self.type}" + self.target_current = None # 초기값 설정(shadow 용) + + # 데이터 생성 로직 정의 + def _generate_data(self) -> dict: + return { + "zoneId": self.space_id, + "equipId": self.manufacture_id, + "sensorId": self.sensor_id, + "sensorType": self.type, + "val": round(random.uniform(20.0 + self.idx, 80.0 + self.idx), 2) + } + + ################################################ + # 제어 로직을 정의 ( shadow의 desired 상태를 구독하여 제어하는 로직을 구현할 예정) + # sprint 2 에서 더 구체화 예정 + ################################################ + def _apply_desired_state(self, desired_state): + """ + Shadow의 desired 상태를 받아서 센서에 적용 + 예) {"target_Vibration": 25.0} 이런 명령을 받아 적용 + """ + target_humidity = desired_state.get("target_humidity") + if target_humidity is not None: + self.target_humidity = target_humidity + print(f"Desired state applied: {self.sensor_id} - Target Humidity: {self.target_humidity}") + else: + print(f"No target_humidity provided for {self.sensor_id}.") \ No newline at end of file diff --git a/service/simulation/HumidityTempSimulator.py b/service/simulation/HumidityTempSimulator.py index 8199580..aa24ece 100644 --- a/service/simulation/HumidityTempSimulator.py +++ b/service/simulation/HumidityTempSimulator.py @@ -1,9 +1,9 @@ -from .SimulatorInterface2 import SimulatorInterface2 -from simulate_type.simulate_list import generate_humidity_temp_data +# from .SimulatorInterface2 import SimulatorInterface2 +# from simulate_type.simulate_list import generate_humidity_temp_data -class HumidityTempSimulator(SimulatorInterface2): - def generate_data(self, idx: int) -> dict: - """ - Generate a single data entry containing both humidity and temperature. - """ - return generate_humidity_temp_data(idx) \ No newline at end of file +# class HumidityTempSimulator(SimulatorInterface2): +# def generate_data(self, idx: int) -> dict: +# """ +# Generate a single data entry containing both humidity and temperature. +# """ +# return generate_humidity_temp_data(idx) \ No newline at end of file diff --git a/service/simulation/simulateTest.py b/service/simulation/simulateTest.py index 8483958..275a70c 100644 --- a/service/simulation/simulateTest.py +++ b/service/simulation/simulateTest.py @@ -3,85 +3,67 @@ import sys import argparse import json +import threading from awscrt import mqtt from mqtt_util.publish import AwsMQTT # 각 시뮬레이션 인터페이스에서 해당 데이터들을 사용, 메인에선 사용 X # from simulate_type.simulate_list import generate_temp_data, generate_humidity_data, generate_humidity_temp_data, generate_wearable_data, generate_vibration_data, generate_current_data from .factory import get_simulator +conn = AwsMQTT() + +# 스레드에서 실행될 시뮬레이션 함수수 +def run_simulator(simulator, count, interval): + for _ in range(count): + data = simulator.start_publishing() + print(json.dumps(data, indent=4)) # 데이터를 JSON 형식으로 출력 + time.sleep(interval) + # 시뮬레이션 함수 -def simulate_data(count, interval, manufacture_id, space_id, sensor_num=2, conn: AwsMQTT = None, simulator_type="temp"): - try: - print(f"Simulating {simulator_type} data stream for {count} entries with {interval} second intervals... (Press Ctrl+C to stop)") - +def run_simulation_from_json(json_file_path): + # JSON 파일 읽기 + with open(json_file_path, 'r') as file: + config = json.load(file) + + devices = config.get("devices", []) + if not devices: + print("No devices found in the configuration.") + return + + threads = [] # 스레드를 저장할 리스트 + + for device in devices: + count = device.get("count", 10) + interval = device.get("interval", 1.0) + manufacture_id = device.get("manufacture_id", "UNKNOWN") + space_id = device.get("space_id", "UNKNOWN") + simulator_type = device.get("simulator", "temp") + sensor_num = device.get("sensor_num", 1) + + print(f"Starting simulation for {simulator_type} with {sensor_num} sensors...") + # 시뮬레이터 생성 simulators = get_simulator( + conn = conn, + simulator_type=simulator_type, idx=sensor_num, - interval=interval, - msg_count=count, - manufacture_id=manufacture_id, space_id=space_id, - simulator_type=simulator_type, - conn=conn + manufacture_id=manufacture_id, + interval=interval, + msg_count=count ) + # 데이터 생성 및 출력 for simulator in simulators: - simulator.start_publishing() - - # 스레드 상태를 모니터링 - while any(sim.thread.is_alive() for sim in simulators): - time.sleep(0.1) - - except KeyboardInterrupt: - print("\nSimulation stopped by user.") - for simulator in simulators: - simulator.stop() - finally: - conn.disconnect() - -# 콜백 함수: MQTT로 데이터를 전송 -def mqtt_publish_callback(data, topic): - # JSON 직렬화 - payload = json.dumps(data) - # MQTT 연결 객체를 통해 publish 호출 - - conn.publish( - topic=topic, - payload=payload, - qos=mqtt.QoS.AT_LEAST_ONCE - ) - print(f"Published: {payload}") - -# 메인 함수 -def main(): - global conn - # CLI 매개변수 파싱 # - parser = argparse.ArgumentParser(description="Simulate various data types and publish them via MQTT.") - - parser.add_argument("--count", type=int, default=10, help="Number of data entries to generate.") - parser.add_argument("--interval", type=float, default=5.0, help="Interval between data entries in seconds.") - parser.add_argument("--manufacture_id", type=str, default="SBID-001", help="Manufacture ID.") - parser.add_argument("--space_id", type=str, default="PID-001", help="Space ID.") - parser.add_argument("--simulator", type=str, choices=["temp", "humidity", "vibration", "current" , "dust" ], default="example", help="Type of data simulator.") - parser.add_argument("--sensor_num", type=int, default=2, help="Number of sensors to simulate.") - args = parser.parse_args() - - # IoT Core MQTT 연결 객체 - conn = AwsMQTT() - - # Shadow에 디바이스 등록 - - # 시뮬레이션 실행, 콜백 함수 전달 - simulate_data( - count=args.count, - interval=args.interval, - space_id=args.space_id, - manufacture_id=args.manufacture_id, - sensor_num=args.sensor_num, - conn=conn, - simulator_type=args.simulator - ) + # for _ in range(count): + # data = simulator.start_publishing() + # # print(json.dumps(data, indent=4)) # 데이터를 JSON 형식으로 출력 + # time.sleep(interval) + thread = threading.Thread(target=run_simulator, args=(simulator, count, interval)) + threads.append(thread) + thread.start() -# 테스트용 메인 함수 (index.py에도 존재함) if __name__ == "__main__": - main() \ No newline at end of file + # JSON 파일 경로 + json_file_path = "C:/lgCns/finalPrj-factoreal/monitory-iot/service/simulation/simulation_cconfig.json" + run_simulation_from_json(json_file_path) \ No newline at end of file diff --git a/service/simulation/simulation_cconfig.json b/service/simulation/simulation_cconfig.json new file mode 100644 index 0000000..77c6367 --- /dev/null +++ b/service/simulation/simulation_cconfig.json @@ -0,0 +1,44 @@ +{ + "devices": [ + { + "count": 5, + "interval": 10.0, + "manufacture_id": "", + "space_id": "PID-789", + "simulator": "humidity", + "sensor_num": 2 + }, + { + "count": 5, + "interval": 10.0, + "manufacture_id": "SBID-124", + "space_id": "PID-800", + "simulator": "vibration", + "sensor_num": 2 + }, + { + "count": 0, + "interval": 0.0, + "manufacture_id": "", + "space_id": "PID-000", + "simulator": "temp", + "sensor_num": 0 + }, + { + "count": 0, + "interval": 0.0, + "manufacture_id": "", + "space_id": "PID-000", + "simulator": "current", + "sensor_num": 0 + }, + { + "count": 0, + "interval": 0.0, + "manufacture_id": "", + "space_id": "PID-000", + "simulator": "dust", + "sensor_num": 0 + } + ] +} \ No newline at end of file From ced015f0051761cc3644bbe973de4d44df8e2766 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B4=91=EB=B6=80=EC=9E=85=EB=8B=88=EB=8B=A4?= Date: Wed, 30 Apr 2025 09:20:19 +0900 Subject: [PATCH 06/15] =?UTF-8?q?fix=20|=20sprint1=20|=20FRB-121=20|=20jso?= =?UTF-8?q?n=20=EC=83=81=EB=8C=80=20=EA=B2=BD=EB=A1=9C=EB=A1=9C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=20|=20=EA=B9=80=EC=9A=B0=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- service/simulation/simulateTest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/service/simulation/simulateTest.py b/service/simulation/simulateTest.py index 275a70c..0895dea 100644 --- a/service/simulation/simulateTest.py +++ b/service/simulation/simulateTest.py @@ -65,5 +65,5 @@ def run_simulation_from_json(json_file_path): if __name__ == "__main__": # JSON 파일 경로 - json_file_path = "C:/lgCns/finalPrj-factoreal/monitory-iot/service/simulation/simulation_cconfig.json" + json_file_path = "service/simulation/simulation_cconfig.json" run_simulation_from_json(json_file_path) \ No newline at end of file From 239f62f291d28c8c19984af8a83f9cb16f6287c1 Mon Sep 17 00:00:00 2001 From: minnnseokk Date: Mon, 5 May 2025 16:45:50 +0900 Subject: [PATCH 07/15] =?UTF-8?q?fix=20|=20sprint1=20|=20FRB-121=20|=20?= =?UTF-8?q?=EC=8B=9C=EB=AE=AC=EB=A0=88=EC=9D=B4=ED=84=B0=20=EC=9E=91?= =?UTF-8?q?=EB=8F=99=20=EC=97=90=EB=9F=AC=20=EC=88=98=EC=A0=95=20|=20?= =?UTF-8?q?=EC=A0=95=EB=AF=BC=EC=84=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- service/simulation/HumiditySimulator.py | 4 +- service/simulation/TempSimulator.py | 6 +-- service/simulation/factory.py | 2 +- service/simulation/simulateTest.py | 2 +- service/simulation/simulation_cconfig.json | 46 +++++++--------------- 5 files changed, 22 insertions(+), 38 deletions(-) diff --git a/service/simulation/HumiditySimulator.py b/service/simulation/HumiditySimulator.py index ebf5cd3..295baf7 100644 --- a/service/simulation/HumiditySimulator.py +++ b/service/simulation/HumiditySimulator.py @@ -21,9 +21,9 @@ def __init__(self, idx: int, space_id:str, manufacture_id:str, interval:int = 5, self.sensor_id = f"UA10H-HUM-2406089{idx}" # 센서 ID self.type = "humid" # 센서 타입 # shadow 등록용 토픽 - self.shadow_regist_topic_name = f"$aws/things/sensor/shadow/name/{self.sensor_id}/update" + self.shadow_regist_topic_name = f"$aws/things/Sensor/shadow/name/{self.sensor_id}/update" # shadow 제어 명령 구독용 토픽 - self.shadow_desired_topic_name = f"$aws/things/sensor/shadow/name/{self.sensor_id}/update/desired" + self.shadow_desired_topic_name = f"$aws/things/Sensor/shadow/name/{self.sensor_id}/update/desired" # 센서 데이터 publish용 토픽 self.topic_name = f"sensor/{space_id}/{manufacture_id}/{self.sensor_id}/{self.type}" self.target_temperature = None # 초기값 설정(shadow 용) diff --git a/service/simulation/TempSimulator.py b/service/simulation/TempSimulator.py index 8637e53..010193c 100644 --- a/service/simulation/TempSimulator.py +++ b/service/simulation/TempSimulator.py @@ -1,7 +1,7 @@ from .SimulatorInterface2 import SimulatorInterface2 import random -class humidSimulator(SimulatorInterface2): +class TempSimulator(SimulatorInterface2): def __init__(self, idx: int, space_id:str, manufacture_id:str, interval:int = 5, msg_count:int = 10, conn=None): ######################################### # 시뮬레이터에서 공통적으로 사용하는 속성 @@ -22,10 +22,10 @@ def __init__(self, idx: int, space_id:str, manufacture_id:str, interval:int = 5, self.sensor_id = f"UA10T-TEM-2406089{idx}" # 센서 ID self.type = "temp" # 센서 타입 # shadow 등록용 토픽 - self.shadow_regist_topic_name = f"$aws/things/sensor/shadow/name/{self.sensor_id}/update" + self.shadow_regist_topic_name = f"$aws/things/Sensor/shadow/name/{self.sensor_id}/update" # shadow 제어 명령 구독용 토픽 - self.shadow_desired_topic_name = f"$aws/things/sensor/shadow/name/{self.sensor_id}/update/desired" + self.shadow_desired_topic_name = f"$aws/things/Sensor/shadow/name/{self.sensor_id}/update/desired" # 센서 데이터 publish용 토픽 self.topic_name = f"sensor/{space_id}/{manufacture_id}/{self.sensor_id}/{self.type}" diff --git a/service/simulation/factory.py b/service/simulation/factory.py index b3edd05..c43d969 100644 --- a/service/simulation/factory.py +++ b/service/simulation/factory.py @@ -1,4 +1,4 @@ -from service.simulation import TempSimulator +from service.simulation.TempSimulator import TempSimulator from service.simulation.HumiditySimulator import HumiditySimulator from service.simulation.VibrationSimulator import VibrationSimulator from service.simulation.CurrentSimulator import CurrentSimulator diff --git a/service/simulation/simulateTest.py b/service/simulation/simulateTest.py index 0895dea..adbe4f2 100644 --- a/service/simulation/simulateTest.py +++ b/service/simulation/simulateTest.py @@ -12,7 +12,7 @@ conn = AwsMQTT() -# 스레드에서 실행될 시뮬레이션 함수수 +# 스레드에서 실행될 시뮬레이션 함수 def run_simulator(simulator, count, interval): for _ in range(count): data = simulator.start_publishing() diff --git a/service/simulation/simulation_cconfig.json b/service/simulation/simulation_cconfig.json index 77c6367..ec0d4f3 100644 --- a/service/simulation/simulation_cconfig.json +++ b/service/simulation/simulation_cconfig.json @@ -1,44 +1,28 @@ { "devices": [ { - "count": 5, - "interval": 10.0, - "manufacture_id": "", - "space_id": "PID-789", - "simulator": "humidity", - "sensor_num": 2 - }, - { - "count": 5, + "count": 1, "interval": 10.0, "manufacture_id": "SBID-124", - "space_id": "PID-800", - "simulator": "vibration", - "sensor_num": 2 - }, - { - "count": 0, - "interval": 0.0, - "manufacture_id": "", - "space_id": "PID-000", + "space_id": "PID-711", "simulator": "temp", - "sensor_num": 0 + "sensor_num": 2 }, { - "count": 0, - "interval": 0.0, - "manufacture_id": "", - "space_id": "PID-000", - "simulator": "current", - "sensor_num": 0 + "count": 1, + "interval": 10.0, + "manufacture_id": "SBID-125", + "space_id": "PID-790", + "simulator": "humidity", + "sensor_num": 3 }, { - "count": 0, - "interval": 0.0, - "manufacture_id": "", - "space_id": "PID-000", - "simulator": "dust", - "sensor_num": 0 + "count": 1, + "interval": 10.0, + "manufacture_id": "SBID-126", + "space_id": "PID-791", + "simulator": "vibration", + "sensor_num": 4 } ] } \ No newline at end of file From a46058f67da25a908cd97cb140fd8ee45a631a08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B4=91=EB=B6=80=EC=9E=85=EB=8B=88=EB=8B=A4?= Date: Wed, 7 May 2025 10:03:44 +0900 Subject: [PATCH 08/15] =?UTF-8?q?fix=20|=20sprint1=20|=20FRB-121=20|=20?= =?UTF-8?q?=EC=8B=9C=EB=AE=AC=EB=A0=88=EC=9D=B4=ED=84=B0=20=EC=86=8D?= =?UTF-8?q?=EC=84=B1=EB=AA=85=20=EC=88=98=EC=A0=95=20(spaceId=20->=20zoneI?= =?UTF-8?q?d=20/=20manufactureId=20->=20equipId)=20|=20=EA=B9=80=EC=9A=B0?= =?UTF-8?q?=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- service/simulation/CurrentSimulator.py | 12 ++++++------ service/simulation/DustSimulator.py | 12 ++++++------ service/simulation/ExampleSimulator.py | 12 ++++++------ service/simulation/HumiditySimulator.py | 12 ++++++------ service/simulation/HumidityTempSimulator.py | 8 ++++---- service/simulation/SimulatorInterface2.py | 10 +++++----- service/simulation/TempSimulator.py | 12 ++++++------ service/simulation/VibrationSimulator.py | 12 ++++++------ service/simulation/VocSimulator.py | 12 ++++++------ service/simulation/factory.py | 18 +++++++++--------- service/simulation/simulateTest.py | 8 ++++---- service/simulation/simulation_cconfig.json | 12 ++++++------ 12 files changed, 70 insertions(+), 70 deletions(-) diff --git a/service/simulation/CurrentSimulator.py b/service/simulation/CurrentSimulator.py index 11418ae..cd03ef0 100644 --- a/service/simulation/CurrentSimulator.py +++ b/service/simulation/CurrentSimulator.py @@ -3,12 +3,12 @@ import random class CurrentSimulator(SimulatorInterface2): - def __init__(self, idx: int, space_id:str, manufacture_id:str, interval:int = 5, msg_count:int = 10, conn=None): + def __init__(self, idx: int, zone_id:str, equip_id:str, interval:int = 5, msg_count:int = 10, conn=None): # 시뮬레이터에서 공통적으로 사용하는 속성 super().__init__( idx=idx, - space_id=space_id, - manufacture_id=manufacture_id, + zone_id=zone_id, + equip_id=equip_id, interval=interval, msg_count=msg_count, conn=conn @@ -18,14 +18,14 @@ def __init__(self, idx: int, space_id:str, manufacture_id:str, interval:int = 5, self.type = "current" # 센서 타입 self.shadow_regist_topic_name = f"$aws/things/Sensor/shadow/name/{self.sensor_id}/update" self.shadow_desired_topic_name = f"$aws/things/Sensor/shadow/name/{self.sensor_id}/update/desired" - self.topic_name = f"sensor/{space_id}/{manufacture_id}/{self.sensor_id}/{self.type}" + self.topic_name = f"sensor/{zone_id}/{equip_id}/{self.sensor_id}/{self.type}" self.target_current = None # 초기값 설정(shadow 용) # 데이터 생성 로직 정의 def _generate_data(self) -> dict: return { - "zoneId": self.space_id, - "equipId": self.manufacture_id, + "zoneId": self.zone_id, + "equipId": self.equip_id, "sensorId": self.sensor_id, "sensorType": self.type, "val": round(random.uniform(0.1 + self.idx, 10.0 + self.idx), 2) diff --git a/service/simulation/DustSimulator.py b/service/simulation/DustSimulator.py index 8fe2ea3..c251839 100644 --- a/service/simulation/DustSimulator.py +++ b/service/simulation/DustSimulator.py @@ -2,12 +2,12 @@ import random class DustSimulator(SimulatorInterface2): - def __init__(self, idx: int, space_id:str, manufacture_id:str, interval:int = 5, msg_count:int = 10, conn=None): + def __init__(self, idx: int, zone_id:str, equip_id:str, interval:int = 5, msg_count:int = 10, conn=None): # 시뮬레이터에서 공통적으로 사용하는 속성 super().__init__( idx=idx, - space_id=space_id, - manufacture_id=manufacture_id, + zone_id=zone_id, + equip_id=equip_id, interval=interval, msg_count=msg_count, conn=conn @@ -17,14 +17,14 @@ def __init__(self, idx: int, space_id:str, manufacture_id:str, interval:int = 5, self.type = "dust" # 센서 타입 self.shadow_regist_topic_name = f"$aws/things/Sensor/shadow/name/{self.sensor_id}/update" self.shadow_desired_topic_name = f"$aws/things/Sensor/shadow/name/{self.sensor_id}/update/desired" - self.topic_name = f"sensor/{space_id}/{manufacture_id}/{self.sensor_id}/{self.type}" + self.topic_name = f"sensor/{zone_id}/{equip_id}/{self.sensor_id}/{self.type}" self.target_current = None # 초기값 설정(shadow 용) # 데이터 생성 로직 정의 def _generate_data(self) -> dict: return { - "zoneId": self.space_id, - "equipId": self.manufacture_id, + "zoneId": self.zone_id, + "equipId": self.equip_id, "sensorId": self.sensor_id, "sensorType": self.type, "val": round(random.uniform(5.0 + self.idx, 50.0 + self.idx), 2) diff --git a/service/simulation/ExampleSimulator.py b/service/simulation/ExampleSimulator.py index 6ff504a..ab43f7c 100644 --- a/service/simulation/ExampleSimulator.py +++ b/service/simulation/ExampleSimulator.py @@ -3,14 +3,14 @@ import random class ExampleSimulator(SimulatorInterface2): - def __init__(self, idx: int, space_id:str, manufacture_id:str, interval:int = 5, msg_count:int = 10, conn=None): + def __init__(self, idx: int, zone_id:str, equip_id:str, interval:int = 5, msg_count:int = 10, conn=None): ######################################### # 시뮬레이터에서 공통적으로 사용하는 속성 ######################################### super().__init__( idx=idx, - space_id=space_id, - manufacture_id=manufacture_id, + zone_id=zone_id, + equip_id=equip_id, interval=interval, msg_count=msg_count, conn=conn @@ -29,7 +29,7 @@ def __init__(self, idx: int, space_id:str, manufacture_id:str, interval:int = 5, self.shadow_desired_topic_name = f"$aws/things/KWYTEST/shadow/name/{self.sensor_id}/update/desired" # 센서 데이터 publish용 토픽 - self.topic_name = f"sensor/{space_id}/{manufacture_id}/{self.sensor_id}/{self.type}" + self.topic_name = f"sensor/{zone_id}/{equip_id}/{self.sensor_id}/{self.type}" self.target_temperature = None # 초기값 설정(shadow 용) @@ -39,8 +39,8 @@ def __init__(self, idx: int, space_id:str, manufacture_id:str, interval:int = 5, ################################################ def _generate_data(self) -> dict: return { - "zoneId": self.space_id, - "equipId": self.manufacture_id, + "zoneId": self.zone_id, + "equipId": self.equip_id, "sensorId": self.sensor_id, "sensorType": self.type, "val": round(random.uniform(20.0 + self.idx, 30.0 + self.idx), 2) diff --git a/service/simulation/HumiditySimulator.py b/service/simulation/HumiditySimulator.py index 295baf7..bf41a59 100644 --- a/service/simulation/HumiditySimulator.py +++ b/service/simulation/HumiditySimulator.py @@ -2,14 +2,14 @@ import random class HumiditySimulator(SimulatorInterface2): - def __init__(self, idx: int, space_id:str, manufacture_id:str, interval:int = 5, msg_count:int = 10, conn=None): + def __init__(self, idx: int, zone_id:str, equip_id:str, interval:int = 5, msg_count:int = 10, conn=None): ######################################### # 시뮬레이터에서 공통적으로 사용하는 속성 ######################################### super().__init__( idx=idx, - space_id=space_id, - manufacture_id=manufacture_id, + zone_id=zone_id, + equip_id=equip_id, interval=interval, msg_count=msg_count, conn=conn @@ -25,7 +25,7 @@ def __init__(self, idx: int, space_id:str, manufacture_id:str, interval:int = 5, # shadow 제어 명령 구독용 토픽 self.shadow_desired_topic_name = f"$aws/things/Sensor/shadow/name/{self.sensor_id}/update/desired" # 센서 데이터 publish용 토픽 - self.topic_name = f"sensor/{space_id}/{manufacture_id}/{self.sensor_id}/{self.type}" + self.topic_name = f"sensor/{zone_id}/{equip_id}/{self.sensor_id}/{self.type}" self.target_temperature = None # 초기값 설정(shadow 용) ################################################z @@ -35,8 +35,8 @@ def __init__(self, idx: int, space_id:str, manufacture_id:str, interval:int = 5, def _generate_data(self) -> dict: """ 데이터 생성 메서드 """ return { - "zoneId": self.space_id, - "equipId": self.manufacture_id, + "zoneId": self.zone_id, + "equipId": self.equip_id, "sensorId": self.sensor_id, "sensorType": self.type, "val": round(random.uniform(20.0 + self.idx, 80.0 + self.idx), 2) diff --git a/service/simulation/HumidityTempSimulator.py b/service/simulation/HumidityTempSimulator.py index bf41313..a8682fb 100644 --- a/service/simulation/HumidityTempSimulator.py +++ b/service/simulation/HumidityTempSimulator.py @@ -2,14 +2,14 @@ import random class humidTempSimulator(SimulatorInterface2): - def __init__(self, idx: int, space_id:str, manufacture_id:str, interval:int = 5, msg_count:int = 10, conn=None): + def __init__(self, idx: int, zone_id:str, equip_id:str, interval:int = 5, msg_count:int = 10, conn=None): ######################################### # 시뮬레이터에서 공통적으로 사용하는 속성 ######################################### super().__init__( idx=idx, - space_id=space_id, - manufacture_id=manufacture_id, + zone_id=zone_id, + equip_id=equip_id, interval=interval, msg_count=msg_count, conn=conn @@ -25,7 +25,7 @@ def __init__(self, idx: int, space_id:str, manufacture_id:str, interval:int = 5, # shadow 제어 명령 구독용 토픽 self.shadow_desired_topic_name = f"$aws/things/KWYTEST/shadow/name/{self.sensor_id}/update/desired" # 센서 데이터 publish용 토픽 - self.topic_name = f"sensor/{space_id}/{manufacture_id}/{self.sensor_id}/{self.type}" + self.topic_name = f"sensor/{zone_id}/{equip_id}/{self.sensor_id}/{self.type}" self.target_temperature = None # 초기값 설정(shadow 용) ################################################ diff --git a/service/simulation/SimulatorInterface2.py b/service/simulation/SimulatorInterface2.py index aaa8d3c..15dd360 100644 --- a/service/simulation/SimulatorInterface2.py +++ b/service/simulation/SimulatorInterface2.py @@ -6,10 +6,10 @@ import time class SimulatorInterface2(ABC): - def __init__(self, idx: int, space_id: str, manufacture_id: str, interval: int, msg_count: int, conn:AwsMQTT=None): # 센서 idx를 받기 + def __init__(self, idx: int, zone_id: str, equip_id: str, interval: int, msg_count: int, conn:AwsMQTT=None): # 센서 idx를 받기 self.idx = idx # 센서 번호 - self.space_id = space_id # 공간 ID - self.manufacture_id = manufacture_id # 설비 ID + self.zone_id = zone_id # 공간 ID + self.equip_id = equip_id # 설비 ID self.interval = interval # publish 주기 self.msg_count = msg_count # publish 횟수 self.conn = conn # 시뮬레이터 별로 생성된 MQTT 연결 객체를 singleton으로 사용하기 위함 @@ -73,8 +73,8 @@ def _update_shadow(self, status: str = "ON"): "state": { "reported": { "sensorId": self.sensor_id, - "spaceId": self.space_id, - "manufactureId": self.manufacture_id, + "equip_id": self.zone_id, + "equip_id": self.equip_id, "type": self.type, "status": status, } diff --git a/service/simulation/TempSimulator.py b/service/simulation/TempSimulator.py index 010193c..53cdb4a 100644 --- a/service/simulation/TempSimulator.py +++ b/service/simulation/TempSimulator.py @@ -2,14 +2,14 @@ import random class TempSimulator(SimulatorInterface2): - def __init__(self, idx: int, space_id:str, manufacture_id:str, interval:int = 5, msg_count:int = 10, conn=None): + def __init__(self, idx: int, zone_id:str, equip_id:str, interval:int = 5, msg_count:int = 10, conn=None): ######################################### # 시뮬레이터에서 공통적으로 사용하는 속성 ######################################### super().__init__( idx=idx, - space_id=space_id, - manufacture_id=manufacture_id, + zone_id=zone_id, + equip_id=equip_id, interval=interval, msg_count=msg_count, conn=conn @@ -28,7 +28,7 @@ def __init__(self, idx: int, space_id:str, manufacture_id:str, interval:int = 5, self.shadow_desired_topic_name = f"$aws/things/Sensor/shadow/name/{self.sensor_id}/update/desired" # 센서 데이터 publish용 토픽 - self.topic_name = f"sensor/{space_id}/{manufacture_id}/{self.sensor_id}/{self.type}" + self.topic_name = f"sensor/{zone_id}/{equip_id}/{self.sensor_id}/{self.type}" self.target_temperature = None # 초기값 설정(shadow 용) @@ -39,8 +39,8 @@ def __init__(self, idx: int, space_id:str, manufacture_id:str, interval:int = 5, def _generate_data(self) -> dict: """ 데이터 생성 메서드 """ return { - "zoneId": self.space_id, - "equipId": self.manufacture_id, + "zoneId": self.zone_id, + "equipId": self.equip_id, "sensorId": self.sensor_id, "sensorType": self.type, "val": round(random.uniform(20.0 + self.idx, 80.0 + self.idx), 2) diff --git a/service/simulation/VibrationSimulator.py b/service/simulation/VibrationSimulator.py index 1723700..ec274c6 100644 --- a/service/simulation/VibrationSimulator.py +++ b/service/simulation/VibrationSimulator.py @@ -3,12 +3,12 @@ import random class VibrationSimulator(SimulatorInterface2): - def __init__(self, idx: int, space_id:str, manufacture_id:str, interval:int = 5, msg_count:int = 10, conn=None): + def __init__(self, idx: int, zone_id:str, equip_id:str, interval:int = 5, msg_count:int = 10, conn=None): # 시뮬레이터에서 공통적으로 사용하는 속성 super().__init__( idx=idx, - space_id=space_id, - manufacture_id=manufacture_id, + zone_id=zone_id, + equip_id=equip_id, interval=interval, msg_count=msg_count, conn=conn @@ -18,14 +18,14 @@ def __init__(self, idx: int, space_id:str, manufacture_id:str, interval:int = 5, self.type = "vibration" # Sensor type self.shadow_regist_topic_name = f"$aws/things/Sensor/shadow/name/{self.sensor_id}/update" self.shadow_desired_topic_name = f"$aws/things/Sensor/shadow/name/{self.sensor_id}/update/desired" - self.topic_name = f"sensor/{space_id}/{manufacture_id}/{self.sensor_id}/{self.type}" + self.topic_name = f"sensor/{zone_id}/{equip_id}/{self.sensor_id}/{self.type}" self.target_vibration = None # Initial value for shadow) # 데이터 생성 로직을 정의 (시뮬레이터 마다 다르게 구현) def _generate_data(self) -> dict: return { - "zoneId": self.space_id, - "equipId": self.manufacture_id, + "zoneId": self.zone_id, + "equipId": self.equip_id, "sensorId": self.sensor_id, "sensorType": self.type, "val": round(random.uniform(0.1 + self.idx, 10.0 + self.idx), 2) diff --git a/service/simulation/VocSimulator.py b/service/simulation/VocSimulator.py index a2978de..ebab0c3 100644 --- a/service/simulation/VocSimulator.py +++ b/service/simulation/VocSimulator.py @@ -2,12 +2,12 @@ import random class VocSimulator(SimulatorInterface2): - def __init__(self, idx: int, space_id:str, manufacture_id:str, interval:int = 5, msg_count:int = 10, conn=None): + def __init__(self, idx: int, zone_id:str, equip_id:str, interval:int = 5, msg_count:int = 10, conn=None): # 시뮬레이터에서 공통적으로 사용하는 속성 super().__init__( idx=idx, - space_id=space_id, - manufacture_id=manufacture_id, + zone_id=zone_id, + equip_id=equip_id, interval=interval, msg_count=msg_count, conn=conn @@ -17,14 +17,14 @@ def __init__(self, idx: int, space_id:str, manufacture_id:str, interval:int = 5, self.type = "voc" # 센서 타입 self.shadow_regist_topic_name = f"$aws/things/Sensor/shadow/name/{self.sensor_id}/update" self.shadow_desired_topic_name = f"$aws/things/Sensor/shadow/name/{self.sensor_id}/update/desired" - self.topic_name = f"sensor/{space_id}/{manufacture_id}/{self.sensor_id}/{self.type}" + self.topic_name = f"sensor/{zone_id}/{equip_id}/{self.sensor_id}/{self.type}" self.target_current = None # 초기값 설정(shadow 용) # 데이터 생성 로직 정의 def _generate_data(self) -> dict: return { - "zoneId": self.space_id, - "equipId": self.manufacture_id, + "zoneId": self.zone_id, + "equipId": self.equip_id, "sensorId": self.sensor_id, "sensorType": self.type, "val": round(random.uniform(5.0 + self.idx, 50.0 + self.idx), 2) diff --git a/service/simulation/factory.py b/service/simulation/factory.py index c43d969..0173a60 100644 --- a/service/simulation/factory.py +++ b/service/simulation/factory.py @@ -9,26 +9,26 @@ from typing import List # from .SimulatorInterface import SimulatorInterface from .SimulatorInterface2 import SimulatorInterface2 -def get_simulator(simulator_type: str, idx: int, space_id: str, manufacture_id: str, interval: int = 5, msg_count: int = 10, conn:AwsMQTT=None)-> List[SimulatorInterface2]: +def get_simulator(simulator_type: str, idx: int, zone_id: str, equip_id: str, interval: int = 5, msg_count: int = 10, conn:AwsMQTT=None)-> List[SimulatorInterface2]: simulator_entity_list = [] for i in range(idx): if simulator_type == "temp": - simulator_entity_list.append(TempSimulator(i, space_id, manufacture_id, interval, msg_count, conn)) + simulator_entity_list.append(TempSimulator(i, zone_id, equip_id, interval, msg_count, conn)) elif simulator_type == "humidity": - simulator_entity_list.append(HumiditySimulator(i, space_id, manufacture_id, interval, msg_count, conn)) + simulator_entity_list.append(HumiditySimulator(i, zone_id, equip_id, interval, msg_count, conn)) # elif simulator_type == "humidity_temp": - # simulator_entity_list.append(HumidityTempSimulator(i, space_id, manufacture_id, interval, msg_count, conn)) + # simulator_entity_list.append(HumidityTempSimulator(i, zone_id, equip_id, interval, msg_count, conn)) elif simulator_type == "vibration": - simulator_entity_list.append(VibrationSimulator(i, space_id, manufacture_id, interval, msg_count, conn)) + simulator_entity_list.append(VibrationSimulator(i, zone_id, equip_id, interval, msg_count, conn)) elif simulator_type == "current": - simulator_entity_list.append(CurrentSimulator(i, space_id, manufacture_id, interval, msg_count, conn)) + simulator_entity_list.append(CurrentSimulator(i, zone_id, equip_id, interval, msg_count, conn)) elif simulator_type == "dust": - simulator_entity_list.append(DustSimulator(i, space_id, manufacture_id, interval, msg_count, conn)) + simulator_entity_list.append(DustSimulator(i, zone_id, equip_id, interval, msg_count, conn)) elif simulator_type == "example": - simulator_entity_list.append(ExampleSimulator(i, space_id, manufacture_id, interval, msg_count, conn)) + simulator_entity_list.append(ExampleSimulator(i, zone_id, equip_id, interval, msg_count, conn)) elif simulator_type == "voc": - simulator_entity_list.append(VocSimulator(i, space_id, manufacture_id, interval, msg_count, conn)) + simulator_entity_list.append(VocSimulator(i, zone_id, equip_id, interval, msg_count, conn)) else: raise ValueError(f"Unknown simulator type: {simulator_type}") return simulator_entity_list \ No newline at end of file diff --git a/service/simulation/simulateTest.py b/service/simulation/simulateTest.py index adbe4f2..bc5b2aa 100644 --- a/service/simulation/simulateTest.py +++ b/service/simulation/simulateTest.py @@ -35,8 +35,8 @@ def run_simulation_from_json(json_file_path): for device in devices: count = device.get("count", 10) interval = device.get("interval", 1.0) - manufacture_id = device.get("manufacture_id", "UNKNOWN") - space_id = device.get("space_id", "UNKNOWN") + equip_id = device.get("equip_id", "UNKNOWN") + zone_id = device.get("zone_id", "UNKNOWN") simulator_type = device.get("simulator", "temp") sensor_num = device.get("sensor_num", 1) @@ -47,8 +47,8 @@ def run_simulation_from_json(json_file_path): conn = conn, simulator_type=simulator_type, idx=sensor_num, - space_id=space_id, - manufacture_id=manufacture_id, + zone_id=zone_id, + equip_id=equip_id, interval=interval, msg_count=count ) diff --git a/service/simulation/simulation_cconfig.json b/service/simulation/simulation_cconfig.json index ec0d4f3..1890c2c 100644 --- a/service/simulation/simulation_cconfig.json +++ b/service/simulation/simulation_cconfig.json @@ -3,24 +3,24 @@ { "count": 1, "interval": 10.0, - "manufacture_id": "SBID-124", - "space_id": "PID-711", + "equip_id": "SBID-124", + "zone_id": "PID-711", "simulator": "temp", "sensor_num": 2 }, { "count": 1, "interval": 10.0, - "manufacture_id": "SBID-125", - "space_id": "PID-790", + "equip_id": "SBID-125", + "zone_id": "PID-790", "simulator": "humidity", "sensor_num": 3 }, { "count": 1, "interval": 10.0, - "manufacture_id": "SBID-126", - "space_id": "PID-791", + "equip_id": "SBID-126", + "zone_id": "PID-791", "simulator": "vibration", "sensor_num": 4 } From 958275614e1861570f47a56d922fdb03c39e9099 Mon Sep 17 00:00:00 2001 From: minnnseokk Date: Wed, 7 May 2025 13:53:47 +0900 Subject: [PATCH 09/15] =?UTF-8?q?fix=20|=20sprint1=20|=20FRB-121=20|=20spa?= =?UTF-8?q?ceId=20=ED=95=9C=EA=B8=80=20=ED=97=88=EC=9A=A9=20|=20=EC=A0=95?= =?UTF-8?q?=EB=AF=BC=EC=84=9D=EC=84=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- service/simulation/simulateTest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/service/simulation/simulateTest.py b/service/simulation/simulateTest.py index adbe4f2..549f6fa 100644 --- a/service/simulation/simulateTest.py +++ b/service/simulation/simulateTest.py @@ -22,7 +22,7 @@ def run_simulator(simulator, count, interval): # 시뮬레이션 함수 def run_simulation_from_json(json_file_path): # JSON 파일 읽기 - with open(json_file_path, 'r') as file: + with open(json_file_path, 'r', encoding="utf-8") as file: config = json.load(file) devices = config.get("devices", []) From 46e27f250124cf8d7448508f4b0306d3c53f4a27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B4=91=EB=B6=80=EC=9E=85=EB=8B=88=EB=8B=A4?= Date: Wed, 7 May 2025 14:05:48 +0900 Subject: [PATCH 10/15] =?UTF-8?q?fix=20|=20sprint1=20|=20FRB-121=20|=20Sha?= =?UTF-8?q?dow=20payload=EC=9D=98=20=EC=86=8D=EC=84=B1=EB=AA=85=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20|=20=EA=B9=80=EC=9A=B0=EC=98=81=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- service/simulation/SimulatorInterface2.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/service/simulation/SimulatorInterface2.py b/service/simulation/SimulatorInterface2.py index 15dd360..6cf8c25 100644 --- a/service/simulation/SimulatorInterface2.py +++ b/service/simulation/SimulatorInterface2.py @@ -73,7 +73,7 @@ def _update_shadow(self, status: str = "ON"): "state": { "reported": { "sensorId": self.sensor_id, - "equip_id": self.zone_id, + "zone_id": self.zone_id, "equip_id": self.equip_id, "type": self.type, "status": status, From 02b8fd20c8f5549fa1437e2b26ff290cb46a0114 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B4=91=EB=B6=80=EC=9E=85=EB=8B=88=EB=8B=A4?= Date: Wed, 7 May 2025 14:05:48 +0900 Subject: [PATCH 11/15] fix | --- service/simulation/SimulatorInterface2.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/service/simulation/SimulatorInterface2.py b/service/simulation/SimulatorInterface2.py index 15dd360..6cf8c25 100644 --- a/service/simulation/SimulatorInterface2.py +++ b/service/simulation/SimulatorInterface2.py @@ -73,7 +73,7 @@ def _update_shadow(self, status: str = "ON"): "state": { "reported": { "sensorId": self.sensor_id, - "equip_id": self.zone_id, + "zone_id": self.zone_id, "equip_id": self.equip_id, "type": self.type, "status": status, From 4a3850cd2dbaa4e13b0f4f88c3f97875054491a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B4=91=EB=B6=80=EC=9E=85=EB=8B=88=EB=8B=A4?= Date: Tue, 13 May 2025 15:30:38 +0900 Subject: [PATCH 12/15] =?UTF-8?q?feat=20|=20sprint2=20|=20FRB-148=20|=20st?= =?UTF-8?q?reamlit=20=EA=B8=B0=EB=B0=98=20=EC=8B=9C=EB=AE=AC=EB=A0=88?= =?UTF-8?q?=EC=9D=B4=ED=84=B0=20UI=20=EC=B6=94=EA=B0=80=20|=20=EA=B9=80?= =?UTF-8?q?=EC=9A=B0=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .dockerignore | 14 ++ Dockerfile | 21 +++ requirements.txt | Bin 1124 -> 999 bytes service/simulation/simulateTest.py | 16 ++ ...on_cconfig.json => simulation_cconfig.json | 0 simulation_config.db | Bin 0 -> 12288 bytes streamlit_app/app.py | 178 ++++++++++++++++++ 7 files changed, 229 insertions(+) create mode 100644 .dockerignore create mode 100644 Dockerfile rename service/simulation/simulation_cconfig.json => simulation_cconfig.json (100%) create mode 100644 simulation_config.db create mode 100644 streamlit_app/app.py diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..d48ad4e --- /dev/null +++ b/.dockerignore @@ -0,0 +1,14 @@ +# Ignore Python cache files +*.pyc +__pycache__/ + +# Ignore environment files +.env + +# Ignore virtual environments +venv/ +.venv/ + +# Ignore other unnecessary files +*.log +*.tmp \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..71a8081 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,21 @@ +# Base image +FROM python:3.13.3 + +# Set the working directory +WORKDIR /app + +# Copy requirements file +COPY requirements.txt . + +# Install dependencies +RUN pip install wheel setuptools +RUN python -m pip install --upgrade pip +RUN pip install --no-cache-dir -r requirements.txt +# Copy the application code +COPY . . + +# Expose the port Streamlit runs on +EXPOSE 8501 + +# Command to run the Streamlit app +CMD ["streamlit", "run", "streamlit_app/app.py", "--server.port=8501", "--server.address=0.0.0.0"] \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 5481d1577bbce60ff18d4f1262d38e0b431a071b..c9a0bf497595102b940be3dbb2ef63de69788014 100644 GIT binary patch literal 999 zcmYLI!EW0y487}LBG|H%CI=sO8ZfLtft_|57+GnQ$dW42P2I2Gqmy+GWabF2b_Ut&N06YOV%DTe-*RsmtVQCO!)( zj8d1HVuc988!L(8|5KZqorM~f*rV)AlvZ8+4KU&Tu5^#}pQ&8u{EJRd7gMnBM4Ut7 z;K5sn0c~39Ti8IE=q#tQ$&V!t+5mWcg{CgTV3?_&RHSk{li2gHFwT=GDz96W$zJKz z$5$l8k4$kSp^4W{WgkMip%bS8>|EgfaXt;hPItmDFI0*Y7zhmbyo^rl6hlzHWZ1sW z?(XB3>WZfz%K&<1z8Q(#%pOT2_oj2IER)2W%|D0R)dwU$1q)|o)XVbw+w)JMB20=q zx#FT-(Hh^(1hP7hk&mLRTO_h09?*v XtGNWY-H8~&@J4LUV}d)fW~2TBJsK+G literal 1124 zcmZuw%}&B#5S+7#j{>1Z5Dp%^YvR>oEufYDNs9;%ug>iDYcUu?6PTUdnc3~ncY*^N zq}ZXw9X}I{5#xr>2-moR;~AchVniZi#WF9<+71=G( z5}!T3TRtaU)t(j7Ft}9Sj%H+4^fc%1$oNW7J{^CjyESWS zdTjA#6^@2oZJE)5U-ikUGk8&zw0K_1sAU&r*7BKgKXN>^Y0~443ntRwgB2qtBY!13 zrsQZ(Bg;`bgov*+q}bICY~P)d^9%F47&8~$M#(&iekTE&878ONd4gA}Ecw)&n3;wt zswjDP36(nL8vHtIvU2lzFf_6>Jyp%tC8)!W?4iGMP)+Ee6qIDf%G~;>A}Bo4m1i(A z9l8;1S(AezC8JzxX4Me$gf#t}`}e-IvtjpMd+It)x(xj7dSahv+~W}shR?fcjyCks xQoV9&u<38Y_bi{TMhScw-zN`O+v3zY^LHyI!*}2lbk9mzcjRxly6WD%^Dm9kp^N|k diff --git a/service/simulation/simulateTest.py b/service/simulation/simulateTest.py index adbe4f2..074ebfe 100644 --- a/service/simulation/simulateTest.py +++ b/service/simulation/simulateTest.py @@ -18,7 +18,23 @@ def run_simulator(simulator, count, interval): data = simulator.start_publishing() print(json.dumps(data, indent=4)) # 데이터를 JSON 형식으로 출력 time.sleep(interval) + +def run_simulator_from_streamlit(simulator_type, count, interval, sensor_num, space_id, manufacture_id): + simulators = get_simulator( + conn=AwsMQTT(), + simulator_type=simulator_type, + idx=sensor_num, + space_id=space_id, + manufacture_id=manufacture_id, + interval=interval, + msg_count=count + ) + for simulator in simulators: + for _ in range(count): + data = simulator.start_publishing() + print(json.dumps(data, indent=4)) # 데이터를 JSON 형식으로 출력 + time.sleep(interval) # 시뮬레이션 함수 def run_simulation_from_json(json_file_path): # JSON 파일 읽기 diff --git a/service/simulation/simulation_cconfig.json b/simulation_cconfig.json similarity index 100% rename from service/simulation/simulation_cconfig.json rename to simulation_cconfig.json diff --git a/simulation_config.db b/simulation_config.db new file mode 100644 index 0000000000000000000000000000000000000000..d419dc72355c8a7c12a1dfffdc70838820ca1e63 GIT binary patch literal 12288 zcmeI%K}*9h6bJBR69vWLZJ?KT+}QBq7qCi@;WlTj;7%iU85G*owdp>9h<87uU&Pn3 ziXDpg@qdtpG=y8DUyjS0&Y_BI``H(lPPghxMsM+hUyfkN^Mx literal 0 HcmV?d00001 diff --git a/streamlit_app/app.py b/streamlit_app/app.py new file mode 100644 index 0000000..accf9c8 --- /dev/null +++ b/streamlit_app/app.py @@ -0,0 +1,178 @@ +import sys +import os +import streamlit as st +import json +import sqlite3 +import threading +import time + +# 프로젝트 루트 디렉터리를 sys.path에 추가 +sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) + +from service.simulation.simulateTest import run_simulator_from_streamlit + +# Filepath for the JSON configuration +JSON_FILE_PATH = "./simulation_cconfig.json" +DB_FILE_PATH = "./simulation_config.db" + +# Thread management +simulation_threads = {} +stop_events = {} + +# Load JSON data +def load_json(): + if os.path.exists(JSON_FILE_PATH): + with open(JSON_FILE_PATH, "r") as file: + try: + return json.load(file) + except json.JSONDecodeError as e: + st.error(f"Error loading JSON: {e}") + return {"devices": []} + return {"devices": []} + +# Save JSON data +def save_json(data): + with open(JSON_FILE_PATH, "w") as file: + json.dump(data, file, indent=4) + +# Initialize SQLite database +def init_db(): + conn = sqlite3.connect(DB_FILE_PATH) + cursor = conn.cursor() + cursor.execute(""" + CREATE TABLE IF NOT EXISTS devices ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + count INTEGER, + interval REAL, + manufacture_id TEXT, + space_id TEXT, + simulator TEXT, + sensor_num INTEGER + ) + """) + conn.commit() + conn.close() + +# Save data to SQLite +def save_to_db(data): + conn = sqlite3.connect(DB_FILE_PATH) + cursor = conn.cursor() + cursor.execute("DELETE FROM devices") # Clear existing data + for device in data["devices"]: + cursor.execute(""" + INSERT INTO devices (count, interval, manufacture_id, space_id, simulator, sensor_num) + VALUES (?, ?, ?, ?, ?, ?) + """, (device["count"], device["interval"], device["manufacture_id"], device["space_id"], device["simulator"], device["sensor_num"])) + conn.commit() + conn.close() + +# Load data from SQLite +def load_from_db(): + conn = sqlite3.connect(DB_FILE_PATH) + cursor = conn.cursor() + cursor.execute("SELECT count, interval, manufacture_id, space_id, simulator, sensor_num FROM devices") + rows = cursor.fetchall() + conn.close() + return {"devices": [dict(zip(["count", "interval", "manufacture_id", "space_id", "simulator", "sensor_num"], row)) for row in rows]} + +# Function to run simulation with stop functionality +def run_simulation_with_stop(simulator_type, count, interval, sensor_num, space_id, manufacture_id, stop_event): + for _ in range(count): + if stop_event.is_set(): # Stop 이벤트가 설정되었는지 확인 + print(f"Stopping simulation for {simulator_type}") + break + run_simulator_from_streamlit(simulator_type, count, interval, sensor_num, space_id, manufacture_id) + time.sleep(interval) # 시뮬레이션 간격 + +# Streamlit app +def main(): + st.title("Simulation Configuration Manager") + + # Initialize session state for data + if "data" not in st.session_state: + st.session_state.data = load_json() + + # Sidebar options to load data + if st.sidebar.button("Load from JSON"): + st.session_state.data = load_json() + st.success("Loaded data from JSON.") + st.rerun() + elif st.sidebar.button("Load from SQLite"): + st.session_state.data = load_from_db() + st.success("Loaded data from SQLite.") + st.rerun() + + # Display devices in blocks + st.header("Devices") + if "devices" in st.session_state.data and st.session_state.data["devices"]: + for i, device in enumerate(st.session_state.data["devices"]): + with st.expander(f"Device {i + 1}"): + st.subheader(f"Device {i + 1} Details") + device["count"] = st.number_input(f"Count (Device {i + 1})", value=device["count"], key=f"count_{i}") + device["interval"] = st.number_input(f"Interval (Device {i + 1})", value=device["interval"], key=f"interval_{i}") + device["manufacture_id"] = st.text_input(f"Manufacture ID (Device {i + 1})", value=device["manufacture_id"], key=f"manufacture_id_{i}") + device["space_id"] = st.text_input(f"Space ID (Device {i + 1})", value=device["space_id"], key=f"space_id_{i}") + device["simulator"] = st.text_input(f"Simulator (Device {i + 1})", value=device["simulator"], key=f"simulator_{i}") + device["sensor_num"] = st.number_input(f"Sensor Num (Device {i + 1})", value=device["sensor_num"], key=f"sensor_num_{i}") + + # Run Simulation Button + if st.button(f"Run Simulation for Device {i + 1}", key=f"run_{i}"): + if i not in simulation_threads or not simulation_threads[i].is_alive(): + stop_events[i] = threading.Event() + st.write(f"Starting simulation for Device {i + 1} with stop_event: {stop_events[i]}") # 디버깅 출력 + thread = threading.Thread(target=run_simulation_with_stop, args=( + device["simulator"], + device["count"], + device["interval"], + device["sensor_num"], + device["space_id"], + device["manufacture_id"], + stop_events[i] + )) + simulation_threads[i] = thread + thread.start() + st.success(f"Simulation for Device {i + 1} started.") + else: + st.warning(f"Simulation for Device {i + 1} is already running.") + + # Stop Simulation Button + if st.button(f"Stop Simulation for Device {i + 1}", key=f"stop_{i}"): + if i in stop_events: + stop_events[i].set() # Stop 이벤트 설정 + st.write(f"Stopping simulation for Device {i + 1} with stop_event: {stop_events[i]}") # 디버깅 출력 + st.success(f"Simulation for Device {i + 1} stopped.") + else: + st.warning(f"No simulation is running for Device {i + 1}.") + + # Delete Device Button + if st.button(f"Delete Device {i + 1}", key=f"delete_{i}"): + st.session_state.data["devices"].pop(i) + st.rerun() + else: + st.write("No devices found. Please load data or add a new device.") + + # Add new device + st.header("Add New Device") + if st.button("Add Device"): + st.session_state.data["devices"].append({ + "count": 1, + "interval": 1.0, + "manufacture_id": "NEW_ID", + "space_id": "NEW_SPACE", + "simulator": "temp", + "sensor_num": 1 + }) + st.rerun() + + # Save options + st.sidebar.header("Save Options") + if st.sidebar.button("Save to JSON"): + save_json(st.session_state.data) + st.success("Saved data to JSON.") + if st.sidebar.button("Save to SQLite"): + save_to_db(st.session_state.data) + st.success("Saved data to SQLite.") + +if __name__ == "__main__": + init_db() + main() \ No newline at end of file From 37074346b6651faa407b45f9b7fdfeaf121303c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B4=91=EB=B6=80=EC=9E=85=EB=8B=88=EB=8B=A4?= Date: Tue, 13 May 2025 16:06:35 +0900 Subject: [PATCH 13/15] =?UTF-8?q?fix=20|=20sprint1=20|=20FRB-32=20|=20?= =?UTF-8?q?=EC=8B=9C=EB=AE=AC=EB=A0=88=EC=9D=B4=ED=84=B0=20=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=84=B0=20=EB=9E=9C=EB=8D=A4=20=EC=83=9D=EC=84=B1=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95=20|=20=EA=B9=80?= =?UTF-8?q?=EC=9A=B0=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- service/simulation/CurrentSimulator.py | 14 +++++++++++--- service/simulation/DustSimulator.py | 11 ++++++++++- service/simulation/HumiditySimulator.py | 2 +- service/simulation/SimulatorInterface2.py | 15 ++++++++++++++- service/simulation/TempSimulator.py | 15 ++++++++++++++- service/simulation/VibrationSimulator.py | 15 +++++++++++++-- 6 files changed, 63 insertions(+), 9 deletions(-) diff --git a/service/simulation/CurrentSimulator.py b/service/simulation/CurrentSimulator.py index cd03ef0..ff63f5d 100644 --- a/service/simulation/CurrentSimulator.py +++ b/service/simulation/CurrentSimulator.py @@ -1,6 +1,6 @@ from .SimulatorInterface2 import SimulatorInterface2 from simulate_type.simulate_list import generate_current_data -import random +from scipy.stats import truncnorm class CurrentSimulator(SimulatorInterface2): def __init__(self, idx: int, zone_id:str, equip_id:str, interval:int = 5, msg_count:int = 10, conn=None): @@ -20,7 +20,14 @@ def __init__(self, idx: int, zone_id:str, equip_id:str, interval:int = 5, msg_co self.shadow_desired_topic_name = f"$aws/things/Sensor/shadow/name/{self.sensor_id}/update/desired" self.topic_name = f"sensor/{zone_id}/{equip_id}/{self.sensor_id}/{self.type}" self.target_current = None # 초기값 설정(shadow 용) - + self.mu = 62.51 + self.sigma = 33.76 + lower = 0 + upper = self.mu + 3 * self.sigma + self.a = (lower - self.mu) / self.sigma + self.b = (upper - self.mu) / self.sigma + + # 데이터 생성 로직 정의 def _generate_data(self) -> dict: return { @@ -28,7 +35,8 @@ def _generate_data(self) -> dict: "equipId": self.equip_id, "sensorId": self.sensor_id, "sensorType": self.type, - "val": round(random.uniform(0.1 + self.idx, 10.0 + self.idx), 2) + # "val": round(random.uniform(0.1 + self.idx, 10.0 + self.idx), 2) + "val": round(truncnorm.rvs(self.a, self.b, loc=self.mu, scale=self.sigma), 2) # 0: 7, 1: 7이상, 2: 30 이상 최소값은 0 } ################################################ diff --git a/service/simulation/DustSimulator.py b/service/simulation/DustSimulator.py index c251839..18f9fb8 100644 --- a/service/simulation/DustSimulator.py +++ b/service/simulation/DustSimulator.py @@ -1,5 +1,6 @@ from .SimulatorInterface2 import SimulatorInterface2 import random +from scipy.stats import truncnorm class DustSimulator(SimulatorInterface2): def __init__(self, idx: int, zone_id:str, equip_id:str, interval:int = 5, msg_count:int = 10, conn=None): @@ -19,6 +20,14 @@ def __init__(self, idx: int, zone_id:str, equip_id:str, interval:int = 5, msg_co self.shadow_desired_topic_name = f"$aws/things/Sensor/shadow/name/{self.sensor_id}/update/desired" self.topic_name = f"sensor/{zone_id}/{equip_id}/{self.sensor_id}/{self.type}" self.target_current = None # 초기값 설정(shadow 용) + + self.mu = 180 # 평균 미세먼지 수치 + self.sigma = 60 # 표준편차 + self.lower = 0 + self.upper = self.mu + 3 * self.sigma + + self.a = (self.lower - self.mu) / self.sigma + self.b = (self.upper - self.mu) / self.sigma # 데이터 생성 로직 정의 def _generate_data(self) -> dict: @@ -27,7 +36,7 @@ def _generate_data(self) -> dict: "equipId": self.equip_id, "sensorId": self.sensor_id, "sensorType": self.type, - "val": round(random.uniform(5.0 + self.idx, 50.0 + self.idx), 2) + "val": round(truncnorm.rvs(self.a, self.b, loc=self.mu, scale=self.sigma), 2) } ################################################ diff --git a/service/simulation/HumiditySimulator.py b/service/simulation/HumiditySimulator.py index bf41a59..49ad278 100644 --- a/service/simulation/HumiditySimulator.py +++ b/service/simulation/HumiditySimulator.py @@ -39,7 +39,7 @@ def _generate_data(self) -> dict: "equipId": self.equip_id, "sensorId": self.sensor_id, "sensorType": self.type, - "val": round(random.uniform(20.0 + self.idx, 80.0 + self.idx), 2) + "val": round(random.gauss(mu = 11.68, sigma = 29.38), 2) # 0: 60이하,1: 60초과, 2: 80 초과과 } ################################################ diff --git a/service/simulation/SimulatorInterface2.py b/service/simulation/SimulatorInterface2.py index 17d12b1..9ad7929 100644 --- a/service/simulation/SimulatorInterface2.py +++ b/service/simulation/SimulatorInterface2.py @@ -4,6 +4,7 @@ import threading from mqtt_util.publish import AwsMQTT import time +from scipy.stats import truncnorm class SimulatorInterface2(ABC): def __init__(self, idx: int, zone_id: str, equip_id: str, interval: int, msg_count: int, conn:AwsMQTT=None): # 센서 idx를 받기 @@ -120,4 +121,16 @@ def start_publishing(self): # self.thread.join() def stop(self): - self.stop_event.set() # 스레드 종료 이벤트 설정 \ No newline at end of file + self.stop_event.set() # 스레드 종료 이벤트 설정 + + def generate_truncated_normal(self, mu: float, sigma: float, lower: float = None, upper: float = None) -> float: + # 기본값 설정: 평균 이상의 값만 생성 + if lower is None: + lower = mu + if upper is None: + upper = mu + 3 * sigma # 거의 대부분의 값 포함 (필요시 조정) + + # truncnorm은 정규화된 구간 [a, b]를 사용하므로 변환 필요 + a, b = (lower - mu) / sigma, (upper - mu) / sigma + value = truncnorm.rvs(a, b, loc=mu, scale=sigma) + return round(value, 2) diff --git a/service/simulation/TempSimulator.py b/service/simulation/TempSimulator.py index 53cdb4a..e204eb0 100644 --- a/service/simulation/TempSimulator.py +++ b/service/simulation/TempSimulator.py @@ -1,5 +1,7 @@ from .SimulatorInterface2 import SimulatorInterface2 import random +from scipy.stats import truncnorm + class TempSimulator(SimulatorInterface2): def __init__(self, idx: int, zone_id:str, equip_id:str, interval:int = 5, msg_count:int = 10, conn=None): @@ -32,6 +34,17 @@ def __init__(self, idx: int, zone_id:str, equip_id:str, interval:int = 5, msg_co self.target_temperature = None # 초기값 설정(shadow 용) + self.mu = 25 # 평균 온도 (정상 범위: 18~21℃) + self.sigma = 10 # 표준편차 (온도의 변동폭) + + # 절단 범위 설정 (최소값 -35℃, 최대값 50℃로 설정) + self.lower = -35 + self.upper = 50 + + # 정규분포 범위의 a, b 값 계산 + self.a = (self.lower - self.mu) / self.sigma + self.b = (self.upper - self.mu) / self.sigma + ################################################z # 데이터 생성 로직을 정의 (시뮬레이터 마다 다르게 구현) # 예) 온도, 습도, 진동, 전류 등등 @@ -43,7 +56,7 @@ def _generate_data(self) -> dict: "equipId": self.equip_id, "sensorId": self.sensor_id, "sensorType": self.type, - "val": round(random.uniform(20.0 + self.idx, 80.0 + self.idx), 2) + "val": round(truncnorm.rvs(self.a, self.b, loc=self.mu, scale=self.sigma), 2) } ################################################ diff --git a/service/simulation/VibrationSimulator.py b/service/simulation/VibrationSimulator.py index ec274c6..06ff015 100644 --- a/service/simulation/VibrationSimulator.py +++ b/service/simulation/VibrationSimulator.py @@ -1,6 +1,7 @@ from .SimulatorInterface2 import SimulatorInterface2 from simulate_type.simulate_list import generate_vibration_data import random +from scipy.stats import truncnorm class VibrationSimulator(SimulatorInterface2): def __init__(self, idx: int, zone_id:str, equip_id:str, interval:int = 5, msg_count:int = 10, conn=None): @@ -20,7 +21,17 @@ def __init__(self, idx: int, zone_id:str, equip_id:str, interval:int = 5, msg_co self.shadow_desired_topic_name = f"$aws/things/Sensor/shadow/name/{self.sensor_id}/update/desired" self.topic_name = f"sensor/{zone_id}/{equip_id}/{self.sensor_id}/{self.type}" self.target_vibration = None # Initial value for shadow) - + self.mu = 3.5 # 평균 진동값 + self.sigma = 2 # 표준편차 (진동의 변동폭) + + # 절단 범위 설정 (최소값 0, 최대값 10으로 설정) + self.lower = 0 + self.upper = 10 + + # 정규분포 범위의 a, b 값 계산 + self.a = (self.lower - self.mu) / self.sigma + self.b = (self.upper - self.mu) / self.sigma + # 데이터 생성 로직을 정의 (시뮬레이터 마다 다르게 구현) def _generate_data(self) -> dict: return { @@ -28,7 +39,7 @@ def _generate_data(self) -> dict: "equipId": self.equip_id, "sensorId": self.sensor_id, "sensorType": self.type, - "val": round(random.uniform(0.1 + self.idx, 10.0 + self.idx), 2) + "val": round(truncnorm.rvs(self.a, self.b, loc=self.mu, scale=self.sigma), 2) } From 18adb2b206169edfcf18388cd62a9f787ea185bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B4=91=EB=B6=80=EC=9E=85=EB=8B=88=EB=8B=A4?= Date: Thu, 15 May 2025 15:54:35 +0900 Subject: [PATCH 14/15] =?UTF-8?q?chore=20|=20=EC=97=86=EC=9D=8C=20|=20?= =?UTF-8?q?=EC=97=86=EC=9D=8C=20|=20ecr=20=EC=9D=B4=EB=AF=B8=EC=A7=80=20?= =?UTF-8?q?=EB=B0=98=EC=98=81=20|=20=EA=B9=80=EC=9A=B0=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/docker-build-develop.yml | 49 ++++++++++++++++++++++ requirements.txt | 1 + 2 files changed, 50 insertions(+) create mode 100644 .github/workflows/docker-build-develop.yml diff --git a/.github/workflows/docker-build-develop.yml b/.github/workflows/docker-build-develop.yml new file mode 100644 index 0000000..e155661 --- /dev/null +++ b/.github/workflows/docker-build-develop.yml @@ -0,0 +1,49 @@ +name: Test and Build Python Image to ECR + +on: + pull_request: + branches: + - main + +jobs: + test-and-deploy: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.10' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + + - name: Run Streamlit sanity check + run: | + streamlit --version + python -m pytest || echo "Tests not configured, skipping..." + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v2 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: ap-northeast-2 + + - name: Login to Amazon ECR + id: login-ecr + uses: aws-actions/amazon-ecr-login@v1 + + - name: Build, tag, and push image to ECR + env: + ECR_REGISTRY: ${{ secrets.AWS_ECR_REGISTRY }} + ECR_REPOSITORY: streamlit-app + IMAGE_TAG: streamlit-latest + run: | + docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG . + docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG diff --git a/requirements.txt b/requirements.txt index c9a0bf4..3a4eee6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -47,6 +47,7 @@ referencing==0.36.2 requests==2.32.3 rpds-py==0.24.0 s3transfer==0.12.0 +scipy==1.15.3 six==1.17.0 smmap==5.0.2 streamlit==1.45.0 From e6c45d3fa414b17800d0b634b573f873c40cef5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B4=91=EB=B6=80=EC=9E=85=EB=8B=88=EB=8B=A4?= Date: Thu, 15 May 2025 16:10:01 +0900 Subject: [PATCH 15/15] =?UTF-8?q?chore=20|=20=EC=97=86=EC=9D=8C=20|=20?= =?UTF-8?q?=EC=97=86=EC=9D=8C=20|=20=EC=8B=9C=EB=AE=AC=EB=A0=88=EC=9D=B4?= =?UTF-8?q?=ED=84=B0=20=EC=84=A4=EC=A0=95=20=EA=B2=BD=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=20|=20=EA=B9=80=EC=9A=B0=EC=98=81=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- service/simulation/simulateTest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/service/simulation/simulateTest.py b/service/simulation/simulateTest.py index 7a5780d..5bd76f9 100644 --- a/service/simulation/simulateTest.py +++ b/service/simulation/simulateTest.py @@ -81,5 +81,5 @@ def run_simulation_from_json(json_file_path): if __name__ == "__main__": # JSON 파일 경로 - json_file_path = "service/simulation/simulation_cconfig.json" + json_file_path = "simulation_cconfig.json" run_simulation_from_json(json_file_path) \ No newline at end of file