From 651151c6ac1e1a2e4628f135383cdc95df57ad1e Mon Sep 17 00:00:00 2001 From: guille Date: Mon, 21 Feb 2022 13:26:14 -0500 Subject: [PATCH] Partial implementation of the new iot sensors, this change broke the sensor factories and a few unit tests that will be fixed in next commit. --- city_model_structure/city.py | 15 +++- .../iot/concordia_energy_sensor.py | 45 ----------- .../iot/concordia_gas_flow_sensor.py | 45 ----------- .../iot/concordia_temperature_sensor.py | 45 ----------- city_model_structure/iot/sensor.py | 81 +++++++++---------- city_model_structure/iot/sensor_measure.py | 40 +++++++++ city_model_structure/iot/sensor_type.py | 20 +++++ city_model_structure/iot/station.py | 41 ++++++++++ helpers/constants.py | 3 - .../sensors/concordia_energy_consumption.py | 1 - unittests/test_schedules_factory.py | 1 - 11 files changed, 152 insertions(+), 185 deletions(-) delete mode 100644 city_model_structure/iot/concordia_energy_sensor.py delete mode 100644 city_model_structure/iot/concordia_gas_flow_sensor.py delete mode 100644 city_model_structure/iot/concordia_temperature_sensor.py create mode 100644 city_model_structure/iot/sensor_measure.py create mode 100644 city_model_structure/iot/sensor_type.py create mode 100644 city_model_structure/iot/station.py diff --git a/city_model_structure/city.py b/city_model_structure/city.py index cf3e78b0..ddccd9d0 100644 --- a/city_model_structure/city.py +++ b/city_model_structure/city.py @@ -52,6 +52,7 @@ class City: self._city_objects = None self._energy_systems = None self._fuels = None + self._stations = [] @property def fuels(self) -> [Fuel]: @@ -349,11 +350,19 @@ class City: @property def energy_systems(self) -> Union[List[EnergySystem], None]: """ - Get energy systems belonging to the city - :return: None or [EnergySystem] - """ + Get energy systems belonging to the city + :return: None or [EnergySystem] + """ return self._energy_systems + @property + def stations(self) -> [Station]: + """ + Get the sensors stations belonging to the city + :return: [Station] + """ + return self._stations + @property def city_objects_clusters(self) -> Union[List[CityObjectsCluster], None]: """ diff --git a/city_model_structure/iot/concordia_energy_sensor.py b/city_model_structure/iot/concordia_energy_sensor.py deleted file mode 100644 index afc7b930..00000000 --- a/city_model_structure/iot/concordia_energy_sensor.py +++ /dev/null @@ -1,45 +0,0 @@ -""" -Energy Sensor module -SPDX - License - Identifier: LGPL - 3.0 - or -later -Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca -""" - -import pandas as pd -from city_model_structure.iot.sensor import Sensor - - -class ConcordiaEnergySensor(Sensor): - """ - Concordia energy sensor. - """ - - def __init__(self, name): - super().__init__() - self._name = name - self._interval = 5 - self._interval_units = 'minutes' - self._type = 'ConcordiaEnergySensor' - self._units = 'kW' - self._measures = pd.DataFrame(columns=["Date time", "Energy consumption"]) - - @property - def measures(self) -> pd.DataFrame: - """ - Get sensor measures [yyyy-mm-dd, hh:mm:ss kW] - :return: DataFrame["Date time", "Energy consumption"] - """ - return self._measures - - @measures.deleter - def measures(self): - """ - Delete sensor measures - """ - self._measures.drop = None - - def add_period(self, measures): - """ - Add or update a period measures to the dataframe - """ - measures = self._measures.append(measures, ignore_index=True) - self._measures = measures.drop_duplicates('Date time', keep='last') diff --git a/city_model_structure/iot/concordia_gas_flow_sensor.py b/city_model_structure/iot/concordia_gas_flow_sensor.py deleted file mode 100644 index 86da31bd..00000000 --- a/city_model_structure/iot/concordia_gas_flow_sensor.py +++ /dev/null @@ -1,45 +0,0 @@ -""" -Gas Flow Sensor module -SPDX - License - Identifier: LGPL - 3.0 - or -later -Copyright © 2020 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca -""" - -import pandas as pd -from city_model_structure.iot.sensor import Sensor - - -class ConcordiaGasFlowSensor(Sensor): - """ - Concordia gas flow sensor. - """ - - def __init__(self, name): - super().__init__() - self._name = name - self._interval = 5 - self._interval_units = 'minutes' - self._type = 'ConcordiaGasFlowSensor' - self._units = 'm3' - self._measures = pd.DataFrame(columns=["Date time", "Gas Flow Cumulative Monthly"]) - - @property - def measures(self) -> pd.DataFrame: - """ - Get sensor measures [yyyy-mm-dd, hh:mm:ss m3] - :return: DataFrame["Date time", "Gas Flow Cumulative Monthly"] - """ - return self._measures - - @measures.deleter - def measures(self): - """ - Delete sensor measures - """ - self._measures.drop = None - - def add_period(self, measures): - """ - Add or update a period measures to the dataframe - """ - measures = self._measures.append(measures, ignore_index=True) - self._measures = measures.drop_duplicates('Date time', keep='last') diff --git a/city_model_structure/iot/concordia_temperature_sensor.py b/city_model_structure/iot/concordia_temperature_sensor.py deleted file mode 100644 index 9ae6079c..00000000 --- a/city_model_structure/iot/concordia_temperature_sensor.py +++ /dev/null @@ -1,45 +0,0 @@ -""" -Temperature Sensor module -SPDX - License - Identifier: LGPL - 3.0 - or -later -Copyright © 2020 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca -""" - -import pandas as pd -from city_model_structure.iot.sensor import Sensor - - -class ConcordiaTemperatureSensor(Sensor): - """ - Concordia temperature sensor. - """ - - def __init__(self, name): - super().__init__() - self._name = name - self._interval = 5 - self._interval_units = 'minutes' - self._type = 'ConcordiaTemperatureSensor' - self._units = 'Celsius' - self._measures = pd.DataFrame(columns=["Date time", "Temperature"]) - - @property - def measures(self) -> pd.DataFrame: - """ - Get sensor measures [yyyy-mm-dd, hh:mm:ss Celsius] - :return: DataFrame["Date time", "Temperature"] - """ - return self._measures - - @measures.deleter - def measures(self): - """ - Delete sensor measures - """ - self._measures.drop = None - - def add_period(self, measures): - """ - Add or update a period measures to the dataframe - """ - measures = self._measures.append(measures, ignore_index=True) - self._measures = measures.drop_duplicates('Date time', keep='last') diff --git a/city_model_structure/iot/sensor.py b/city_model_structure/iot/sensor.py index 4eceafd1..c3801749 100644 --- a/city_model_structure/iot/sensor.py +++ b/city_model_structure/iot/sensor.py @@ -1,76 +1,73 @@ """ Sensor module SPDX - License - Identifier: LGPL - 3.0 - or -later -Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca +Copyright © 2022 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca """ +import uuid -from helpers.location import Location +from city_model_structure.iot.sensor_measure import SensorMeasure +from city_model_structure.iot.sensor_type import SensorType class Sensor: """ Sensor abstract class """ - def __init__(self): - self._name = None - self._type = None - self._units = None - self._location = None + def __init__(self, sensor_id=None, model=None, sensor_type=None, indoor=False, board=None): + self._id = sensor_id + self._model = model + self._type = sensor_type + self._indoor = indoor + self._board = board + self._measures = [] @property - def name(self): + def id(self): """ - Get sensor name - :return: str + Get the sensor id a random uuid will be assigned if no ID was provided to the constructor + :return: Id """ - if self._name is None: - raise ValueError('Undefined sensor name') - return self._name - - @name.setter - def name(self, value): - """ - Set sensor name - :param value: str - """ - if value is not None: - self._name = str(value) + if self._id is None: + self._id = uuid.uuid4() + return self._id @property - def type(self): + def type(self) -> SensorType: """ Get sensor type - :return: str + :return: SensorTypeEnum or Error """ + if self._type is None: + raise ValueError('Unknown sensor type') return self._type @property - def units(self): + def model(self): """ - Get sensor units - :return: str + Get sensor model is any + :return: str or None """ - return self._units + return self._model @property - def location(self) -> Location: + def board(self): """ - Get sensor location - :return: Location + Get sensor board if any + :return: str or None """ - return self._location - - @location.setter - def location(self, value): - """ - Set sensor location - :param value: Location - """ - self._location = value + return self._model @property - def measures(self): + def indoor(self): + """ + Get is the sensor it's located indoor or outdoor + :return: boolean + """ + return self._indoor + + @property + def measures(self) -> [SensorMeasure]: """ Raises not implemented error """ - raise NotImplementedError + return self._measures diff --git a/city_model_structure/iot/sensor_measure.py b/city_model_structure/iot/sensor_measure.py new file mode 100644 index 00000000..afdd40db --- /dev/null +++ b/city_model_structure/iot/sensor_measure.py @@ -0,0 +1,40 @@ +""" +Sensor measure module +SPDX - License - Identifier: LGPL - 3.0 - or -later +Copyright © 2022 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca +""" + +class SensorMeasure: + def __init__(self, latitude, longitude, utc_timestamp, value): + self._latitude = latitude + self._longitude = longitude + self._utc_timestamp = utc_timestamp + self._value = value + + @property + def latitude(self): + """ + Get measure latitude + """ + return self._latitude + + @property + def longitude(self): + """ + Get measure longitude + """ + return self._longitude + + @property + def utc_timestamp(self): + """ + Get measure timestamp in utc + """ + return self._utc_timestamp + + @property + def value(self): + """ + Get sensor measure value + """ + return self._value \ No newline at end of file diff --git a/city_model_structure/iot/sensor_type.py b/city_model_structure/iot/sensor_type.py new file mode 100644 index 00000000..414b6f60 --- /dev/null +++ b/city_model_structure/iot/sensor_type.py @@ -0,0 +1,20 @@ +""" +Sensor type module +SPDX - License - Identifier: LGPL - 3.0 - or -later +Copyright © 2022 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca +""" + +from enum import Enum + +class SensorType(Enum): + HUMIDITY = 0 + TEMPERATURE = 1 + CO2 = 2 + NOISE = 3 + PRESSURE = 4 + DIRECT_RADIATION = 5 + DIFFUSE_RADIATION = 6 + GLOBAL_RADIATION = 7 + AIR_QUALITY = 8 + GAS_FLOW = 9 + ENERGY = 10 diff --git a/city_model_structure/iot/station.py b/city_model_structure/iot/station.py new file mode 100644 index 00000000..8a15e62d --- /dev/null +++ b/city_model_structure/iot/station.py @@ -0,0 +1,41 @@ +""" +Station +SPDX - License - Identifier: LGPL - 3.0 - or -later +Copyright © 2022 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca +""" +import uuid + +from city_model_structure.iot.sensor import Sensor + + +class Station: + def __init__(self, station_id=None, _mobile=False): + self._id = station_id + self._mobile = _mobile + self._sensors = [] + + @property + def id(self): + """ + Get the station id a random uuid will be assigned if no ID was provided to the constructor + :return: Id + """ + if self._id is None: + self._id = uuid.uuid4() + return self._id + + @property + def _mobile(self): + """ + Get if the station is mobile or not + :return: bool + """ + return self._mobile + + @property + def sensors(self) -> [Sensor]: + """ + Get the sensors belonging to the station + :return: [Sensor] + """ + return self._sensors diff --git a/helpers/constants.py b/helpers/constants.py index 0f372605..4ce228d4 100644 --- a/helpers/constants.py +++ b/helpers/constants.py @@ -93,6 +93,3 @@ HEATING_SET_POINT = 'HtgSetPt' # todo: are any of these two the receptacle concept?? EQUIPMENT = 'Equipment' ACTIVITY = 'Activity' - -# Geometry -EPSILON = 0.0000001 diff --git a/imports/sensors/concordia_energy_consumption.py b/imports/sensors/concordia_energy_consumption.py index 0b006045..b25578b7 100644 --- a/imports/sensors/concordia_energy_consumption.py +++ b/imports/sensors/concordia_energy_consumption.py @@ -5,7 +5,6 @@ Copyright © 2021 Project Author Guille Gutierrez guillermo.gutierrezmorote@conc """ import pandas as pd from imports.sensors.concordia_file_report import ConcordiaFileReport -from city_model_structure.iot.concordia_energy_sensor import ConcordiaEnergySensor class ConcordiaEnergyConsumption(ConcordiaFileReport): diff --git a/unittests/test_schedules_factory.py b/unittests/test_schedules_factory.py index 0506abae..349c5c08 100644 --- a/unittests/test_schedules_factory.py +++ b/unittests/test_schedules_factory.py @@ -67,4 +67,3 @@ class TestSchedulesFactory(TestCase): for usage_zone in building.usage_zones: for schedule in usage_zone.schedules: print(schedule) - print(usage_zone.schedules[schedule])