Welcome to ecoControl’s documentation!

NOTE: The documentation is work in progress.

Contents:

Getting Started

ecoControl is based on open-source tools and frameworks such as Django and PostgreSQL which makes it easy to deploy. In order to be able to start ecoControl, all requirements need to be installed and a server needs to be configured.

Install Requirements

To automatically install all dependencies on a Linux machine, make sure that pip and bower are installed and run the following commands:

pip install -r requirements.txt bower install

How to Run ecoControl Locally

This section is still in process.

How to Deploy ecoControl

This section is still in process.

REST API Documentation

The ecoControl server communicates through a REST-API only.

List of All API End Points

API End Point Description
General  
api/ Starting point
api/export/ CSV-Export function
api/login/ Login end point
api/logout/ Logout end point
api/notifications/ Get notifications list
api/sensors/ Get sensors list
api/settings/ Get settings list
api/status/ Get system status
Technician  
api/configure/ Set configurations
api/data/(monthly|yearly)/ Get sensor data
api/forecast/ Get forecast
api/forward/ forward
api/live/ Get live data
api/settings/tunable/ Get tunable settings
api/snippets/ Manage snippets
api/code/ Manage code
api/start/ Start system
api/statistics/(monthly/) Get statistics
api/thresholds/ Manage thresholds
api/automoptimize/ Manage auto optimization
Manager  
api/avgs/ Get sensor averages
api/balance/total/(latest/) Get balances
api/history/ Get history
api/loads/ Get loads
api/sensor/ Get sensor details
api/sums/ Get sensor sums

General

Bla

Starting point

/api
GET

Returns the current version number

GET /api HTTP/1.1
{

}

CSV-Export function

/api/export
POST

Reflects post data and starts a CSV file download.

Param Description
name Name of the service
description Description of service
POST /api/export
curl

Login end point

Logout end point

Get notifications list

Get sensors list

Get settings list

Get system status

Technician

Set configurations

Get sensor data

Get forecast

forward

Get live data

Get tunable settings

Manage snippets

Manage code

Start system

Get statistics

Manage thresholds

Manage auto optimization

Manager

Get sensor averages

Get balances

Get history

Get loads

Get sensor details

Get sensor sums

Models

class Configuration(*args, **kwargs)[source]

Configuration(id, key, value, value_type, unit, internal)

BOOL = 4
DATE = 3
exception DoesNotExist
Configuration.FLOAT = 2
Configuration.INT = 1
exception Configuration.MultipleObjectsReturned
Configuration.STR = 0
Configuration.TYPES = ((0, 'str'), (1, 'int'), (2, 'float'), (3, 'date'), (4, 'bool'))
Configuration.get_value_type_display(*moreargs, **morekwargs)
Configuration.objects = <django.db.models.manager.Manager object at 0x7ffec804db50>
class Device(*args, **kwargs)[source]

Device(id, name, device_type)

CU = 2
DEVICE_TYPES = ((0, 'HeatStorage'), (1, 'PowerMeter'), (2, 'CogenerationUnit'), (3, 'PeakLoadBoiler'), (4, 'ThermalConsumer'), (5, 'ElectricalConsumer'))
exception DoesNotExist
Device.EC = 5
Device.HS = 0
exception Device.MultipleObjectsReturned
Device.PLB = 3
Device.PM = 1
Device.TC = 4
Device.deviceconfiguration_set
Device.get_device_type_display(*moreargs, **morekwargs)
Device.objects = <django.db.models.manager.Manager object at 0x7ffec804d6d0>
Device.sensor_set
class DeviceConfiguration(*args, **kwargs)[source]

Does not inherit from Configuration because of bulk creation

BOOL = 4
DATE = 3
exception DoesNotExist
DeviceConfiguration.FLOAT = 2
DeviceConfiguration.INT = 1
exception DeviceConfiguration.MultipleObjectsReturned
DeviceConfiguration.STR = 0
DeviceConfiguration.TYPES = ((0, 'str'), (1, 'int'), (2, 'float'), (3, 'date'), (4, 'bool'))
DeviceConfiguration.device
DeviceConfiguration.get_value_type_display(*moreargs, **morekwargs)
DeviceConfiguration.objects = <django.db.models.manager.Manager object at 0x7ffec8060150>
class Notification(*args, **kwargs)[source]

Notification(id, threshold_id, sensor_value_id, target, read)

exception DoesNotExist
exception Notification.MultipleObjectsReturned
Notification.objects = <django.db.models.manager.Manager object at 0x7ffec7ffaf90>
Notification.sensor_value
Notification.threshold
class RealWeatherValue(*args, **kwargs)[source]

RealWeatherValue(id, temperature, timestamp)

exception DoesNotExist
exception RealWeatherValue.MultipleObjectsReturned
RealWeatherValue.get_next_by_timestamp(*moreargs, **morekwargs)
RealWeatherValue.get_previous_by_timestamp(*moreargs, **morekwargs)
RealWeatherValue.objects = <django.db.models.manager.Manager object at 0x7ffec806b310>
class Sensor(*args, **kwargs)[source]

Sensor(id, device_id, name, key, setter, unit, in_diagram, aggregate_sum, aggregate_avg)

exception DoesNotExist
exception Sensor.MultipleObjectsReturned
Sensor.device
Sensor.objects = <django.db.models.manager.Manager object at 0x7ffec8060790>
Sensor.sensorvalue_set
Sensor.sensorvaluedaily_set
Sensor.sensorvaluehourly_set
Sensor.sensorvaluemonthlyavg_set
Sensor.sensorvaluemonthlysum_set
Sensor.threshold_set
class SensorValue(*args, **kwargs)[source]

SensorValue(id, sensor_id, value, timestamp)

exception DoesNotExist
exception SensorValue.MultipleObjectsReturned
SensorValue.get_next_by_timestamp(*moreargs, **morekwargs)
SensorValue.get_previous_by_timestamp(*moreargs, **morekwargs)
SensorValue.notification_set
SensorValue.objects = <django.db.models.manager.Manager object at 0x7ffec8060c10>
SensorValue.sensor
class SensorValueDaily(*args, **kwargs)[source]

SensorValueDaily(id, sensor_id, timestamp, value)

exception DoesNotExist
exception SensorValueDaily.MultipleObjectsReturned
SensorValueDaily.get_next_by_timestamp(*moreargs, **morekwargs)
SensorValueDaily.get_previous_by_timestamp(*moreargs, **morekwargs)
SensorValueDaily.objects = <django.db.models.manager.Manager object at 0x7ffec806bbd0>
SensorValueDaily.sensor
class SensorValueHourly(*args, **kwargs)[source]

SensorValueHourly(id, sensor_id, timestamp, value)

exception DoesNotExist
exception SensorValueHourly.MultipleObjectsReturned
SensorValueHourly.get_next_by_timestamp(*moreargs, **morekwargs)
SensorValueHourly.get_previous_by_timestamp(*moreargs, **morekwargs)
SensorValueHourly.objects = <django.db.models.manager.Manager object at 0x7ffec806b790>
SensorValueHourly.sensor
class SensorValueMonthlyAvg(*args, **kwargs)[source]

SensorValueMonthlyAvg(id, sensor_id, timestamp, avg)

exception DoesNotExist
exception SensorValueMonthlyAvg.MultipleObjectsReturned
SensorValueMonthlyAvg.get_next_by_timestamp(*moreargs, **morekwargs)
SensorValueMonthlyAvg.get_previous_by_timestamp(*moreargs, **morekwargs)
SensorValueMonthlyAvg.objects = <django.db.models.manager.Manager object at 0x7ffec7ffa510>
SensorValueMonthlyAvg.sensor
class SensorValueMonthlySum(*args, **kwargs)[source]

SensorValueMonthlySum(id, sensor_id, timestamp, sum)

exception DoesNotExist
exception SensorValueMonthlySum.MultipleObjectsReturned
SensorValueMonthlySum.get_next_by_timestamp(*moreargs, **morekwargs)
SensorValueMonthlySum.get_previous_by_timestamp(*moreargs, **morekwargs)
SensorValueMonthlySum.objects = <django.db.models.manager.Manager object at 0x7ffec7ffa090>
SensorValueMonthlySum.sensor
class Threshold(*args, **kwargs)[source]

Threshold(id, sensor_id, name, category, show_manager, min_value, max_value)

Danger = 5
Default = 0
exception DoesNotExist
Threshold.Info = 3
exception Threshold.MultipleObjectsReturned
Threshold.Primary = 1
Threshold.Success = 2
Threshold.TYPES = ((0, 'Default'), (1, 'Primary'), (2, 'Success'), (3, 'Info'), (4, 'Warning'), (5, 'Danger'))
Threshold.Warning = 4
Threshold.get_category_display(*moreargs, **morekwargs)
Threshold.notification_set
Threshold.objects = <django.db.models.manager.Manager object at 0x7ffec7ffaa50>
Threshold.sensor
class WeatherValue(*args, **kwargs)[source]

WeatherValue(id, temperature, timestamp, target_time)

exception DoesNotExist
exception WeatherValue.MultipleObjectsReturned
WeatherValue.get_next_by_target_time(*moreargs, **morekwargs)
WeatherValue.get_next_by_timestamp(*moreargs, **morekwargs)
WeatherValue.get_previous_by_target_time(*moreargs, **morekwargs)
WeatherValue.get_previous_by_timestamp(*moreargs, **morekwargs)
WeatherValue.objects = <django.db.models.manager.Manager object at 0x7ffec8060fd0>

Devices

This module represents the energy systems.

The hardware interface should orient at the base classes of the devices. The simulation in server.forecasting.systems is also based on these classes.

class BaseDevice(device_id, env)[source]

Represents a general interface to the energy-systems.

class BaseEnvironment(initial_time=None, step_size=120, demomode=False, forecast=False)[source]

This class manages the environment of the devices holds the simulated time as well as the mode, the devices are running in. All connected devices share one BaseEnvironment

demo_mode = None
forecast | demo_mode True False
True forecast of simulated devices forecast of real devices
False demo simulation real device (env not defined)
forecast = None

see demo_mode

get_day_of_year()[source]

Returns an int value of the current simulated day of the year

initial_date = None

a unix timestamp representing the start of simulation if initial_time is None the current time is used

is_demo_simulation()[source]

Returns, if this is the demo_simulation

step_size = None

int value of seconds how often the simulated devices calculate their state

class CogenerationUnit(device_id, env)[source]

Represents a basic interface to a cogeneration unit. The configuration is read from the database and can be set from the frontend. The following parameters are available:

Parameters:
  • max_gas_input (float) – in kW
  • thermal_efficiency (float) – in percent between 0 and 1 calculated by the maximal thermal power and gas input
  • electrical_efficiency (float) – in percent between 0 and 1 calculated by the maximal electrical power and gas input
  • minimal_workload (float) – in percent between 0 and 1 used for modulation
  • minimal_off_time (float) – minimal time between to power-ons in seconds
  • purchase_price (float) – in Euro
  • purchase_date (date) – to calculate armotization
  • maintenance_interval_hours (int) – operating hours until maintenance is necessary
  • maintenance_interval_powerons (int) – maximal power-ons until maintenance is necessary
connected()[source]

The device needs a PowerMeter and a HeatStorage to operate properly.

current_electrical_production = None

kW

current_gas_consumption = None

kW

current_thermal_production = None

kWh

gas_costs = None

default 0.0655 Euro per kWh

get_operating_costs()[source]

Calculated by the consumed gas and maintenance costs (0.05 Euro per electric produced kWh).

total_electrical_production = None

kWh

total_gas_consumption = None

kWh

total_thermal_production = None

kWh

workload(workload=None)[source]

Getter and setter for the workload.

Parameters:workload (float) – between 0-100, if None nothing is set
Returns:current workload in percent [0,100]
class PeakLoadBoiler(device_id, env)[source]

Represents a basic interface to a cogeneration unit. The configuration is read from the database and can be set from the frontend. The following parameters are available:

Parameters:
  • max_gas_input (float) – in kW
  • thermal_efficiency (float) – in percent between 0 and 1 calculated by the maximal thermal power and gas input
connected()[source]

The device needs a HeatStorage to operate properly.

current_gas_consumption = None

kW

current_thermal_production = None

kWh

gas_costs = None

default 0.0655 Euro

get_operating_costs()[source]

Calculated by the consumed gas.

total_gas_consumption = None

kWh

total_thermal_production = None

kWh

workload_percent(workload=None)[source]

Getter and setter for the workload.

Parameters:workload (float) – between 0-100, if None nothing is set
Returns:current workload in [0,100]
class CogenerationUnit(device_id, env)[source]

Represents a basic interface to a cogeneration unit. The configuration is read from the database and can be set from the frontend. The following parameters are available:

Parameters:
  • max_gas_input (float) – in kW
  • thermal_efficiency (float) – in percent between 0 and 1 calculated by the maximal thermal power and gas input
  • electrical_efficiency (float) – in percent between 0 and 1 calculated by the maximal electrical power and gas input
  • minimal_workload (float) – in percent between 0 and 1 used for modulation
  • minimal_off_time (float) – minimal time between to power-ons in seconds
  • purchase_price (float) – in Euro
  • purchase_date (date) – to calculate armotization
  • maintenance_interval_hours (int) – operating hours until maintenance is necessary
  • maintenance_interval_powerons (int) – maximal power-ons until maintenance is necessary
connected()[source]

The device needs a PowerMeter and a HeatStorage to operate properly.

current_electrical_production = None

kW

current_gas_consumption = None

kW

current_thermal_production = None

kWh

gas_costs = None

default 0.0655 Euro per kWh

get_operating_costs()[source]

Calculated by the consumed gas and maintenance costs (0.05 Euro per electric produced kWh).

total_electrical_production = None

kWh

total_gas_consumption = None

kWh

total_thermal_production = None

kWh

workload(workload=None)[source]

Getter and setter for the workload.

Parameters:workload (float) – between 0-100, if None nothing is set
Returns:current workload in percent [0,100]
class PeakLoadBoiler(device_id, env)[source]

Represents a basic interface to a cogeneration unit. The configuration is read from the database and can be set from the frontend. The following parameters are available:

Parameters:
  • max_gas_input (float) – in kW
  • thermal_efficiency (float) – in percent between 0 and 1 calculated by the maximal thermal power and gas input
connected()[source]

The device needs a HeatStorage to operate properly.

current_gas_consumption = None

kW

current_thermal_production = None

kWh

gas_costs = None

default 0.0655 Euro

get_operating_costs()[source]

Calculated by the consumed gas.

total_gas_consumption = None

kWh

total_thermal_production = None

kWh

workload_percent(workload=None)[source]

Getter and setter for the workload.

Parameters:workload (float) – between 0-100, if None nothing is set
Returns:current workload in [0,100]
class ThermalConsumer(device_id, env)[source]

This class represents the thermal consume of the house. The demand is calculated by the necessary heating power and the required warm water. The house parameters are read from the database and can be set from the frontend. The following parameters are available:

Parameters:
  • apartments (int) – number of apartments in the house
  • avg_rooms_per_apartment (int) – average number of rooms
  • avg_windows_per_room (int) – average number of windows
  • type_of_windows (int) – isolation value between MISSING
  • total_living_area (int) – in square meters
  • type_of_housing (int) – isolation value between MISSING
  • residents (int) –
  • type_of_residents (int) – used to classify thermal demand MISSING RANGE
  • target_temperature (int) – requested temperature of the rooms in degree Celsius
  • avg_thermal_consumption (int) – in kWh
connected()[source]

The device needs a HeatStorage to operate properly.

daily_demand = None

list of 24 values representing target_temperature per hour

room_height = None

constant room height

temperature_warmwater = None

temperature of warm water 40 degrees Celsius by default

class ElectricalConsumer(device_id, env)[source]

This class represents the electrical consume of the house. The demand is calculated by the forecasting in :mod:server.forecasting.forecasting The house parameters are read from the database and can be set from the frontend. The following parameters are available:

Parameters:
  • apartments (int) – number of apartments in the house
  • residents (int) –
  • type_of_residents (int) – used to classify thermal demand MISSING RANGE
  • avg_electrical_consumption (int) – in kWh
connected()[source]

The device needs a PowerMeter to operate properly.

class HeatStorage(device_id, env)[source]

Represents a heat storage necessary to supply heating and warm water demand. The temperatures of the storage are as average and measured in degree Celsius. The configuration is read from the database and can be set from the frontend. The following parameters are available:

Parameters:
  • capacity (int) – in liters
  • min_temperature (float) – below this temperature the PeakLoadBoiler will turn on
  • target_temperature (float) – the HS schould always have this temperature
  • critical_temperature (float) – above this temperature all production devices are turned off
base_temperature = None

assume no lower temperature

specific_heat_capacity = None

specific heat capacity of water 4.19 J/(g*K)

class PowerMeter(device_id, env)[source]

Represents the power meter of the whole building. Measures the purchased and fed in electricity in kWh

add_energy(energy)[source]

This counts up the produced energy.

Parameters:energy (float) – in kWh
consume_energy(energy)[source]

This counts up the consumed energy.

Parameters:energy (float) – in kWh
electrical_costs = None

costs in Euro to purchase 1 kW/h from external supplier (default 0.283)

energy_consumed = None

set by consumer devices with consume_energy

energy_produced = None

set by producer devices with add_energy

fed_in_electricity = None

since last step

feed_in_reward = None

reward in Euro for feed in 1 kW/h to public grid (default 0.0917)

get_costs()[source]

Calculated by overall purchased electricity and default costs of 0.283 Euro per kWh

get_reward()[source]

Calculated by overall fed in electricity and the default reward of 0.0917 Euro per kWh. Sale to tenants is not considered here.

purchased = None

since last step

get_initialized_scenario()[source]

The function returns a list of energy systems based on the configuration in the database

Returns:list of objects from server.forecasting.systems
get_user_function(devices, code=None)[source]

Builds a method with the users code from the programming-interface.

Parameters:
  • systemslist of devices from :func:get_initialized_scenario:
  • codestring with the user-code
Returns:

callable user-function expecting a pointer to a systems list as argument

perform_configuration(data)[source]

Saves a systems configuration to the database.

Parameters:datajson with configuration values for energy systems

Forecasting

This package contains the simulation and methods for creating forecasts. They are split into statistical forecasts and weather forecast.

Simulation

class SimulatedCogenerationUnit(device_id, env)[source]

The simulation of a cogeneration unit

calculate_new_workload()[source]

Selects right operating mode for workload calculation

consume_and_produce_energy()[source]

Updates currently consumed and produced energy

get_calculated_workload_electric()[source]

Returns workload for electrical driven mode

get_calculated_workload_thermal()[source]

Returns workload for thermal driven mode

get_efficiency_loss_factor()[source]

Computes efficiency loss on modulation and returns left efficiency in percent [0,1]

get_electrical_energy_production()[source]

Returns produced electrical energy in kWh during current time-step

get_thermal_energy_production()[source]

Returns produced thermal energy in kWh during current time-step

off_time = None

Saves the last powered off time to ensure minimal_off_time

overwrite_workload = None

Efficiency is reached only on maximum workload at minumum workload the efficiency is decreased by 15 %

set_workload(calculated_workload)[source]

Sets given workload, detects power-ons and tracks operating time

Parameters:calculated_workload (float) – new workload for the next time-step
step()[source]

Calculates new workload, produce and consume energy for the last time-step

class SimulatedPeakLoadBoiler(device_id, env)[source]

The simulation of a peak load boiler

calculate_workload()[source]

Switches on when the heat storage is undersupplied and off if target temperature is reached. Also detects power-ons and tracks operating time.

consume_and_produce_energy()[source]

Updates currently consumed and produced energy

get_thermal_energy_production()[source]

Returns produced thermal energy in kWh during current time-step

off_time = None

Saves the last power off time to ensure 3 min off-time

overwrite_workload = None

Device can have fixed workload without internal control. Be aware of overheating!

step()[source]

Calculates new workload, produce and consume energy for the last time-step

class SimulatedThermalConsumer(device_id, env)[source]

The simulation of the thermal consume (heating and warm water) of a house

Usied formulas from http://www.model.in.tum.de/um/research/groups/ai/fki-berichte/postscript/fki-227-98.pdf and http://www.inference.phy.cam.ac.uk/is/papers/DanThermalModellingBuildings.pdf

calculate()[source]

Update the heating parameters when a house parameter is changed. Therefore some assumptions are made

get_consumption_energy()[source]

Returns consumed thermal energy for heating in kWh during current time-step

get_outside_temperature()[source]

The thermal energy demand depends on the outside temperature. For the current simulated time (self.env.now) the outside temperature is returned.

get_warmwater_consumption_energy()[source]

Returns needed thermal energy for warm water in kWh during current time-step

get_warmwater_consumption_power()[source]

The energy needed for warm water is calculated by the amount of needed liters in average. For the time step the power is calculated which could heat the needed water of all residents to the given temperature (40 degrees Celsius default).

heat_apartments()[source]

Increases the rooms temperature. With the current heating power an amount of energy for the current time-step is produced. This energy and the specific heat capacity of air (1000 J/(m^3 * K)) is needed for the temperature calculation.

heat_loss_power()[source]

Returns the power in kW by with the house loses thermal energy at outer walls and windows. The outside temperature is needed for the temperature difference.

simulate_consumption()[source]

Determine the heating power of the whole house considerung the rooms target temperature.

step()[source]

Simulate the heating and consume according energy

class SimulatedElectricalConsumer(device_id, env)[source]

The simulation of the electrical consume of a house based on forecasting.

get_consumption_energy()[source]

Returns needed electrical energy in kWh during current time-step

get_consumption_power()[source]

Use the forecast to determine the current power demand

step()[source]

Calculate the current power and consume according energy for current time-step.

class SimulatedHeatStorage(device_id, env)[source]

The simulation of a heat storage

add_energy(energy)[source]

Store energy in the heat storage.

Parameters:energy (float) – in kWh
consume_energy(energy)[source]

Use energy from the heat storage

Parameters:energy (float) – in kWh
empty_count = None

count the steps when mimium temperature is undershot

energy_stored()[source]

Currently available energy in kWh

get_energy_capacity()[source]

Returns the maximal storable amount of energy in kWh

get_required_energy()[source]

Necessary energy in kWh to reach the target temperature.

get_target_energy()[source]

Returns the overall energy needed for reaching the target temperature when the water is cold (base temperature)

get_temperature()[source]

Returns the average temperature of the heat storage

set_temperature(temperature)[source]

When the simulation is initialized to a real system the temperature of the real heat storage must be set

step()[source]

Loose some energy according to isolation

temperature_loss = None

temperature loss per day by default 3 degress Celsius

undersupplied()[source]

Returns True if the minimal temperature is undershot.

class SimulatedPowerMeter(device_id, env)[source]

The simulation of a power meter

add_energy(energy)[source]

Devices should use this method to supply electrical energy.

Parameters:energy (float) – in kWh
consume_energy(energy)[source]

Devices should use this method to consume electrical energy.

Parameters:energy (float) – in kWh
step()[source]

Purchase electrical energy if more energy needed than produced. Otherwise the remaining energy is fed in.

Statistical Forecasting

This module contains the statistical forecasting initiation and management.

The base class for all forecastings is StatisticalForecast , to generate forecasts one of the following subclasses has to be used

StatisticalForecast(env, input_data[, ...]) This is the abstract class for statistical forecasting.
DSHWForecast(env, input_data[, ...]) This forecast uses the double seasonal exponential smoothing method.
DayTypeForecast(env, input_data[, ...]) This forecast splits the demands into 7 weekdays and minimizes and forecasts each with the holt-winters multiplicative method.
class StatisticalForecast(env, input_data, samples_per_hour=1, start=None, try_cache=True, **kwargs)[source]

This is the abstract class for statistical forecasting. Statistical forecasts use exponential smoothing methods to forecast timeseries into the future. These methods rely on the right parameters to make a realistic forecast. The parameters can be passed to the function, if they are omitted they are found by minimizing the MSE.

Forecastings are calculated after contruction of class and then whenever needed, which is set by forecast_update_interval.

Parameters:
  • input_data (list) – list of consecutive values sampled in samples_per_hour
  • start (datetime) – start date of input data
  • samples_per_hour (int) – Number of samples per hour in input_data
  • try_cache (boolean) – Read and Save forecasts to a cache on the file device to avoid unneccesary recomputation, is True by default.
  • **kwargs – Any instance variable can be overwritten with a keyword from here, f.e. input_weeks = 14. Will be set before any data is processed. Only use, if you know what your doing.
Variables:
  • forecast_update_interval (int) – The time in seconds for how long forecasts stay valid. When this interval is passed, a new forecast is calculated.
  • input_weeks (int) – only forecast with this many weeks of data, default are 12 weeks.
  • output_weeks (int) – the forecast will cover this many weeks of future data,default are 8 weeks.
  • demands ([[],]) – the processed demands, depending on subclass this contains one or more series
get_forecast_at(timestamp)[source]

Return the forecast at the (unix) timestamp.

Raise a IndexError if there is no forecast for the timestamp.

process_inputdata(data, samples_per_hour, start)[source]

Preprocess and return the input demands. Needed for the division into weekdays in DayTypeForecast.

Parameters:start (datetime) – the time of the first datapoint. Only the day is of interest.
forecast_demands()[source]

Forecast and return the demands. The forecasting method depends on the subclass.

append_values(data, start_date=None)[source]

Pushes in new values and cuts off values at the beginning to keep input length. Will update the forecasts if needed.

classmethod make_hourly(data, samples_per_hour)[source]

aggregates data series to 1hourly data.

Parameters:
  • data (list) – the series
  • samples_per_hour (int) – number of samples per hour contained in data
Returns:

list of 1hourly data

classmethod MASE(training_series, testing_series, prediction_series)[source]

Computes the MEAN-ABSOLUTE SCALED ERROR forecast error for univariate time series prediction.

See “Another look at measures of forecast accuracy”, Rob J Hyndman

Parameters:
  • training_series (list) – the series used to train the model
  • testing_series (list) – the test series to predict
  • prediction_series (list) – the prediction of testing_series (same size as testing_series)
update_if_needed()[source]

Internal Method Update the forecasts, if env.now is more than forecast_update_interval seconds ahead from last demand measurement

read_from_cache()[source]

Internal Method Return a cached result. If try_cache = True, this will try to read from cache/cached_forecasts.cache. The results are only returned, if the timestamp of the forecast creation is not older than 24h. Else or if no cached file is available, None is returned.

Returns:list or None

Double-Seasonal Forecast

class DSHWForecast(env, input_data, samples_per_hour=1, start=None, try_cache=True, **kwargs)[source]

Bases: server.forecasting.statistical.StatisticalForecast

This forecast uses the double seasonal exponential smoothing method. It often delivers better results than the DayTypeForecast.

append_values(data, start_date=None)[source]

See StatisticalForecast.append_values()

forecast_demands(verbose=False)[source]

See StatisticalForecast.forecast_demands().

process_inputdata(data, samples_per_hour, start)[source]

See StatisticalForecast.process_inputdata() Dummy Method, returns array of data.

Day-Type Forecast

class DayTypeForecast(env, input_data, samples_per_hour=1, start=None, try_cache=True, **kwargs)[source]

Bases: server.forecasting.statistical.StatisticalForecast

This forecast splits the demands into 7 weekdays and minimizes and forecasts each with the holt-winters multiplicative method.

append_values(data, start_date=None)[source]

See StatisticalForecast.append_values()

forecast_demands()[source]

See StatisticalForecast.forecast_demands(). This method uses processes, to speed up the calculation. This drives the cpu to full load for a short time.

process_inputdata(data, samples_per_hour, start)[source]

See StatisticalForecast.process_inputdata() Splits the data into 7 arrays, one for each weekday.

Holt-Winters Methods

This module contains four exponential smoothing algorithms.

They are Holt’s linear trend method and Holt-Winters seasonal methods (additive and multiplicative). The fourth method is the double seasonal exponential smoothing method with AR(1) autocorrelation and no trend.

References:

Hyndman, R. J.; Athanasopoulos, G. (2013) Forecasting: principles and practice. http://otexts.com/fpp/

Byrd, R. H.; Lu, P.; Nocedal, J. A Limited Memory Algorithm for Bound Constrained Optimization, (1995), SIAM Journal on Scientific and Statistical Computing, 16, 5, pp. 1190-1208.

Taylor, W James, (2003); Short-Term Electricity Demand Forecasting Using Double Seasonal Exponential Smoothing, Journal of the Operational Research Society

linear(x, forecast, alpha=None, beta=None)[source]

Returns a forecast calculated with linear exponential smoothing. If alpha or beta are None, the method will optimize the MSE() and find the most suitable parameters. The method returns these optimized parameters and also the one-step-forecasts, for each value of x.

Parameters:
  • x (list) – the series to be forecasted
  • forecast (int) – the timeperiod of the forecast. F.e. forecast=24*7 for one week (assuming hourly data)
  • alpha (float) – the level component
  • beta (float) – the trend component
Returns:

(forecast, parameters, one-step-forecasts)

additive(x, m, forecast, alpha=None, beta=None, gamma=None, initial_values_optimization=[0.002, 0.0, 0.0002], optimization_type='MSE')[source]

Returns a forecast calculated with the seasonal exponential smoothing method (additive Holt-Winters). This method will consider seasonality and can be configured by setting the length of the seasonality m. If alpha or beta or gamma are None, the method will optimize the MSE() and find the most suitable parameters. The method returns these optimized parameters and also the one-step-forecasts, for each value of x.

If optimization is used, a list of starting parameters can be supplied by initial_values_optimization. The algorithm will start searching in the neighbourhood of these values. It can’t be guaranteed, that all values in the boundaries (0,1) are considered.

Parameters:
  • x (list) – the series to be forecasted
  • m (int) – the seasonality, f.e. m=24 for daily seasonality (a daily cycle in data is expected)
  • forecast (int) – the timeperiod of the forecast. F.e. forecast=24*7 for one week (assuming hourly data)
  • alpha (float) – the level component
  • beta (float) – the trend component
  • gamma (float) – the seasonal component component
  • initial_values_optimization (list) – a first guess of the parameters to use when optimizing.
  • optimization_criterion (string) –

    type of minimization measure, if minimization is used

    • “MSE” - use MSE()
    • “MASE” - use MASE() (slowest)
Returns:

(forecast, parameters, one-step-forecasts)

multiplicative(x, m, forecast, alpha=None, beta=None, gamma=None, initial_values_optimization=[0.002, 0.0, 0.0002], optimization_type='MSE')[source]

This method uses the multiplicative Holt-Winters method. It often delivers better results for our use-case than the additive method. For parameters, see additive() .

double_seasonal(x, m, m2, forecast, alpha=None, beta=None, gamma=None, delta=None, autocorrelation=None, initial_values_optimization=[0.1, 0.0, 0.2, 0.2, 0.9], optimization_type='MSE')[source]

Returns a forecast calculated with the double seasonal holt-winters method ( Taylor 2003 ). This method considers two seasonalies. This is great for electrical demand forecasting, as demands have daily and weekly seasonalities. The method also uses autocorrelation, to forecast patterns in residuals. The trend component is ignored for this method, as electrical demands mostly dont have a trend.

For all parameters, see additive().

Parameters:
  • m (int) – intraday seasonality (m = 24, for hourly data)
  • m2 (int) – intraweek seasonality (m = 24*7, for hourly data)
Returns:

(forecast, parameters, one-step-forecasts)

MSE(params, *args)[source]

Internal Method. Calculates the Mean Square Error of one run of holt-winters with the supplied arguments. The MSE is actually computed from the MSE of the one-step-forecast error and the error between the forecast and a testseries.

Parameters:
  • params (list) – (alpha, ...) the parameters
  • *args (list) – (input_series, hw type, m), with hwtype in [0:3] depicting hw method
MASE(params, *args)[source]

Calculates the Mean-Absolute Scaled Error (see server.forecasting.forecasting.StatisticalForecast.MASE()). For parameters see MSE().

Choltwinters — Holt-Winters Extensions

This module contains an optimized version of the Holt-Winters double-seasonal method and the multiplicative method.

The functions in this module should deliver the same results as the unoptimized version in holt_winters. Just import the double_seasonal() from this module instead of the one in holt_winters.py. This module has to be compiled with Cython, it introduces statically typed variables and optimizes array usage and can therefore get speedups up to 100x. Note that the optimizing function differs from the normal version, as it first searches the global boundaries and then does a extremely accurate local search. This leads to results very close to the absolute optimum.

To build this module, use the build_holtwinters_extension() function. If it suceeds, a .pyd extension is built, which can be used like a normal python module. An example for importing and building the extension can be seen in server.forecasting.forecasting (source).

Weather

This module handles crawling, storing and retrieving of weather values.

It is split into two Classes.

DemoWeather([env]) Gets Weathervalues from the database.
CurrentWeatherForecast([env, city]) Gets the current Weatherforecast from an online service.
get_temperature(env, date)[source]

General function to retrieve forecasts. Will decide upon the env parameter, if DemoWeather or CurrentWeatherForecast should be used.

Parameters:
  • env (BaseEnvironment) – the current environment
  • date (datetime) – the time of which to retrieve the weather(forecast)
class DemoWeather(env=None)[source]

Gets Weathervalues from the database. The demo_mode operates on stored data from the past. For maximum realism, the past data should contain the real weather values as well as stored weather forecasts.

The data is stored in the database, with server.models.RealWeatherValue for history weather and server.models.WeatherValue for stored forecasts.

get_temperature(date)[source]

Retrieve a temperature at a certain time. The class will cache the values after the first query to speed up subsequent requests.

Parameters:date (datetime) – The time

Raises an Exception if there are no values in the database for the current time.

get_temperature_estimate(target_date)[source]

Retrieve a forecasted temperature at a certain time. The target_date must be between 0 and 10 days away from the creation_date, as weather forecasts only cover 10 days.

The class will cache the values after the first query to speed up subsequent requests.

Parameters:date (datetime) – The timepoint
class CurrentWeatherForecast(env=None, city='Berlin')[source]

Gets the current Weatherforecast from an online service. This is http://api.openweathermap.org/ at the moment, but may change in future versions.

get_temperature_estimate(date)[source]

Get the most accurate forecast for given date that can be derived from 5 days forecast, 14 days forecast or from history data. This is the public getter for forecasts and should be used

Parameters:date (datetime) – the timepoint for which to get the forecast
Returns:temperature (float)
get_forecast_temperature_hourly(date)[source]

Get the hourly forecast for the given date.

get_forecast_temperature_daily(date)[source]

get the forecast for given date. This only has day accuracy, but the forecast span is longer

find_city(name)[source]

returns a dictionary with city id, names and country based on the given search name the first search result is returned as ‘default’ too.

Parameters:name (string) – f.e. “Berlin”
get_weather_forecast(hourly=True)[source]

retrieves an entire forecast. Tries to get forecast from internal list or filesystem cache. If that fails or data is too old, the online service will be queried

get_openweathermapdata()[source]

read from openweathermap. If this fails, use get_average_outside_temperature()

get_average_outside_temperature(date, offset_days=0)[source]

return an average Berlin temperature in 2012/2013 for a given date.

Parameters:offset_days (int) – offset the real days, f.e. to get some randomness

Helping functions for Forecasting

helpers

helper methods for forecasting

approximate_index(dataset, findvalue)[source]

Return index value in dataset, with optimized find procedure. This assumes a dataset with continuous, increasing values. Typically, these are timestamps.

Parameters:
  • dataset (list) – a continuous list of values (f.e. timestamps)
  • findvalue (int) – the value, of which to find the index.
cached_data(name, data_function=None, max_age=0)[source]

store and retrieve data from a cache on the filesystem. The function will try to retrieve the cached data. If there is None or the data is too old, data_function will be called and the result is stored in the cache.

Parameters:
  • name (string) – name of cache file
  • data_function (function) – A function, which outputs the data to be stored. If the function is None and the cache is invalid, the funtion will return None.
  • max_age (int) – The maximum age (real time) in seconds, the cache is allowed to have before turning invalid.
Returns:

data or None

interpolate_year(day)[source]

input: int between 0,365 output: float between 0,1 interpolates a year day to 1=winter, 0=summer

perdelta(start, end, delta)[source]

generator function, which outputs dates. works like range(start, stop, step) for dates

Parameters:
  • start,end (datetime) – dates between which to iterate
  • delta (timedelta) – the stepwidth

dataloader

class DataLoader[source]

This class reads data from CSV formatted in a specific way. The files are cached in memory to enable fast, re-reads

classmethod load_from_file(filepath, column_name, delim='t', date_name='Datum', sampling_interval=600)[source]

load a time series from a csv file. This assumes, that the csv is formatted in the following way:

Date header Row Header1 Row Header2 Row Header N
Timestamp0 Row1Value0 Row2Value0 RowNValue0
Timestamp1 ... ... ...

If the values in the file isn’t sampled evenly, because it contains skips, blackouts, etc.. the data will be sampled evenly by copying certain data (see evenly_sampled()).

Parameters:
  • column_name (string) – The name of the column (in the csv) to retrieve
  • delim (string) – The delimiter between values of a row. Default is Tab.
  • date_name (string) – The name of the Date header of the date row
  • sampling_interval (int) – The interval the data in the file is sampled.
classmethod evenly_sampled(data, date_name='Datum', sampling_interval=600)[source]

Will return a version of data, in which every value has a corresponding timestamp, which is roughly sampling_interval seconds away from the last value. This is a maximum interval, if the data contains closer values together than sampling_interval, no actions will be taken.

The data which is used to fill up gaps is tried to gather intelligently. It is specifically designed for electrical data and takes values from one week ago, if present, else one day or the last value if everything else fails.

Parameters:
  • data (dict) – dictionary with column names as keys and column data as values
  • date_name (string) – name of the date row
  • sampling_interval (int) – the number of seconds between each consecutive sample

Forecasts

get_forecast(initial_time, configurations=None, code=None, forward=None)[source]
class Forecast(initial_time, configurations=None, code=None, forward=None, forecast=True)[source]

Bases: threading.Thread

Setup a Forecast Object. A new BaseEnvironment and new Devices will be created. Forecasting can either be ran synchronous or asynchronous (threaded):

foocast = Forecast(time.time(), forward=10*24*3600)
barcast = Forecast(time.time(), forward=2*24*3600)

#run threaded
barcast.start() 

#wait until foocast is finished, then get result
resultfoo = foocast.run().get() 

# wait until barcast is finished
while resultbar == None:
    resultbar = barcast.get()
Parameters:
  • initial_time (int) – timestamp of the time, at which the forecast starts
  • configurations – cached configurations, if None, retrieve from database
  • code – code to be executed
  • forward (int) – Time to forecast. Uses DEFAULT_FORECAST_INTERVAL if None
  • forecast (boolean) – Passed to BaseEnvironment forecast.
get()[source]

return the result of the forecast. If the mainloop is still forecasting, None is returned.

outputs a dict with:

result = {start: datetime, 
           step: stepsize, 
            end: datetime, 
        sensors: list with values per sensor (see MeasurementStorage)}
run()[source]

run the main loop. Returns self after finishing. Results are obtained with get()

step()[source]

execute one step of the simulation. This steps all devices, auto-optimizes if needed and store the values

store_values()[source]

sample device values

class DemoSimulation(initial_time, configurations=None)[source]

Bases: server.forecasting.Forecast

A Forecast, which writes the values to the database. It replaces the real devices and is used to develop and show the capabilities of ecoControl. It uses real electrical and weather values instead of forecasts, the device simulation on the other hand is the same as in Forecast.

After calling start(), the simulation will currently run at 30 steps per second (or 30x speed). This is controlled by the step_size in BaseEnvironment.

The simulation can be forwarded to a certain point by setting the forward variable in seconds > 0. It will then run at maximum speed. The simulation runs until the variable running is set to False.

Note

DemoSimulations should generally be started with start_or_get()

run()[source]

run while running is true, call the parent step() method. This method must be called by start(), otherwise it immediately returns

start()[source]

start the simulation in a seperate thread

classmethod start_or_get(print_visible=False)[source]

This method starts a new demo simulation if necessary and it makes sure that only one demo simulation can run at once. This is the preferred way to start the demo simulation.

Returns:DemoSimulation or None if system not in demo mode.
store_values()[source]

stores values in database. Overwrites parents saving method. Values are only stored every (simulated) minute

class ForecastQueue[source]

A container, holding the running forecasts. Each forecast gets an id.

Usage:

q = ForecastQueue()
f_id = q.schedule_new(initial_time=time.time())
#... do other stuff, then retrieve forecast
result = q.get_by_id(f_id)
get_by_id(forecast_id)[source]

get a forecast by its id. Will return None, if forecast is not completed. If the forecast is finished, the result is returned and deleted from the ForecastQueue.

schedule_new(initial_time, **kwargs)[source]

start a new forecast and return its id. :param dict kwargs: the parameters for the Forecast

get_initialized_scenario(env, configurations)[source]

this function returns an initialized scenario. It creates new simulated devices and connects the right devices.

The devices are restored to the latest state of the SensorValue‘s in the db, if there are no Values, a warning will be logged and the standard values are used.

Parameters:
  • envBaseEnvironment for all Devices
  • configurations (list) – the device configurations, which to set in the devices. These are typically DeviceConfiguration objects.
Returns:

a namedtuple of devices, with the acronym (f.e plb), as key

Auto-Optimization

This module contains the algorithm for optimizing the costs of energy systems.

DEFAULT_FORECAST_INTERVAL = 3600.0

The interval for how long one auto_optimize will forecast and for how long one specific workload is set. Note, that this constant also represents a compromise: Shorter intervals can adjust to quick changes, f.e. electricity demands changes, while longer intervals can incorporate more forecasts, but wont be able to adjust quickly. The interval of one hour lead to good results in our tests.

auto_optimize(forecast)[source]

Tries to optimize the cost and sets the cu.overwrite_workload

The method forecasts from env.now with different cu workloads and finds the one with the lowest cost. The length of the forecast is DEFAULT_FORECAST_INTERVAL.

Parameters:forecast – the forecast to be optimized
find_optimal_config(initial_time, forecast)[source]

Internal Method Main method, which optimizes the costs by running a global approximation for the best configuration and then running a local minimization method on this approximation

estimate_cost(params, *args)[source]

Internal Method copies the devices and environment, forwards it and returns the costs.

Parameters:
  • params (list) – parameter to be optimized (CU.workload for now)
  • args – (initial_time, forecast, prices, rewards)
simplified_forecast(env, initial_time, devices)[source]

runs the forward loop only executing the step function

total_costs(devices, prices, rewards)[source]

Internal Method Returns the cost of a forecast run. The function uses the prices which are stored in the db deviceconfiguration. It is also constrained by boundaries, f.e. the heatstorage should never go below min temperature.

Parameters:
  • devices – The devices after the forecast
  • prices, rewards (dict) – Cached prices and rewards
class BilanceResult(cost, params)[source]

wrapper for storing a optimization result

Front End

The front end has been developed independently from the ecoControl server and communicates exclusively through the REST-API. It is based on jQuery and Twitter’s Bootstrap which provides an easy to use grid system and enables a responsive design. For all diagrams, the front end is using Highcharts and Highstock. The programming interface is based on Ace.

Structure

The front end can be found within the /static folder.

Folder Description
css/ Custom style sheets
img/ All images
js/ ecoControl specific Javascript code
js/libs/ Custom libraries
js/mgmt/ All Javascript code for the management views
js/tech/ All Javascript code for the technician views
libs/ Third party libraries
templates/ Mustache templates
index.html This is the starting point

Multi-language Support

The front end is available in English and in German. The language files can be found in /static/js/ and are called lang.en.js and lang.de.js.

Indices and Tables