class HotWaterDB():
    def __init__(self, hotWaterDBConfig, entityDBConfig):
        self.entityDB = MariaDB_handler(**entityDBConfig)
        self.hotWaterAPI = HotWaterAPI()
        self.hotWaterDBObject = MariaDB_handler(**hotWaterDBConfig)
        self.hotWaterDBObject.createTables(hotWaterModel.Base)

    def getAllBuildingData(self):
        try:
            buildings = []
            session_entity = self.entityDB.create_session()
            for building in self.entityDB.getAll(session_entity,
                                                 entitymodel.Building):
                buildings.append((building.name, building.lat, building.long))
        except Exception as e:
            print("Please Update database with entities")
            print(e)
            raise e
        finally:
            self.entityDB.close_session(session_entity)
        print(buildings)
        return buildings

    def getPowerDHW(self, timestamp, buildingName, latitude, longitude):
        try:
            session = self.hotWaterDBObject.create_session()
            latitude = round(float(latitude), 4)
            longitude = round(float(longitude), 4)
            powerDHWValue = session.query(hotWaterModel.HotWater).filter(hotWaterModel.HotWater.timestamp == timestamp). \
                filter(hotWaterModel.HotWater.buildingName == buildingName).first()
            if powerDHWValue:
                powerDHWDict = powerDHWValue.toDict()
            print(powerDHWDict)
            return powerDHWDict['powerDHW']
        except Exception as e:
            print(e)
            self.hotWaterDBObject.close_session(session)

    def writePowerDHWToDB(self, timestamp):
        buildings = self.getAllBuildingData()
        session = self.hotWaterDBObject.create_session()
        try:
            for building in buildings:
                buildingName = building[0]
                latitude = building[1]
                longitude = building[2]
                powerDHW = self.hotWaterAPI.getThermalPowerDHW(buildingName)
                hotWaterDBData = hotWaterModel.HotWater(
                    timestamp, buildingName, latitude, longitude, powerDHW)
                self.hotWaterDBObject.addElementToDatabase(
                    session, hotWaterDBData)
        except Exception as e:
            print(e)
        finally:
            self.hotWaterDBObject.close_session(session)
Beispiel #2
0
class Co2DB():
    def __init__(self, carbonIntensityDBConfig):
        self.carbonIntensityAPI = CarbonIntensityAPI()
        self.carbonIntensityDB = MariaDB_handler(**carbonIntensityDBConfig)
        self.carbonIntensityDB.createTables(co2model.Base)

    def writeCo2ValuesToDB(self):
        try:
            self.carbonIntensityAPI.getPowerGenData()
            response = self.carbonIntensityAPI.calculateCarbonIntensity()
            session = self.carbonIntensityDB.create_session()
            for timestamp in response:
                carbonIntensity = co2model.Co2ForecastProxy(
                    timestamp, response[timestamp])
                self.carbonIntensityDB.addElementToDatabase(
                    session, carbonIntensity)

        except Exception as e:
            print(e)
            return

        finally:
            self.carbonIntensityDB.close_session(session)
class PriceDB():
    def __init__(self, priceDBConfig):
        self.priceAPI = PricesAPI()
        self.priceDB = MariaDB_handler(**priceDBConfig)
        self.priceDB.createTables(pricemodel.Base)

    def writePriceToDB(self, time=None):
        currentTime = datetime.now()
        if not time:
            time = currentTime
        self.priceAPI.setTime(time)
        self.priceAPI.forgePayload()
        try:
            response = self.priceAPI.getPriceForecast()
        except Exception as e:
            print(e)
            return
        print(response)
        day = response[0].replace(hour=0)
        prices = response[1]
        try:
            session = self.priceDB.create_session()
            for price in prices:
                timestamp = day + timedelta(hours=int(price[0]) - 1)
                forecastPrice = session.query(
                    pricemodel.PriceForecast).filter_by(
                        timestamp=timestamp).first()
                if forecastPrice:
                    forecastPrice.price = price[1]
                    forecastPrice.retrivalTime = currentTime
                    self.priceDB.commitOrRollback(session)
                else:
                    forecastPrice = pricemodel.PriceForecast(
                        timestamp, currentTime, price[1])
                    self.priceDB.addElementToDatabase(session, forecastPrice)
        finally:
            self.priceDB.close_session(session)
class SpaceHeatingAPI():
    """
    API to calculate power required for space heating.
    Requires weather data to calculate power required for space heating.

    Attributes
    ----------
    buildingName : string
        name of the building where gas boiler is installed and space heating has to be done

    prevTempIndoor : float
        calculated indoor temperature in previous iteration. Parameter is read from database
    currentTempIndoor : float
        calculated current indoor temperature

    prevTempOutdoor : float
        outdoor temperature provided by weather api in previous iteration. Parameter is read from database
    currentTempOutdoor : float
        current outdoor temperarure. Data is provided by weather api

    prevThermalPowerSH : float
        calculated power (Watt) for space heating in previous iteration. Parameter is read from database
    currentThermalPowerSH : float
        calculated power (Watt) for space heating in current iteration

    tempIndoorDesired : float
        desired indoor temperature. Reads from global config file
    thermalResistance : float
        thermal resistance of the building. Parameter is read from database
    heatCapacityAirIndoor : float
        heat capacity of the indoor air. Parameter is read from database
    

    Methods
    -------
    getBuildingConstants()
        get mathematical model of a building from database 
    calculateCurrentTempIndoor()
        calculate current indoor temperature
    calculateThermalPowerSH(buildingName)
        returns power required (in Watt) for space heating

    """
    def __init__(self, spaceHeatingDBConfig):
        self.spaceHeatingDB = MariaDB_handler(**spaceHeatingDBConfig)
        self.prevTempIndoor = config.TEMP_INDOOR_INITIAL
        self.prevThermalPowerSH = 0
        self.tempIndoorDesired = config.TEMP_INDOOR_DESIRED

    def getBuildingConstants(self, buildingModel):
        self.thermalResistance = buildingModel['thermalResistance']
        self.heatCapacityAirIndoor = buildingModel['heatCapacityAirIndoor']
        self.exponentTerm = math.exp(
            -TIME_STEP_HR /
            (self.thermalResistance * self.heatCapacityAirIndoor))

    def calculateCurrentTempIndoor(self):
        try:
            session_SH = self.spaceHeatingDB.create_session()
            prevTimestamp = datetime.now().replace(
                minute=0, second=0, microsecond=0) - timedelta(hours=1)
            prevSpaceHeatingValue = session_SH.query(spaceHeatingModel.SpaceHeating).filter(spaceHeatingModel.SpaceHeating.timestamp>=prevTimestamp, \
                spaceHeatingModel.SpaceHeating.buildingName==self.buildingName).first()
            if prevSpaceHeatingValue:
                spaceHeatingDict = prevSpaceHeatingValue.toDict()
                print(spaceHeatingDict)
                self.prevTempIndoor = spaceHeatingDict['temperatureIndoor']
                self.prevThermalPowerSH = spaceHeatingDict['powerSH']
                self.prevTempOutdoor = spaceHeatingDict['temperatureOutdoor']
            else:
                # Values are not available. Set default values
                self.prevTempOutdoor = self.currentTempOutdoor

            self.currentTempIndoor = (self.prevTempIndoor * self.exponentTerm) + ( ( \
                (self.thermalResistance * self.prevThermalPowerSH) + self.prevTempOutdoor) * (1- self.exponentTerm) )
            #self.currentTempIndoor = self.prevTempIndoor + ((TIME_STEP_SEC/self.heatCapacityBuilding) \
            #* ( self.prevThermalPowerSH - (self.heatLossCoefficientBuilding * (self.prevTempIndoor - self.prevTempOutdoor) ) ) )
        except Exception as e:
            print(e)
            return
        finally:
            self.spaceHeatingDB.close_session(session_SH)

    def calculateThermalPowerSH(self, timestamp, buildingName,
                                currentTempOutdoor, buildingModel):
        self.currentTempOutdoor = currentTempOutdoor
        self.buildingName = buildingName
        self.getBuildingConstants(buildingModel)
        self.calculateCurrentTempIndoor()

        firstTerm = ((self.tempIndoorDesired -
                      (self.currentTempIndoor * self.exponentTerm)) /
                     (self.thermalResistance * (1 - self.exponentTerm)))
        secondTerm = currentTempOutdoor / self.thermalResistance
        self.currentThermalPowerSH = firstTerm - secondTerm
        return self.currentTempIndoor, self.currentThermalPowerSH
class Optimzer_DB():

    def __init__(self, schduleDBConfig, entityDBConfig, priceDBConfig, number_of_time_steps=24, time_limit=None, gap_factor=10):
        self.scheduleDB = MariaDB_handler(**schduleDBConfig)
        self.scheduleDB.createTables(optimizerModel.Base)
        self.entityDB = MariaDB_handler(**entityDBConfig)
        self.entityDB.createTables(entitymodel.Base)
        self.priceDB = MariaDB_handler(**priceDBConfig)
        self.priceDB.createTables(pricesModel.Base)
        self.number_of_time_steps = number_of_time_steps
        self.time_limit = time_limit
        self.gap_factor = gap_factor

    def writeScheduleToDB(self, obj_function, use_this=False):
        '''
        Loads all data, generates a schedule and writes it to the database.
        '''
        self.__loadGrid()
        date = datetime.now().replace(hour=0, minute=0, second=0, microsecond=0) + timedelta(days=1)
        self.__loadForecast(date)
        self.__loadBatteryEnergy(date)
        try:
            self.__loadPrices(date)
        except NotEnoughDataException:
            print('No current prices. Use the prices from yesterday.')
            self.__loadPrices(date - timedelta(days=1))
        obj_value, schedule = self.__optimize(obj_function, self.time_limit, self.gap_factor)
        try:
            session_scheduleDB = self.scheduleDB.create_session()
            schedule_DB_data = session_scheduleDB.query(optimizerModel.Schedule) \
                .filter(
                    optimizerModel.Schedule.date == date,
                    optimizerModel.Schedule.obj_function == obj_function
                    ).first()
            if schedule_DB_data:
                schedule_DB_data.obj_value = obj_value
                schedule_DB_data.schedule = schedule
                self.scheduleDB.commitOrRollback(session_scheduleDB)
            else:
                schedule_DB_data = optimizerModel.Schedule(date, obj_function, obj_value,schedule)
                self.scheduleDB.addElementToDatabase(session_scheduleDB, schedule_DB_data)
        finally:
            self.scheduleDB.close_session(session_scheduleDB)
        return schedule_DB_data

    def setObjectiveInDB(self, obj_function):
        '''
        Sets the objective of the next day.
        '''
        date = datetime.now().replace(hour=0, minute=0, second=0, microsecond=0) + timedelta(days=1)
        try:
            session_scheduleDB = self.scheduleDB.create_session()
            objective_DB_data = session_scheduleDB.query(optimizerModel.Objective) \
                .filter(
                    optimizerModel.Objective.date == date
                    ).first()
            if objective_DB_data:
                objective_DB_data.obj_function = obj_function
                self.scheduleDB.commitOrRollback(session_scheduleDB)
            else:
                objective_DB_data = optimizerModel.Objective(date, obj_function)
                self.scheduleDB.addElementToDatabase(session_scheduleDB, objective_DB_data)
        finally:
            self.scheduleDB.close_session(session_scheduleDB)
        return objective_DB_data

    def setSameObjectiveAsLastDay(self):
        '''
        Sets the objective of the next day with the value of the objective of this day, if there is no objective for tomorrow.
        '''
        date = datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)
        try:
            session_scheduleDB = self.scheduleDB.create_session()
            objective_DB_data = session_scheduleDB.query(optimizerModel.Objective) \
                .filter(
                    optimizerModel.Objective.date == date
                    ).first()
            if objective_DB_data:
                objective = objective_DB_data.obj_function
            else:
                objective = 'cost'
            new_date = date + timedelta(days=1)
            new_objective_DB_data = session_scheduleDB.query(optimizerModel.Objective) \
                .filter(
                    optimizerModel.Objective.date == new_date
                    ).first()
            if not  new_objective_DB_data:
                new_objective_DB_data = optimizerModel.Objective(new_date, objective)
                self.scheduleDB.addElementToDatabase(session_scheduleDB, new_objective_DB_data)
        finally:
            self.scheduleDB.close_session(session_scheduleDB)
        return new_objective_DB_data



    def __loadGrid(self):
        ''' 
        Loads the micro grid from the database.
        '''
        self.windTurbines = []
        self.solarPanels = []
        self.batteries = []
        self.buildings = []
        try:
            session_entityDB = self.entityDB.create_session()
            for windturbine in self.entityDB.getAll(session_entityDB,entitymodel.WindTurbine):
                self.windTurbines.append(windturbine)

            for solarpanel in self.entityDB.getAll(session_entityDB, entitymodel.SolarPanel):
                self.solarPanels.append(solarpanel)

            for building in self.entityDB.getAll(session_entityDB, entitymodel.Building):
                self.buildings.append(building)

            for battery in self.entityDB.getAll(session_entityDB, entitymodel.Battery):
                self.batteries.append(battery)
        finally:
            self.entityDB.close_session(session_entityDB)

    def __loadForecast(self, date):
        '''
        Loads the simulation forecast data from the database.
        '''
        date_start = date.replace(hour=0, minute=0, second=0, microsecond=0)
        date_end = date_start + timedelta(days=1)
        self.gen_forecasts = {}
        try:
            session_entityDB = self.entityDB.create_session() 
            for solarpanel in self.solarPanels:
                forcast = session_entityDB \
                    .query(entitymodel.SimulationForecastSolarPanel) \
                    .filter(
                        entitymodel.SimulationForecastSolarPanel.solarpanel_name == solarpanel.name,
                        entitymodel.SimulationForecastSolarPanel.timestamp >= date_start, 
                        entitymodel.SimulationForecastSolarPanel.timestamp < date_end
                        ).all()
                if len(forcast) != self.number_of_time_steps:
                    raise NotEnoughDataException(f'Not enough forcast data for {solarpanel.name}.')
                self.gen_forecasts[solarpanel.name] = [item.supply for item in forcast]

            for windturbine in self.windTurbines:
                forcast = session_entityDB \
                    .query(entitymodel.SimulationForecastWindTurbine) \
                    .filter(
                        entitymodel.SimulationForecastWindTurbine.windturbine_name == windturbine.name,
                        entitymodel.SimulationForecastWindTurbine.timestamp >= date_start, 
                        entitymodel.SimulationForecastWindTurbine.timestamp < date_end
                        ).all()
                if len(forcast) != self.number_of_time_steps:
                    raise NotEnoughDataException(f'Not enough forcast data for {windturbine.name}.')
                self.gen_forecasts[windturbine.name] = [item.supply for item in forcast]
        finally:
            self.entityDB.close_session(session_entityDB)

    def __loadPrices(self, date):
        '''
        Loads the prices from the database.
        '''
        date_start = date.replace(hour=0, minute=0, second=0, microsecond=0)
        date_end = date_start + timedelta(days=1)
        try:
            session_priceDB = self.priceDB.create_session()
            price_data = session_priceDB \
                .query(pricesModel.PriceForecast) \
                    .filter(
                        pricesModel.PriceForecast.timestamp >= date_start,
                        pricesModel.PriceForecast.timestamp < date_end
                    ).all()
            if len(price_data) != self.number_of_time_steps:
                    raise NotEnoughDataException(f'Not enough price data.')
            self.prices_buy = [price.price for price in price_data]
            # sell prices are are 10 percent less than buy prices due to taxes
            self.prices_sell = [price.price*0.9 for price in price_data]
        finally:
            self.priceDB.close_session(session_priceDB)

    def __loadBatteryEnergy(self, date):
        '''
        Loads the battery energy from the last schedue, so that energy can be transfered to the next day.
        If there is no last schedule, initialize all batteries with energy 0.
        '''
        self.batteries_startEnergy = {}
        date = date.replace(hour=0, minute=0, second=0, microsecond=0) - timedelta(days=1)
        try:
            session_scheduleDB = self.scheduleDB.create_session()
            objective_DB_data = session_scheduleDB.query(optimizerModel.Objective) \
                .filter(
                    optimizerModel.Objective.date == date
                    ).first()
            if objective_DB_data:
                objective = objective_DB_data.obj_function
            else:
                objective = 'cost'
            last_schedule = session_scheduleDB \
                .query(optimizerModel.Schedule) \
                .filter(
                    optimizerModel.Schedule.date==date,
                    optimizerModel.Schedule.obj_function==objective
                    ).first()
            if last_schedule:
                battery_schedule = last_schedule['batteries']
                for battery in self.batteries:
                    self.batteries_startEnergy[battery.name] = battery_schedule[battery.name]['energy'][24]
            else:
                for battery in self.batteries:
                    self.batteries_startEnergy[battery.name] = 0
        finally:
            self.scheduleDB.close_session(session_scheduleDB)



    def __optimize(self, obj_function, time_limit=None, gap_factor=10):
        '''
        Initialize the optimizer and run the optimization.
        '''
        opt = Optimizer(self.number_of_time_steps)
        for building in self.buildings:
            opt.addBuilding(building)
        for battery in self.batteries:
            opt.addBattery(battery, self.batteries_startEnergy[battery.name])
        for name, forecast in self.gen_forecasts.items():
            opt.addGenerator(name, forecast)
        opt.addPriceBuy(self.prices_buy)
        opt.addPriceSell(self.prices_sell)
        if time_limit:
            opt.set_time_limit(time_limit)
        # Try the optimization until is works with the specified time limit and mip gap
        # After each time out triple the mip gap and try it again
        while(True):
            try:
                opt.optimize(obj_function)
                break
            except TimeoutError:
                opt.multiply_mip_gap(gap_factor)
        return opt.getObjFuncValue(), opt.getSchedule()
Beispiel #6
0
class WeatherDB():

    def __init__(self, weatherDBConfig, entityDBConfig):
        self.weatherDB = MariaDB_handler(**weatherDBConfig)
        self.weatherDB.createTables(weathermodel.Base)
        self.entityDB = MariaDB_handler(**entityDBConfig)
        self.entityDB.createTables(entitymodel.Base)
        self.weatherAPI = WeatherAPI()

    def writeWeatherToDB(self):
        locations = []
        try:
            session_entity = self.entityDB.create_session()
            for solarpanel in self.entityDB.getAll(session_entity, entitymodel.SolarPanel):
                locations.append((solarpanel.lat, solarpanel.long))
            for windturbine in self.entityDB.getAll(session_entity, entitymodel.WindTurbine):
                locations.append((windturbine.lat, windturbine.long))
        except Exception as e:
            print("Please Update database with entities")
            print (e)
            raise e
        finally:
            self.entityDB.close_session(session_entity)
        # remove duplicates
        locations = set(locations)
        print(locations)
        try:
            session_weather = self.weatherDB.create_session()
            for location in locations:
                lat = location[0]
                long = location[1]
                currentWeatherData = self.weatherAPI.getCurrent(lat, long)
                currentWeather = session_weather.query(weathermodel.WeatherCurrent).filter_by(lat=lat, long=long, timestamp=currentWeatherData["timestamp"]).first()
                if currentWeather:
                    currentWeather.temp = currentWeatherData["temp"]
                    currentWeather.windSpeed = currentWeatherData["windSpeed"]
                    currentWeather.pressure = currentWeatherData["pressure"]
                    currentWeather.relativeHumidity = currentWeatherData["relativeHumidity"]
                    currentWeather.s_horizontal = currentWeatherData["s_horizontal"]
                    self.weatherDB.commitOrRollback(session_weather)
                else:
                    currentWeather = weathermodel.WeatherCurrent(lat, long, **currentWeatherData)
                    self.weatherDB.addElementToDatabase(session_weather, currentWeather)

            
            for location in locations:
                lat = location[0]
                long = location[1]
                forecastWeatherList = self.weatherAPI.getForecast(lat, long)
                for forecastWeatherData in forecastWeatherList:
                    forecastWeather = session_weather.query(weathermodel.WeatherForecast).filter_by(lat=lat, long=long, timestamp=forecastWeatherData["timestamp"]).first()
                    if forecastWeather:
                        forecastWeather.temp = forecastWeatherData["temp"]
                        forecastWeather.windSpeed = forecastWeatherData["windSpeed"]
                        forecastWeather.pressure = forecastWeatherData["pressure"]
                        forecastWeather.relativeHumidity = forecastWeatherData["relativeHumidity"]
                        forecastWeather.s_horizontal = forecastWeatherData["s_horizontal"]
                        self.weatherDB.commitOrRollback(session_weather)
                    else:
                        forecastWeather = weathermodel.WeatherForecast(lat, long, **forecastWeatherData)
                        self.weatherDB.addElementToDatabase(session_weather, forecastWeather)
        except Exception as e:
            raise e
        finally:
            self.weatherDB.close_session(session_weather)
class SpaceHeatingDB():
    def __init__(self, spaceHeatingDBConfig, entityDBConfig):
        self.entityDB = MariaDB_handler(**entityDBConfig)
        self.spaceHeatingDBObject = MariaDB_handler(**spaceHeatingDBConfig)
        self.spaceHeatingDBObject.createTables(spaceHeatingModel.Base)
        self.buildings = self.getAllBuildingData()
        self.spaceHeatingAPI = SpaceHeatingAPI(spaceHeatingDBConfig)

    def getAllBuildingData(self):
        try:
            buildings = []
            session_entity = self.entityDB.create_session()
            for building in self.entityDB.getAll(session_entity,
                                                 entitymodel.Building):
                mathematicalModel = {
                    "thermalResistance": building.thermalResistance,
                    "heatCapacityAirIndoor": building.heatCapacityAirIndoor
                }
                buildings.append((building.name, building.lat, building.long,
                                  mathematicalModel))
        except Exception as e:
            print("Please Update database with entities")
            print(e)
            raise e
        finally:
            self.entityDB.close_session(session_entity)

        print(buildings)
        return buildings

    def getPowerSH(self, timestamp, buildingName, latitude, longitude):
        try:
            session = self.spaceHeatingDBObject.create_session()
            latitude = round(float(latitude), 4)
            longitude = round(float(longitude), 4)
            print(timestamp, buildingName, latitude, longitude)
            powerSHValue = session.query(spaceHeatingModel.SpaceHeating).filter(spaceHeatingModel.SpaceHeating.timestamp == timestamp). \
                filter(spaceHeatingModel.SpaceHeating.buildingName == buildingName).first()
            if powerSHValue:
                powerSHDict = powerSHValue.toDict()
                print(powerSHDict)
            return powerSHDict['powerSH']
        except Exception as e:
            print(e)
            self.spaceHeatingDBObject.close_session(session)

    def writePowerSHToDB(self, timestamp):
        if self.buildings == None:
            self.building = self.getAllBuildingData()
        try:
            session = self.spaceHeatingDBObject.create_session()
            print("Pinging weather service")
            for building in self.buildings:
                buildingName = building[0]
                latitude = building[1]
                longitude = building[2]
                mathematicalModel = building[3]
                payload = {'lat': latitude, 'longi': longitude}
                response = requests.get(config.URL_WEATHER_SERVICE +
                                        "/currentWeather",
                                        params=payload)
                response = json.loads(response.text)
                currentWeather = response['currentWeatherData']
                response_code = response['response_code']

                if response_code != 200:
                    print("Weather Data Unavailable!!")

                currentTempOutdoor = currentWeather['temp']
                currentTempIndoor, thermalPowerSH = self.spaceHeatingAPI.calculateThermalPowerSH(
                    timestamp, buildingName, currentTempOutdoor,
                    mathematicalModel)
                print(currentTempIndoor, thermalPowerSH)
                spaceHeatingData = spaceHeatingModel.SpaceHeating(
                    timestamp, buildingName, latitude, longitude,
                    currentTempIndoor, currentTempOutdoor, thermalPowerSH)
                self.spaceHeatingDBObject.addElementToDatabase(
                    session, spaceHeatingData)
            self.spaceHeatingDBObject.close_session(session)

        except Exception as e:
            print(e)
            self.spaceHeatingDBObject.close_session(session)
Beispiel #8
0
class Simulation():
    def __init__(self, weatherDBConfig, entityDBConfig, scheduleDBConfig):
        # init weater database
        self.weatherDB = MariaDB_handler(**weatherDBConfig)
        self.weatherDB.createTables(weathermodel.Base)
        # init entity database
        self.entityDB = MariaDB_handler(**entityDBConfig)
        self.entityDB.createTables(entitymodel.Base)
        # init schedule database
        self.scheduleDB = MariaDB_handler(**scheduleDBConfig)
        self.scheduleDB.createTables(schedulemodel.Base)
        self.windTurbines = {}
        self.solarPanels = {}
        self.batteries = {}
        self.buildings = {}

    def init_sim(self, startingTime):
        self.time = startingTime.replace(minute=0, second=0, microsecond=0)
        self.__loadMicroGridFromDatabase()

        self.simObj = entitymodel.Simulation(self.time, True)
        try:
            session_entityDB = self.entityDB.create_session()
            # stop running simulations
            sims = session_entityDB.query(
                entitymodel.Simulation).filter_by(running=True).all()
            for sim in sims:
                sim.running = False
            self.entityDB.commitOrRollback(session_entityDB)
            self.entityDB.addElementToDatabase(session_entityDB, self.simObj)
        finally:
            self.entityDB.close_session(session_entityDB)

    def close_sim(self):
        try:
            session_entityDB = self.entityDB.create_session()
            self.simObj = session_entityDB.query(
                entitymodel.Simulation).filter_by(id=self.simObj.id).first()
            self.simObj.running = False
            self.entityDB.commitOrRollback(session_entityDB)
        finally:
            self.entityDB.close_session(session_entityDB)

    def __loadMicroGridFromDatabase(self):
        self.windTurbines = {}
        self.solarPanels = {}
        self.batteries = {}
        self.buildings = {}
        try:
            session_entityDB = self.entityDB.create_session()
            for windturbine in self.entityDB.getAll(session_entityDB,
                                                    entitymodel.WindTurbine):
                self.windTurbines[
                    windturbine.name] = WindTurbineSim.createFromModel(
                        windturbine)

            for solarpanel in self.entityDB.getAll(session_entityDB,
                                                   entitymodel.SolarPanel):
                self.solarPanels[
                    solarpanel.name] = SolarPanelSim.createFromModel(
                        solarpanel)

            for building in self.entityDB.getAll(session_entityDB,
                                                 entitymodel.Building):
                self.buildings[building.name] = BuildingSim.createFromModel(
                    building)

            for battery in self.entityDB.getAll(session_entityDB,
                                                entitymodel.Battery):
                self.batteries[battery.name] = BatterySim.createFromModel(
                    battery)
        finally:
            self.entityDB.close_session(session_entityDB)

    def __getCurrentWeatherData(self, lat, long):
        try:
            session_weatherDB = self.weatherDB.create_session()
            currentWeather = session_weatherDB.query(
                weathermodel.WeatherCurrent).filter_by(
                    lat=lat, long=long, timestamp=self.time).first()
            if currentWeather:
                return currentWeather
            forecastWeather = session_weatherDB.query(
                weathermodel.WeatherForecast).filter_by(
                    lat=lat, long=long, timestamp=self.time).first()
        finally:
            self.weatherDB.close_session(session_weatherDB)
        if forecastWeather:
            print("return forecast")
            return forecastWeather
        raise NoWeatherDataException(
            f"No data is available. lat:{lat}, long:{long}, timestamp:{str(self.time)}"
        )

    def __getForecastWeatherDataList(self, lat, long):
        try:
            session_weatherDB = self.weatherDB.create_session()
            forecastWeather = session_weatherDB.query(weathermodel.WeatherForecast) \
                .filter(
                    weathermodel.WeatherForecast.timestamp>=self.time,
                    weathermodel.WeatherForecast.lat==lat,
                     weathermodel.WeatherForecast.long==long) \
                .all()
        finally:
            self.weatherDB.close_session(session_weatherDB)
        if forecastWeather:
            return forecastWeather
        raise NoWeatherDataException(
            f"No forecast data is available. lat:{lat}, long:{long}, timestamp:{str(self.time)}"
        )

    def simulateNextHour(self):
        self.__loadSchedule()
        day_of_the_year = self.time.timetuple().tm_yday
        hour_of_the_day = self.time.timetuple().tm_hour
        total_energy = 0
        total_energy += self.__simulateWindTurbines()
        total_energy += self.__simulateSolarPanels(day_of_the_year)
        total_energy -= self.__simulateBuildings(hour_of_the_day)
        total_energy -= self.__simulateBatteries(hour_of_the_day)
        try:
            session_entityDB = self.entityDB.create_session()
            total_sim = session_entityDB.query(
                entitymodel.SimulationTotalEnergy).filter_by(
                    timestamp=self.time).first()
            if total_sim:
                total_sim.energy = total_energy
                self.entityDB.commitOrRollback(session_entityDB)
            else:
                self.entityDB.addElementToDatabase(
                    session_entityDB,
                    entitymodel.SimulationTotalEnergy(self.time, total_energy))
        finally:
            self.entityDB.close_session(session_entityDB)
        self.time = self.time + timedelta(hours=1)

    def simulateForecast(self):
        try:
            session_entityDB = self.entityDB.create_session()
            for windturbine in self.windTurbines.values():
                try:
                    forecastList = self.__getForecastWeatherDataList(
                        windturbine.lat, windturbine.long)
                except NoWeatherDataException as e:
                    print(e)
                for forecast in forecastList:
                    supply = windturbine.computePower(
                        forecast.temp, forecast.pressure, forecast.windSpeed,
                        forecast.relativeHumidity)
                    forecast_data = session_entityDB.query(
                        entitymodel.SimulationForecastWindTurbine).filter_by(
                            windturbine_name=windturbine.name,
                            timestamp=forecast.timestamp).first()
                    if forecast_data:
                        forecast_data.supply = supply
                        self.entityDB.commitOrRollback(session_entityDB)
                    else:
                        forecast_data = entitymodel.SimulationForecastWindTurbine(
                            windturbine.name, forecast.timestamp, supply)
                        self.entityDB.addElementToDatabase(
                            session_entityDB, forecast_data)

            for solarpanel in self.solarPanels.values():
                try:
                    forecastList = self.__getForecastWeatherDataList(
                        solarpanel.lat, solarpanel.long)
                except NoWeatherDataException as e:
                    print(e)
                for forecast in forecastList:
                    day_of_the_year = forecast.timestamp.timetuple().tm_yday
                    supply = solarpanel.computePower(day_of_the_year,
                                                     forecast.temp,
                                                     forecast.s_horizontal)
                    forecast_data = session_entityDB.query(
                        entitymodel.SimulationForecastSolarPanel).filter_by(
                            solarpanel_name=solarpanel.name,
                            timestamp=forecast.timestamp).first()
                    if forecast_data:
                        forecast_data.supply = supply
                        self.entityDB.commitOrRollback(session_entityDB)
                    else:
                        forecast_data = entitymodel.SimulationForecastSolarPanel(
                            solarpanel.name, forecast.timestamp, supply)
                        self.entityDB.addElementToDatabase(
                            session_entityDB, forecast_data)
        finally:
            self.entityDB.close_session(session_entityDB)

    def __simulateWindTurbines(self):
        total_suppy = 0
        try:
            session_entityDB = self.entityDB.create_session()
            for windturbine in self.windTurbines.values():
                weather_data = self.__getCurrentWeatherData(
                    windturbine.lat, windturbine.long)
                supply = windturbine.computePower(
                    weather_data.temp, weather_data.pressure,
                    weather_data.windSpeed, weather_data.relativeHumidity)
                total_suppy += supply
                windturbine_sim = session_entityDB.query(
                    entitymodel.SimulationWindTurbine).filter_by(
                        windturbine_name=windturbine.name,
                        timestamp=self.time).first()
                if windturbine_sim:
                    windturbine_sim.supply = supply
                    self.entityDB.commitOrRollback(session_entityDB)
                else:
                    self.entityDB.addElementToDatabase(
                        session_entityDB,
                        entitymodel.SimulationWindTurbine(
                            windturbine.name, self.time, supply))
            return total_suppy
        finally:
            self.entityDB.close_session(session_entityDB)

    def __simulateSolarPanels(self, day_of_the_year):
        total_suppy = 0
        try:
            session_entityDB = self.entityDB.create_session()
            for solarpanel in self.solarPanels.values():
                weather_data = self.__getCurrentWeatherData(
                    solarpanel.lat, solarpanel.long)
                supply = solarpanel.computePower(day_of_the_year,
                                                 weather_data.temp,
                                                 weather_data.s_horizontal)
                total_suppy += supply
                solarpanel_sim = session_entityDB.query(
                    entitymodel.SimulationSolarPanel).filter_by(
                        solarpanel_name=solarpanel.name,
                        timestamp=self.time).first()
                if solarpanel_sim:
                    solarpanel_sim.supply = supply
                    self.entityDB.commitOrRollback(session_entityDB)
                else:
                    self.entityDB.addElementToDatabase(
                        session_entityDB,
                        entitymodel.SimulationSolarPanel(
                            solarpanel.name, self.time, supply))
            return total_suppy
        finally:
            self.entityDB.close_session(session_entityDB)

    def __simulateBuildings(self, hour):
        total_demand = 0
        try:
            session_entityDB = self.entityDB.create_session()
            for name, building in self.buildings.items():
                building.setSchedule(self.schedule['buildings'][name])
                demand = building.getDemand(hour)
                componentState = building.getComponentState(hour)
                total_demand += demand
                building_sim = session_entityDB.query(
                    entitymodel.SimulationBuilding).filter_by(
                        building_name=name, timestamp=self.time).first()
                if building_sim:
                    building_sim.demand = demand
                    building_sim.componentState = componentState
                    self.entityDB.commitOrRollback(session_entityDB)
                else:
                    self.entityDB.addElementToDatabase(
                        session_entityDB,
                        entitymodel.SimulationBuilding(name, self.time, demand,
                                                       componentState))
            return total_demand
        finally:
            self.entityDB.close_session(session_entityDB)

    def __simulateBatteries(self, hour):
        total_charging_rate = 0
        try:
            session_entityDB = self.entityDB.create_session()
            for name, battery in self.batteries.items():
                battery.setSchedule(self.schedule['batteries'][name])
                rate = battery.getRate(hour)
                total_charging_rate += rate
                energy = battery.getEnergy(hour)
                battery_sim = session_entityDB.query(
                    entitymodel.SimulationBattery).filter_by(
                        battery_name=name, timestamp=self.time).first()
                if battery_sim:
                    battery_sim.energy = energy
                    battery_sim.rate = rate
                    self.entityDB.commitOrRollback(session_entityDB)
                else:
                    self.entityDB.addElementToDatabase(
                        session_entityDB,
                        entitymodel.SimulationBattery(
                            name, self.time, energy, rate,
                            battery.energyUpperBound))
            return total_charging_rate
        finally:
            self.entityDB.close_session(session_entityDB)

    def __loadSchedule(self):
        schedule_date = self.time.replace(hour=0,
                                          minute=0,
                                          second=0,
                                          microsecond=0)
        schedule_data = None
        try:
            session_scheduleDB = self.scheduleDB.create_session()
            objective_data = session_scheduleDB.query(
                schedulemodel.Objective).filter_by(date=schedule_date).first()
            if objective_data:
                schedule_data = session_scheduleDB.query(schedulemodel.Schedule) \
                    .filter(
                        schedulemodel.Schedule.date == schedule_date,
                        schedulemodel.Schedule.obj_function == objective_data.obj_function
                        ).first()
        finally:
            self.scheduleDB.close_session(session_scheduleDB)
        if schedule_data:
            self.schedule = schedule_data.schedule
        else:
            self.__generateDefaultSchedule()

    def __generateDefaultSchedule(self):
        schedule = {'buildings': {}, 'batteries': {}}
        zero = [0 for i in range(0, 24)]
        idle = ['idle' for i in range(0, 24)]
        for name, building in self.buildings.items():
            schedule['buildings'][name] = {}
            for comp in building.listOfComponets:
                schedule['buildings'][name][comp.name] = {
                    'start': comp.let - comp.lot,
                    'end': comp.let
                }
        for name, battery in self.batteries.items():
            schedule['batteries'][name] = {
                'state': idle,
                'rate': zero,
                'energy': zero
            }
        self.schedule = schedule