Академический Документы
Профессиональный Документы
Культура Документы
Master Thesis
Author(s):
Baumann, Christof
Publication Date:
2012
Permanent Link:
https://doi.org/10.3929/ethz-a-007139689
Rights / License:
In Copyright - Non-Commercial Use Permitted
This page was generated automatically upon download from the ETH Zurich Research Collection. For more
information please consult the Terms of use.
ETH Library
Load-Balancing of Consumers in
Electricity Networks
Master’s Thesis
Christof Baumann
baumachr@student.ethz.ch
Supervisors:
Dipl. Math. Stephan Holzer (stholzer@tik.ee.ethz.ch)
Miguel Rodriguez (miguel.rodriguez@aizo.com)
Prof. Dr. Roger Wattenhofer (wattenhofer@tik.ee.ethz.ch)
I would like to thank my mentors Stephan Holzer, Miguel Rodriguez and Roger
Wattenhofer, who always had time for me when I needed them.
Many thanks also to all the colleagues at aizo for supporting me and an-
swering many of my questions. Especially, I would like to express my thanks to
Andreas Brauchli, who gave me an excellent introduction in digitalSTROM app
development and the ExtJS4 framework. I would also like to reward Christian
Hitz and Reto Flütsch for always having time for me when questions appeared.
I am grateful to my wife Marianne for helping me on some of the artwork and
supporting me during my studies. She encouraged and withstood me in good
and bad times of the work process.
i
Abstract
ii
Contents
Acknowledgements i
Abstract ii
1 Introduction 1
2 digitalSTROM
R 3
2.1 Configuration of a digitalSTROM System . . . . . . . . . . . . . 4
2.2 digitalSTROM Server . . . . . . . . . . . . . . . . . . . . . . . . 4
2.3 Electricity Markets . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.3.1 Derivatives Market . . . . . . . . . . . . . . . . . . . . . . 8
2.3.2 Spot Market . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.3.3 Intraday Market . . . . . . . . . . . . . . . . . . . . . . . 8
3 Smart-Grid App 10
3.1 Idea . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
3.2 Configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
3.2.1 Delayed ON . . . . . . . . . . . . . . . . . . . . . . . . . . 11
3.2.2 Short OFF . . . . . . . . . . . . . . . . . . . . . . . . . . 12
3.2.3 Example Configurations . . . . . . . . . . . . . . . . . . . 12
3.3 Dataflow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
3.3.1 Protocol . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
3.4 Property Tree . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
3.5 The Configuration User Interface . . . . . . . . . . . . . . . . . . 16
3.6 Detecting Device Presence . . . . . . . . . . . . . . . . . . . . . . 17
3.7 Demonstration: Energy Provider . . . . . . . . . . . . . . . . . . 18
3.8 Deploying the System . . . . . . . . . . . . . . . . . . . . . . . . 18
iii
Contents iv
4 Load-Balancing Algorithms 23
4.1 Simple Reacting Algorithm . . . . . . . . . . . . . . . . . . . . . 23
4.2 2D Packing Algorithm . . . . . . . . . . . . . . . . . . . . . . . . 25
4.2.1 Heuristic to Find the Best Starting Point . . . . . . . . . 26
4.3 Simulating the Algorithms . . . . . . . . . . . . . . . . . . . . . . 27
4.3.1 Results . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
6 Social Aspects 36
6.1 Sales Appeal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
6.2 Security . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
6.3 Privacy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
Bibliography 41
A Implementation Notes 1
A.1 Smart-Grid App . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
A.1.1 Subscriptions to Events . . . . . . . . . . . . . . . . . . . 1
A.1.2 Script . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
A.1.3 User Interface . . . . . . . . . . . . . . . . . . . . . . . . . 2
A.2 Demonstration Energy Provider . . . . . . . . . . . . . . . . . . . 2
A.3 Simulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
B Source Code 5
B.1 Smart-Grid App . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
B.1.1 Subscriptions to Events . . . . . . . . . . . . . . . . . . . 6
B.1.2 Script . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
B.1.3 User Interface . . . . . . . . . . . . . . . . . . . . . . . . . 21
B.2 Demonstration Energy Provider . . . . . . . . . . . . . . . . . . . 29
Contents v
B.3 Simulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
Chapter 1
Introduction
In the future much more of the consumed electricity will be produced as renew-
able energies like wind or solar energy. Several issues need to be sorted out such
as where to take the energy from if there is currently no wind or sun. Or what
to do with excess energy in case of too much sun or wind. Currently the energy
providers have to either shut down a power plant or start up an additional plant
to compensate these imbalances. Those processes can be very expensive and in
general they are a waste of energy. Another option the energy providers have in
times of energy exuberance is to store the energy in other places. For example the
energy can be transformed to potential energy and back to electrical energy later
when it is needed. This is done in Switzerland with some barrier lakes. In times
of energy excess water is pumped upwards to the lakes and again flushed down
if not enough energy is available. This is a very clever storage facility except for
the fact that in every transformation there is also loss involved. Additionally
only a limited amount of energy can be stored that way.
To address those problems it would be desirable to have a possibility to
regulate the consumer side of the network and not only react on the producer
side. All energy providers have to regulate the availability of energy according
to the consumption. Apart from the ripple control system [9] they don’t have
an instrument to control the consumption. Ripple control systems are widely
spread these days to control the starting times of devices. A ripple control sender
sends signals over the power line that are received in the households and may
trigger the start of devices. Disadvantages of the ripple control system are that
communication is only unidirectional and its expandability is limited. Normally
the system is just used during the night to stagger devices that consume large
amounts of energy like boilers.
An energy provider predicts the future consumption needs and has to fulfill
those needs under any circumstance. If it fails in satisfying the consumption
this results in a power outage. The only way to control this is to either start
up or shut down power plants or to store energy at another place. With an
instrument to regulate the consumer side the set of actions can be enlarged and
the overall efficiency of the network can be increased. Of course this regulation
1
1. Introduction 2
should not have an impact on the comfort of the customer. Instead the system
should be able to shift consumption peaks and to store energy in the household
where it can be used directly and does not have to be transformed again. The
user of such a system should not miss any comfort and should not notice when
load-balancing occurs.
There are already some pilot projects running that try to achieve the goal of
balancing the consumption. An example of such a project is the pilot study of
ienergie1 in Ittigen Switzerland [3]. They try to animate the consumers to shift
their consumptions to periods of larger availability. Except for their product
“Flex” they want to find out if users are willing to change their consumption
habits by just being informed about the availability and consumption curves.
The users should themselves shift their consumption behavior without the help
of the system. The product “Flex” provides a way to regulate some special
devices, like boilers or heat pumps, over the GSM/UMTS network by an energy
provider instead of the established ripple control [9].
In this thesis I would like to generalize the concept of publishing devices
to an energy provider that can use those devices to load-balance the energy
consumption. I worked together with the company aizo2 . Aizo is a start up
company that is developing and selling the digitalSTROM home automation
system3 .
In the chapter 2 we describe the digitalSTROM automation system in fur-
ther detail and try to give some insight into the topic of energy markets. The
3rd chapter covers the implementation, testing and evaluation of the extension
application for digitalSTROM that was developed in this thesis. We discuss and
evaluate load-balancing algorithms that make use of the user configured devices
in the chapter 4. Then in chapter 5 we propose a method to detect consumption
patterns of devices by just looking at the overall consumption of the household.
Finally in the chapter 6 we try to analyze the proposed load-balancing system
from the users point of view.
1
http://inergie.ch
2
http://www.aizo.com
3
http://www.digitalstrom.org
Chapter 2
digitalSTROM
R
• digitalSTROM Meter (dSM): Several dSMs are deployed in the fuse box
of a building. There is one needed for every current circuit in the building.
It communicates with the clamps in the building over power line and with
other dSM s over an RS485 bus.
• Clamps are deployed everywhere in the house. Every power plug, every
light bulb, every light switch and every device that should be used with
digitalSTROM has to be equipped with a clamp. As seen in the figure 2.1
there exist several types of clamps. These are categorized in color groups
to do auto configuration. The black joker clamp can be configured to any
other color. Every clamp in the system has its unique digitalSTROM ID
3
2. digitalSTROM
R 4
(dSID), that it used to identify and address the clamp. The functionality
provided is different for each clamp type. A light clamp for example con-
tains the hardware to dim and switch loads up to 150W. A blind clamp
includes two relays to drive the blind’s motors.
• Use a normal light switch to configure the system with specialized patterns
of clicks.
• Use the the web User Interface (UI) of the dSS that has to be connected to
the local network infrastructure. A screenshot of the web UI can be seen
in the figure 2.3.
For further information about the usage and configuration of the system take a
look at the users manual on the digitalSTROM website [1].
During my thesis I mainly worked with the dSS. The dSS is an ARM powered
device running an embedded Linux operating system. I wrote an extensions
program (app) that can be installed on the dSS using the apps page of the
2. digitalSTROM
R 5
dSS
dSID
dSID dSID
dSM
dSID
dSID dSID
dSM
RS485 bus
(a) Apps
• Scripts written in JavaScript that are interpreted by the dSS main process
on event raises.
In the last decade many countries removed the strict regulations of electricity
markets [6]. The price of electricity or energy in general is now determined by
the economic rule of supply and demand. Let me give some insight into this
topic, that is required to understand all aspects of the system. Because of the
fact that electricity can not be stored efficiently, a system operator is needed
that matches supply and demand [8]. Stakeholders of energy markets are:
• Electricity generators.
• Electricity providers that sell electricity to households for fixed prices (day
and night tariff).
• Speculators.
• Large companies with large energy needs that directly buy their energy on
the market.
1
http://developer.digitalstrom.org/download/dss/1.4/dss-1.4.2-doc/dss-1.4.2-json api.html
2
http://developer.digitalstrom.org/download/dss/1.4/dss-1.4.2-doc/dss-1.4.2-soap api.html
3
https://developer.mozilla.org/en/SpiderMonkey
2. digitalSTROM
R 8
This market is intended for long-term trades. In the year 2011 you can already
buy energy that will be consumed in 2015. The amounts of traded electricity on
this market is very large and the prices are rather stable.
On the spot market the stakeholders trade energy for about the next week. The
prices on this market are still quite stable.
The intraday market serves electricity requests and offers for about the next 24
hours. The prices of this market underlie large fluctuations as seen in the figure
2.4. There sometimes even occur negative electricity prices because it is cheaper
for an atomic power plant to pay for its produced energy than to shut down the
reactor. The traded volume on the intraday market is very small compared to
the derivatives market.
4
http://www.eex.com/en/Market%20Data
2. digitalSTROM
R 9
200
150
Price in €/MWh
100
50
0
-50 lowest
-100 highest
last
-150
00 06 12 18 00 06 12 18 00
Time
Figure 2.4: Price curves in the time between 27.11.2011 00:00 and 28.11.2011
24:005 on the German electricity market. Note that such low negative prices are
very rare. Normally the prices stay positive.
5
http://www.epexspot.com/en/market-data/intraday/intraday-table/2011-11-27/DE
Chapter 3
Smart-Grid App
This chapter describes the smart-grid app I developed for the dSS.
3.1 Idea
The user has to have full control over everything that is sent to the energy
provider. This principle should facilitate the acceptance by the users and is
important for privacy issues as discussed further in the section 6.3.
The user specifies devices to which the energy provider has access. The en-
ergy provider then can remotely start up or shut down the configured devices
according to the rules the user specified. The compliance with the rules is en-
forced by the local digitalSTROM installation. But the energy provider has all
the freedom to act within the specified rules.
3.2 Configuration
The user of the digitalSTROM installation has to configure the devices in the
configuration web UI of the smart-grid app, as seen in figure 3.1.
Figure 3.1: The web configuration UI start screen of the smart-grid app.
10
3. Smart-Grid App 11
Using the configuration pop up as seen in figure 3.2 each device in the dig-
italSTROM installation can be configured to be in one of the following three
states according to the smart-grid algorithm:
• Excluded from the algorithm. The device will always work no matter what
the energy provider does. The energy provider is not going to receive
information about this device.
• Delayed ON: a device in this state is normally OFF. If it is used its start
may be delayed by the energy provider according to the rules specified.
• Short period OFF: a device in this state is normally ON. It can be powered
OFF by the energy provider for a short time if there is not enough energy
available.
3.2.1 Delayed ON
This group contains devices of which the start time is not that relevant. For
example if we have an electric car we don’t actually care when it is charged but
we care that it is charged in the morning when going to work. Other typical
devices that could be configured with this state are:
• Boiler
• Dish washer
3. Smart-Grid App 12
A delay ON device is given a time slot that has to be longer than the time the
device needs to be powered ON. To simplify the configuration a device cannot
be powered OFF if it is once started until the minimal ON time is reached.
The system’s task is now to ensure that the device is at least powered ON for
its minimal ON time during the slot given. The parameters that have to be
specified for a device in this group are listed in the following table:
Parameter Description
Slot start The slot start can either be given as an absolute time or dy-
namically by detecting the presence of a selectable clamp. The
second possibility is discussed in the section 3.6.
Slot length The length of the slot.
ON time The minimal time for which the connected device should be pow-
ered ON during the slot.
Short OFF devices are normally powered ON but it does not matter if they are
shut OFF for a short amount of time. A typical short OFF device is an electric
heater that does not need to heat exactly at the consumption peek. Normally it
does not matter if its powered OFF for some minutes. The room will not cool
down very much during that time. Other typical devices that could be configured
short OFF are:
• Heat pump
• Freezer
• Air conditioner
A short OFF device is given a slot length and a maximal OFF time in this slot.
The system then ensures that the device is powered OFF for maximally the
given amount of time inside the slot. The slot is automatically repeated after its
expiration. The following table shows the parameters of a short OFF device:
Parameter Description
Slot length The length of a slot.
OFF time The maximal time the device can be powered OFF during a slot.
The device configured with the parameters stated in the table 3.1(b) is a de-
vice that is normally ON. In an interval of six hours it can be turned OFF for
maximally twenty minutes.
3. Smart-Grid App 13
Configuration of devices
Overall household
consumption prediction
The device configured with the parameters stated in the table 3.1(a) is a
device that is normally OFF. The slot of the device starts on January 25, at
17:30 and ends 12 hours later on January 26, at 05:30. In this slot the device
has to be powered ON for at least 4 hours. Its latest starting time is therefore
January 26, at 01:30.
3.3 Dataflow
The protocol between the building and the electricity provider is sketched in the
Figure 3.3. An outline of the protocol would look like this:
1. The building sends its configuration values for all devices, that are con-
figured short OFF or delay ON, to the energy provider. If some sort of
consumption pattern information of the devices is available this is sent as
well.
2. The building periodically sends a prediction of the consumption for the
next time unit to the energy provider.
3. The energy provider computes commands that will be sent to the building
to trigger its configured devices.
This provides a mechanism for the energy provider to control the devices config-
ured by the user. The prediction of the household consumption can be used at
the provider’s side to improve the overall consumption prediction.
3. Smart-Grid App 14
3.3.1 Protocol
<consumptions>
<item>
<timestamp>
Mon, 30 Jan 2012 09:33:01 GMT
3. Smart-Grid App 15
</timestamp>
<value>31</value>
</item>
...
</consumptions>
<config>
<item>
<type>off</type>
<id>3504175fe0000000000075cc</id>
<slotLength>3600</slotLength>
<offTime>3540</offTime>
</item>
<item>
<type>on</type>
<id>3504175fe000000000015227</id>
<startTime>Mon, 30 Jan 2012 10:38:43 GMT</startTime>
<slotLength>3600</slotLength>
<onTime>60</onTime>
</item>
...
</config>
The id transmitted in the message is the dSID of the configured device used to
identify the device in the household.
The only way to conserve data between multiple runs of the JavaScript inter-
preter is to save the data in the so called property tree. This is an XML file
that is accessible with some helper function of the internal JavaScript API or
the JSON / SOAP APIs. I used the property tree extensively in the smart-grid
app because it is the only way to store data between scopes. The property tree
node of my app contains the following entries:
3. Smart-Grid App 16
Entry Description
serverAddress Address of the server of the energy provider to con-
nect to.
serverPort Port of the server of the energy provider to connect
to.
pollInterval Time that specifies when the next check for a still
available connection to the energy provider should
happen.
startupPerformed This entry is never written to the xml file but just
kept in the cached version of the property tree by
the dSS. It is used to check whether the script is
launched for the first time.
clockDriftOK and These entries are used to make sure that the energy
checkingClockDrift provider’s and the dSS’s clock are more or less syn-
chronized.
timeLastDataReceived Used to check if the connection to the energy
provider is still open.
sendRequest A flag to signal that the configuration of a device
has changed. The next time the dSS is polled by the
energy provider it should send its new configuration
if this flag is set.
pollEventId Used to store the event id of the delayed poll event
if the poll interval changes and the event has to be
rescheduled.
Of course also all the configuration of the devices need to be stored in the
property tree. Each device has its own node inside the app node. In this device
node all the information about the device is stored.
The property tree can be viewed through the web user interface of the dSS
under SW: System > System Properties.
Like the main user interface of the dSS also my app builds on the JavaScript
ExtJS4 framework by Sencha1 . ExtJS4 is a very rich JavaScript library2 that
introduces known concepts of object oriented programming, like classical inher-
itance and mixins, to JavaScript. It comes along with many ready to use UI
components. To use the same library simplified many tasks: for example I could
directly use the template of the already existing digitalSTROM apps. The web
interface communicates with the dSS via the JSON interface. With the JSON
1
http://www.sencha.com
2
http://docs.sencha.com/ext-js/4-0/
3. Smart-Grid App 17
interface it is directly possible to read and write the property tree as well as
raising events that may trigger executions of app JavaScript code on the dSS.
For the delay ON devices I implemented a mechanism to start a new slot au-
tomatically if a specified device is connected to a power plug. For example the
system can detect that the electric car has been connected to a power plug and
then automatically start the slot with the configured ON time and slot length.
The idea was to have a digitalSTROM clamp between the device and the power
plug that is disconnected from the power line if the device is disconnected. Then
the system can check the presence of that clamp and react accordingly. The
presence detection of a clamp turned out to be not trivial. Because of the lim-
ited bandwidth on the power line the presence of devices is just checked once a
day. This means that the dSS normally does not know if a device is present or
not. But the dSS can communicate via the dSMs with the clamps. So a presence
detection of a clamp can look like this:
1. Ask the corresponding dSM of a clamp via RS485 about the current status
of the clamp.
2. The dSM asks the clamp over the power line.
3. If the clamp is present it answers to the dSM with its current status.
4. If an answer is received on the dSM it is sent back to the dSS over the
RS485 bus.
If the clamp answers then it has to be present. If it does not answer this does not
mean that it is not present. There could have been a collision on the power line
leading to packet loss from the clamp. But if it still not answers after another
try then it is likely that the clamp is not present. Unfortunately the limited API
hindered the straight implementation of this idea. There is currently no function
in the internal app JavaScript API to get the status of a clamp, but there is one
in the JSON API. So I had to find a way to access the JSON API from inside
the dSS. From outside, the JSON API is accessible through an SSL encrypted
HTTP channel. From inside, the JSON API can be contacted over an insecure
HTTP channel but a token is needed to get access to all the functionality. This
token can be retrieved over the insecure channel as well by authenticating with
username and password. This means I had to build up HTTP requests that were
sent over a TCP connection to localhost. From the replies parsed with a JSON
parser the data could be extracted.
The way this problem was solved is not very nice but there is currently no
better solution.
3. Smart-Grid App 18
Figure 3.4: Screen shot of the energy provider demo application. Because there
is just one client connected the consumption curves for the sum and the single
client cannot be differentiated. The library that was used to display the graph
is called JFreeChart3 .
During the work we used a digitalSTROM installation box that was provided by
aizo. The box contained everything that was needed for the development of the
app. A picture of the demonstration box can be seen in the figure 3.5.
To test the system in a more realistic environment we deployed it in the
demonstration apartment of aizo. In the demonstration apartment we configured
two devices to be used with the system. The first device was an Electrolux
3
http://www.jfree.org/jfreechart/
3. Smart-Grid App 19
Figure 3.5: Demonstration box containing switches, light bulbs and power sock-
ets. The top left fuse box contains a dSF, two dSMs and a dSS. The bottom
left fuse box contains an earth leakage circuit breaker, some fuses and the power
supply for the dSS.
(a) Segway and freezer. (b) The laptop is connected to the tempera-
ture sensor and reads out its value every 10s.
4 DS1820 data
Schottky 1.5k
diode
3
Figure 3.7: Schema to connect the DS1820 temperature sensor to the serial port.
The temperature sensor used was a DS1820 sensor6 connected to the serial
bus of the computer using the schema in the figure 3.7. The open source software
to read out the temperature value of the sensor is called digitemp7 .
The devices worked as expected. For the Segway the only criterion the system
had to fulfill was that it was charged within 20 hours after plugged in. Because
the Segway was not used very much during this time the results were not very
informative. But it was always charged when used.
The freezer could be analyzed much better because there was temperature
information available. The freezer was configured to −20◦ C. First the figure
3.8(a) shows the temperature of the empty freezer without the load-balancing
system working. As you can see the freezer is cooling in almost equidistant
intervals keeping the temperature below −20◦ C. The figure 3.8(b) shows the
temperature curve of the same freezer but this time it was filled with thirteen 1.5
liter bottles of water. As you can see the cooling intervals are now slightly longer
because water is a much better cold accumulator than air. The figures 3.9(a)
6
http://datasheets.maxim-ic.com/en/ds/DS18S20.pdf
7
http://www.digitemp.com/
3. Smart-Grid App 21
Temperature in °C -18
-19
-20
-21
-22
-23
00:00 01:00 02:00 03:00 04:00 05:00 06:00
Time
-18
Temperature in °C
-19
-20
-21
-22
-23
00:00 01:00 02:00 03:00 04:00 05:00 06:00
Time
and 3.9(b) show the temperatures with activated load-balancing algorithm. The
freezer was powered OFF manually, using the demonstration energy provider
application, for 10 minutes at the times:
• 11:06:23
• 12:59:13
• 14:21:47
• 15:34:39
Temperature in °C -18
-19
-20
-21
-22
-23
00:00 01:00 02:00 03:00 04:00 05:00 06:00
Time
-18
Temperature in °C
-19
-20
-21
-22
-23
00:00 01:00 02:00 03:00 04:00 05:00 06:00
Time
the freezer is exactly powered off in this time this could increase the temperature
to a level that damages the goods inside the freezer. So the system should be
deployed directly in the freezers software to have a way to take the temperature
into account.
Chapter 4
Load-Balancing Algorithms
In this chapter we want to address the problem of actually using the device data
provided by the user at the energy provider. There are many possibilities to use
this information. In our two approaches we focused on the principle of using
the available energy. This is also what would increase the user’s acceptance.
An energy provider could also try optimize the problem with the focus on other
criterion, like the increase of its winnings. However in this thesis we only focused
on the constraint to use the available energy as efficient as possible. Under this
point of view the optimal load-balancing algorithm minimizes this equation:
Z∞
|availability(t) − consumption(t)| dt (4.1)
t=0
The idea of this first algorithm is to just react on under / over runs as seen in fig-
ure 4.1. No prediction is involved. Just the actual availability and consumption
values are compared and actions are taken based on these.
energy
Figure 4.1: Illustration of the idea of the simple algorithm. Just the availabilities
and the consumptions are compared.
23
4. Load-Balancing Algorithms 24
1 o v e r r u n := f a l s e ;
2 underrun := f a l s e ;
3 measure consumption and a v a i l a b i l i t y ;
4 d e l t a := abs ( consumption − a v a i l a b i l i t y ) ;
5 number := d e l t a / a v g d e v i c e c o n s u m p t i o n ;
6 i f consumption > a v a i l a b i l i t y then begin
7 f o r i := 0 to number do begin
8 i f a d e v i c e c a n b e t u r n e d o f f then begin
9 turn off that device ;
10 end ;
11 e l s e begin
12 o v e r r u n := true ;
13 Break ;
14 end ;
15 end ;
16 end ;
17 e l s e begin
18 f o r i := 0 to number do begin
19 i f a d e v i c e c a n b e t u r n e d o n then begin
20 turn on device ;
21 end ;
22 e l s e begin
23 underrun := true ;
24 Break ;
25 end ;
26 end ;
27 end ;
28 i f o v e r r u n then begin
29 turn off power plants ;
30 end ;
31 e l s e i f underrun then begin
32 turn on power plants ;
33 end ;
Listing 4.1: Pseudo code of a reacting algorithm.
4. Load-Balancing Algorithms 25
Availability
energy
Time
Figure 4.2: The devices have to be scheduled to be finished before their deadlines
(vertical lines). The rectangles represent the energy consumption period of a
device.
The algorithm just needs measurements of the availability and the consump-
tion and an estimation of the average consumption of a device. If there is con-
sumption information available for the specific devices one does not have to rely
on the average consumption estimation but instead directly use the consumption
information of the device to turn ON / OFF. The running time of the algorithm
depends on the underlying data structures. With n devices the search for a de-
vice that can be turned ON / OFF takes O(log(n)) if the devices are stored in an
interval tree where the intervals are the times when a device can be turned ON /
OFF. The worst case is if we have to find n devices to turn ON / OFF. Therefore
we get a running time of O(n log(n)). There may be better data structures but
even with an interval tree the running time is acceptable.
A good heuristic is to start the device at the first point in the interval where
g(t) = f(t) − consumption of device(t) is positive. There are 3 possibilities where
this first positive point can occur.
2nd case g(t) does have one or multiple zero points in the interval I. We can
compute one of them assuming g(t) to be continues with the Newton method.
We have to repeat the Newton method multiple times with changing intervals to
make sure that we found the smallest zero point.
3rd case g(t) is not positive in the interval I. In this case we apply another
heuristic. We first compute a local maximum of g(t) in the interval I. Again
assuming the g(t) to be continuous we can apply a binary search on the interval.
Now we know that at that point where g(t) is maximal the device should run
because it would have the least impact on the system. The actual starting point
4. Load-Balancing Algorithms 27
Intuitively the starting point of the device is computed by taking the point with
largest availability and subtracting a factor of the ON time of it because the
device should already run at this time point. The factor depends on the position
of the largest availability point in the interval I.
We did not have the possibility to deploy the system in a real village or town,
that is why we simulated the algorithms. Our simulations are not that close to
reality because of the lack of information and data. Some shortcoming of the
simulations are:
70
Electricity Production in GW
60
50
40
solar
30 wind
conventional
20 sum
10
0
00 02 04 06 08 10 12 14 16 18 20 22
Time
Figure 4.3: Average of the electricity production between November 21, 2011
and December 12, 2011.
We simulated the algorithms for 200, 2’000, 20’000 and 200’000 devices.
These numbers represent a small village, a large village, a small and a large
town. About 1/3 of the devices were excluded from the algorithm, 1/3 were de-
lay ON and the last 1/3 were short OFF devices. There is no particular reason
why one should choose 1/3 of the devices. In a real environment the percentage
of configured devices may be much smaller. But we wanted to have clearly visible
effects on the consumption characteristics in the simulations. The overall con-
sumption of the whole system was evaluated every 60 seconds. The parameters
of the devices were assigned randomly in the following ranges:
Parameter Range
Consumption [0W, 2000W ].
ON time [1min, 4h]
Slot length [ON time, 8h]
Next slot start in [0, 24h]
Parameter Range
Consumption [0W, 2000W ].
OFF time [1min, 4h]
Slot length [OFF time, 24h]
4.3.1 Results
In the figure 4.4 you can see the results of the simulation for 3 days. The figure 4.5
shows the function ∆(t) = availability(t) − consumption(t) for both algorithms.
Finally the figure 4.6 shows the function
Zx
|∆(t)| dt
t=0
Both algorithms can not fulfill all the peak situations. But this was expected
because there is a moment when all devices are turned ON or OFF and there are
no more possibilities to do further corrections on the consumptions. The first
peak can be served but then for the second peak no more devices are left that
could be powered on in both algorithms. As you can see the simple algorithm
performed better with many devices than the more sophisticated packing algo-
rithm. This is mainly because of the fact that with many devices the expectations
match reality closer than with few devices. On the contrary, the packaging al-
gorithm performs slightly better with fewer devices. This is because with few
devices the scheduling of the delay ON devices is much more important.
4. Load-Balancing Algorithms 30
125 1150
120
1100
115
110 1050
Energy in KW
Energy in KW
105 1000
100
950
95
90 900
85 simple 850 simple
80 packaging packaging
no algorithm 800 no algorithm
75 availability availability
70 750
0 12 24 36 48 60 72 0 12 24 36 48 60 72
Time in h Time in h
11.5 115
11 110
10.5 105
Energy in MW
Energy in MW
10 100
9.5 95
9 simple 90 simple
packaging packaging
8.5 no algorithm 85 no algorithm
availability availability
8 80
0 12 24 36 48 60 72 0 12 24 36 48 60 72
Time in h Time in h
20 120
Availability - Consumption in KW
Availability - Consumption in KW
100
15
80
10 60
40
5 20
0 0
-20
-5 -40
-60
-10 simple simple
packaging -80 packaging
-15 -100
0 12 24 36 48 60 72 0 12 24 36 48 60 72
Time in h Time in h
0.6 6
Availability - Consumption in MW
Availability - Consumption in MW
0.4 4
0.2 2
0 0
-0.2 -2
-0.4 -4
-0.6 -6
1400
250
1200
200
1000
150 800
600
100
400
50
simple 200 simple
packaging packaging
0 0
0 12 24 36 48 60 72 0 12 24 36 48 60 72
Time in h Time in h
12 120
10 100
8 80
6 60
4 40
2 20
simple simple
packaging packaging
0 0
0 12 24 36 48 60 72 0 12 24 36 48 60 72
Time in h Time in h
Figure 4.6: Integral of the absolute difference for four days. This represents the
amount of energy that could not be compensated by the algorithms.
Chapter 5
The goal is to differentiate devices just by looking at the overall metering data.
One approach is to apply a discrete Fourier transformation on the consump-
tion data. Doing this we get a vector in the frequency domain. The most
33
5. Device Detection and Consumption Prediction 34
400
Measured consumption
350
Device detection
Consumption in W
300
250
200
150
100
50
0
04:00 08:00 12:00 16:00 20:00 00:00 04:00 08:00 12:00
Time
(a) Overall consumption curve and prediction curve of a single device. The prediction curve is
scaled to improve visibility.
180
160
140
120
Amplitude
100
80
60
40
20
0
0 1 2 3 4 5 6
Frequency in 1/h
Figure 5.1: The overall consumption curve is transformed to its frequency spec-
trum. From that spectrum the frequency with the most impact is extracted
(about 1.2 h1 ) and transformed back to the time domain.
5. Device Detection and Consumption Prediction 35
interesting frequencies are now between 0.5 h1 and 2 h1 because we expect device
patterns in the interval [0.5h, 2h]. Lower frequencies originate from large peaks
and larger frequencies belong to noise. Now we extract the frequency with the
largest impact in the interval [0.5h, 2h] and transform it back to the time domain
using an inverse discrete Fourier transformation. This gives us a sine curve with
the positive peaks at the moments where the device is most probably active.
Multiple devices can be extracted like this and their active times extrapolated.
The whole process is illustrated in the figure 5.1.
Energy providers know these predictions very well. This is why the whole energy
system works at all these days. To improve those predictions the household could
compute some local predictions and send them to the energy provider. To do
this as accurate as possible it would be nice to have per device consumption
information about the last few days. With such information one could compare
the last days per device, try to find some patterns in the consumption, and
give predictions per device. The power provider is not interested in per device
predictions so the delivered result would be the sum over all devices.
To find consumption information of single devices in a digitalSTROM instal-
lation the proposal of [7] could be used. An overall meter is available as well
as the ON / OFF state information of the different devices (with some delay
however).
A possible model to predict the consumption for the next few hours is an
artificial Elman neural network. Something like this has already been done in
[2]. As input we could use
• Holiday information.
Social Aspects
In this section we try to answer the question what appeals could be created to
encourage households to participate the system. The only one actually profiting
from such a system directly is the energy provider. Of course a single household
also wins from the system because fewer power outages may happen. But this
is just a weak indirect benefit because the system cannot guarantee that no
blackouts occur. Therefore the energy provider has to share its benefit with its
customers. Otherwise very few would see a reason to participate.
How to share the benefits is now a question for sales people but we also
made some thoughts about it. A possibility would be to grant price reductions
either proportional to the number of devices that are configured to load-balance
or proportional to their power consumptions. For the latter exact information
has to be available for the devices. With such a stimulation the households that
have the system installed are animated to configure and use as many devices as
possible with the system.
Another appeal to participate in such a project would be to increase the
awareness of sustainability. Who does not want its own children or grand chil-
dren to live in the same world as we do these days. To ensure this we have
to fundamentally change our habits and consumer behavior. A load-balancing
system can not do this but it can help to go forward into the right direction.
6.2 Security
At the moment the implementation of the system does not use industry standard
security mechanisms. All the communication between the household and the en-
ergy provider is not encrypted and there are no authentication checks performed.
An attacker can read all the information sent in plain text. However he cannot
do much harm to the system because all the rules are enforced on the dSS. Of
36
6. Social Aspects 37
course an attacker can prevent the usage of household devices for load-balancing
or even use them to worsen the problem.
All those security issues have to be fixed before professional use of the system.
At least all the communication has to be encrypted and the energy provider has
to authenticate itself to the dSS.
6.3 Privacy
There may be concerns about the energy provider knowing about the devices of
a household. Of course the energy provider knows more about a household using
the smart-grid app than about one not using it. But the household also benefits
from a bonus. This bonus comes with the cost of giving information to the energy
provider. With the configuration possibility of the user the information given
to the energy provider can be specified very fine grained. The user can specify
exactly what the energy provider should see.
The main problem about privacy is that the energy provider is able to map
devices to households. This problem could be solved by using a peer to peer
network among all households participating in the load-balancing system. The
configuration would then be sent along a path in the peer to peer network. Every
node in the network just knows where it received the packet from and where it
has to send it to. A system like this is described in [10]. The crowds system works
without encryption. This simplifies the deployment because no key distribution
is required. The principle of the crowds system is the following: On receiving a
request from another node in the crowd the node flips a coin whether to send
the request to its destination or to send it to another node in the crowd. The
packet may be forwarded many times until it reaches its destination. The path a
packet takes to the destination is therefore random and the energy provider has
no information about the origin of a packet. A configuration packet for a device
could belong to any household that participates in the crowd. Every node has
to record where the packets it forwards were received from, to be able to return
the resulting answer on the same path. To introduce encryption such that not
everyone in the crowd that receives a message can read it, the original sender can
encrypt its message with the energy providers public key. This way it is ensured
that only the energy provider can read the message. The other direction is more
complicated because we can not tell the energy provider the public key of the
sender. If it knew the public key of the sender it could create a mapping from
device to household again. A possibility would be that the household includes
a random key in its message. The energy provider can decrypt the key in the
message and use it to symmetrically encrypt the messages it wants to send to
the household belonging to the request. This ensures that the answer message
can just be seen by the original sender because he is the only one that knows the
key. An illustration of the protocol is given in the figure 6.1.
6. Social Aspects 38
{M , K A }K E
{M , K A }K E
A B
{M }K A
{M }K A
E
Figure 6.1: Household A generates a random key KA and adds this key to its
message. It decides to send the request to a random node in the crowd. Node B
receives the message and decides randomly to send the packet to its destination.
It records the route to be able to deliver the response on the same path. The
energy provider E can decrypt the packet with its secret key and use the key KA
to encrypt information to A with a symmetric encryption scheme. Note that A,
B, and E do not stand for Alice, Bob and Eve in this example but for A, B and
E.
Chapter 7
As the energy production has to shift towards renewable energy, we have to start
thinking about load-balancing power consumption. My approach seems to be a
natural extension of the ripple control system1 [9]. It is much more flexible and
supports bidirectional communication.
The experiments with the freezer and the Segway showed that the system
can be used with typical household devices. Because the user can configure the
devices by itself the system is very flexible and can be adapted to a very wide
range of environments. There is some work needed to better integrate with the
devices but in general the approach works. One serious problem is that you don’t
always want to set the time a device should be finished with a web UI from your
computer. Instead the system should be integrated directly into the UI of devices
that can be used to load-balance. For example you want to directly set the time
the washing machine should be finished on the washing machine itself. To use
the system with a washing machine that does not include the load-balancing
system but can be powered ON / OFF with digitalSTROM the following steps
are needed:
2. Power OFF the machine by switching the energy off using digitalSTROM.
From the point of view of the washing machine this looks like a power
outage.
3. Configure the machine to be finished at the desired time using the config-
uration UI of the smart-grid app.
4. Hope that the machine resumes the last program before the power outage
when powered ON again.
This solution would not be applicable. To improve this issue an open standard,
to load-balance devices, has to be defined that can interface with different bus
1
http://www.rundsteuerung.de
39
7. Conclusions & Future Work 40
[3] D. Berner. Halbzeit beim projekt ismart in ittigen. Bulletin des SEV VSE
Including Jahresheft, 102(9):18, 2011.
[8] J.J. Lucia and E.S. Schwartz. Electricity prices and power derivatives: Ev-
idence from the nordic power exchange. Review of Derivatives Research,
5:5–50, 2002. 10.1023/A:1013846631785.
[10] M.K. Reiter and A.D. Rubin. Crowds: anonymity for web transactions.
ACM Trans. Inf. Syst. Secur., 1:66–92, November 1998.
41
Bibliography 42
[12] L. Wei, A. Lim, and W. Zhu. A skyline-based heuristic for the 2d rectangular
strip packing problem. In Kishan G. Mehrotra, Chilukuri K. Mohan, Jae C.
Oh, Pramod K. Varshney, and Moonis Ali, editors, IEA/AIE (2), volume
6704 of Lecture Notes in Computer Science, pages 286–295. Springer, 2011.
http://www.computational-logistics.org/orlib/topic/2Dx.html.
[13] L. Wei, D. Zhang, and Q. Chen. A least wasted first heuristic algorithm for
the rectangular packing problem. Comput. Oper. Res., 36:1608–1614, May
2009.
Appendix A
Implementation Notes
The smart-grid app subscribes to two events. First it is called on the “running”
event. This event is emitted after starting the main process of the dSS. Further
it subscribes to the “smart-grid” event. This event is raised by the smart-grid
app itself. If the event “smart-grid” is raised, the parameter action type has
to be set in the event. This parameter specifies the type of event that occurred.
The following values of action type are used so far:
Value Description
config The user changed the energy provider configuration of the
app in the UI. Parameters that belong in this group are the
address and port of the energy providers server.
poll This event is raised by the script itself. On this event the
script performs a check if the connection is still open.
configDevice The user changed the configuration of a device in the UI.
shortOffReset This event is raised by the script itself. On this event a short
OFF device that is shut down is reactivated.
delayOnStart The delay ON devices can be given a starting time. On their
starting time this event is raised by the app itself and the
device is started.
delayOnReset This event is raised by the script if a delay ON device needs
to be powered OFF again.
A.1.2 Script
• jsonparser.js
1
A. Implementation Notes 2
• rexml.js
• smartgrid.js
The first two are libraries used to parse and create JSON and XML strings. The
script we implemented is contained in the file smartgrid.js.
The UI part of the app consists of the following directories and files:
Folder / File Description
dss This folder contains the app framework provided by aizo.
It uses the ExtJS4 library to create special UI components.
Further the framework defines a unique look and feel for
all apps.
ext This folder contains the ExtJS4 library.
jsgettext This folder contains a JavaScript implementation of get-
text. With this library the app could be translated with
little effort at a later time.
time.js This is a UI element to display and edit a time in hours
and minutes.
deviceWindow.js This file describes the main window of the smart-grid con-
figuration UI.
configWindow.js Contains the configuration pop up window of a device.
main.js This file is also part of the app framework by aizo. This
file contains the entry method for the whole UI.
The simple demonstration energy provider program is written in Java. For the
communication with the different clients it uses the java.nio library. This
library can be used to do non-blocking IO operations in Java. In the following
table all classes implemented are listed with their purpose:
A. Implementation Notes 3
Class Description
Client.java Represents a client.
Controller.java This class implements the algorithm that controls
the devices. In my demo application this algo-
rithm is very easy.
Device.java Contains features that are available for all de-
vices.
DelayOnDevice.java Extends the Device class and adds all the features
needed to manage delay ON devices.
ShortOffDevice.java Extends the Device class and adds functionality
for short OFF devices.
DSSServer.java This class manages all the communication with
the clients.
EnergyProvider.java This class contains the main method of the whole
program and implements the UI.
Logger.java Contains code to do nice logging.
SingletonUtil.java Implements the singleton pattern and contains
tool objects that can be reused globally.
IntradayMarketPoint.java This class is not used any more. Its original
purpose was to represent a data point from the
intraday electricity market. Unfortunately the
platform eex.com where the intraday market was
fetched from changed its website such that the re-
trieval of the information would have to be reim-
plemented. I never used the information in my
Controller class but just used it do display the
actual electricity price in a chart. Because of this
I decided to not reimplement the feature.
A.3 Simulation
The simulations created in this thesis were all implemented using python. In
the beginning I implemented all the simulations in a single threaded design.
For the 200’000 devices this turned out to be quite slow. The choice of python
turned out to be a bad decision because the Global Interpreter Lock (GIL)
made a simple expansion to a multithreaded solution impossible. The GIL is
a mechanism in python that just allows one running instance of the interpreter
per process at any point in time. This simplifies the internal implementation of
python but leads to a maximal core utilization of 1 with a single process. There
exists a python interpreter called Jython1 implemented in Java that allows full
multithreading. However this implementation was not really faster than the
1
http://www.jython.org/
A. Implementation Notes 4
Source Code
This chapter contains all the source code that was written for this thesis. Li-
braries that were used are not included. See a list of listings below:
B.1 config/smart-grid.xml . . . . . . . . . . . . . . . . . . . . . . . . 6
B.2 scripts/smartgrid.js . . . . . . . . . . . . . . . . . . . . . . . . . . 6
B.3 ui/js/configWindow.js . . . . . . . . . . . . . . . . . . . . . . . . 21
B.4 ui/js/deviceWindow.js . . . . . . . . . . . . . . . . . . . . . . . . 23
B.5 Client.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
B.6 Controller.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
B.7 Device.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
B.8 DelayOnDevice.java . . . . . . . . . . . . . . . . . . . . . . . . . 35
B.9 ShortOffDevice.java . . . . . . . . . . . . . . . . . . . . . . . . . 36
B.10 DSSServer.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
B.11 EnergyProvider.java . . . . . . . . . . . . . . . . . . . . . . . . . 40
B.12 Logger.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
B.13 SingletonUtil.java . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
B.14 IntradayMarketDataPoint.java . . . . . . . . . . . . . . . . . . . 45
B.15 device.py . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
B.16 simulation.py . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
B.17 integrate.py . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
5
B. Source Code 6
B.1.2 Script
1 /∗
2 ∗ T h i s p r o g r a m i s f r e e s o f t w a r e : you can r e d i s t r i b u t e i t and / o r m o d i f y
3 ∗ i t u n d e r t h e t e r m s o f t h e GNU G e n e r a l P u b l i c L i c e n s e a s p u b l i s h e d b y
4 ∗ t h e Free S o f t w a r e Foundation , e i t h e r v e r s i o n 3 o f t h e License , or
5 ∗ ( a t y o u r o p t i o n ) any l a t e r v e r s i o n .
6 ∗
7 ∗ This program i s d i s t r i b u t e d i n t h e hope t h a t i t w i l l be u s e f u l ,
8 ∗ b u t WITHOUT ANY WARRANTY; w i t h o u t e v e n t h e i m p l i e d w a r r a n t y o f
9 ∗ MERCHANTABILITY o r FITNESS FOR A PARTICULAR PURPOSE . See t h e
10 ∗ GNU G e n e r a l P u b l i c L i c e n s e f o r more d e t a i l s .
11 ∗
12 ∗ You s h o u l d h a v e r e c e i v e d a c o p y o f t h e GNU G e n e r a l P u b l i c L i c e n s e
13 ∗ along with t h i s program . I f n o t , s e e < h t t p : / / www . gnu . o r g / l i c e n s e s / >.
14 ∗
15 ∗ C o p y r i g h t ( c ) 2011 digitalSTROM . org , Zurich , S w i t z e r l a n d
16 ∗ A u t h o r : C h r i s t o f Baumann <b a u m a c h r @ s t u d e n t . e t h z . ch>
17 ∗ B a s e d on w o r k o f : A n d r e a s B r a u c h l i <a n d r e a s . b r a u c h l i @ a i z o . com>
18 ∗/
19
20 var LOGFILE NAME = ’ s m a r t - g r i d . l o g ’ ;
21 var LOG = new L o g g e r (LOGFILE NAME) ;
22
23 var LOG PRIORITY = 1 0 ;
24
25 function l o g ( t e x t , p r i o r i t y ) {
26 i f ( p r i o r i t y < LOG PRIORITY) {
27 var c a l l s t a c k = " " , c a l l e r , c a l l e r N a m e , l i n e ;
28 try {
29 i . dont . e x i s t +=0; // d o e s n ’ t e x i s t − t h a t ’ s t h e point
30 } catch ( e ) {
31 i f ( e . s t a c k ) { // F i r e f o x
32 //LOG. l o g l n ( e . s t a c k ) ;
33 c a l l s t a c k = e . stack . s p l i t ( ’\ n ’) ;
34 // Remove c a l l t o p r i n t S t a c k T r a c e ( )
35 callstack . shift () ;
36 }
37 }
38 caller = callstack [ 0 ] . s p l i t ( ’( ’) ;
39 callerName = c a l l e r [ 0 ] ;
40 i f ( c a l l e r N a m e === ’ ’ ) {
41 callerName = ’ c a l l b a c k ’ ;
B. Source Code 7
42 }
43 l i n e = p a r s e I n t ( c a l l s t a c k [ 0 ] . s p l i t ( ’ . js : ’ ) [ 1 ] , 10) + 1 ;
44 LOG. l o g l n ( ’ [ ’ + c a l l e r N a m e + ’ : ’ + l i n e + ’ ] ’ + t e x t ) ;
45 /∗ v a r i ;
46 f o r ( i =0; i < c a l l s t a c k . l e n g t h ; i ++){
47 LOG. l o g l n ( c a l l s t a c k [ i ] ) ;
48 } ∗/
49 }
50 }
51
52 /∗ ∗
53 ∗ Checks i f t h e system v e r s i o n matches a t l e a s t a g i v e n v e r s i o n
54 ∗ @param v e r s i o n V e r s i o n t o c h e c k a g a i n s t ( i n t h e f o r m a t X . Y . Z )
55 ∗ @return t r u e i f t h e system v e r s i o n i s at l e a s t t h e passed version ,
56 f a l s e o t h e r w i s e , i n c l u d i n g t h e c a s e where t h e v e r s i o n node doesn ’ t e x i s t
57 ∗/
58 function r e q u i r e S y s t e m V e r s i o n ( v e r s i o n ) {
59 var n d S y s V e r s i o n = P r o p e r t y . getNode ( ’ / s y s t e m / v e r s i o n / v e r s i o n ’ ) ;
60 i f ( ndSysVersion ) {
61 var s y s V e r s i o n , r e q V e r s i o n , l e n , i ;
62 sysVersion = ndSysVersion . getValue ( ) . s p l i t ( ’ . ’ ) ;
63 reqVersion = version . s p l i t ( ’. ’ ) ;
64 len = sysVersion . length < reqVersion . length ? sysVersion . length : reqVersion .
length ;
65 f o r ( i = 0 ; i < l e n ; ++i ) {
66 var s y s , r e q ;
67 sys = p a r s e I n t ( sysVersion [ i ] , 10) ;
68 req = p a r s e I n t ( reqVersion [ i ] , 10) ;
69 i f ( r e q < s y s | | ( i === l e n − 1 && r e q === s y s ) ) {
70 return true ;
71 }
72 i f ( req > sys ) {
73 return f a l s e ;
74 }
75 }
76 }
77 return f a l s e ;
78 } // r e q u i r e S y s t e m V e r s i o n
79
80 function t i m e D r i f t C h e c k ( ) {
81 var a l r e a d y C h e c k i n g = P r o p e r t y . g e t P r o p e r t y ( ’ c h e c k i n g C l o c k D r i f t ’ ) ;
82 i f ( a l r e a d y C h e c k i n g !== n u l l && a l r e a d y C h e c k i n g ) {
83 log ( ’ A n o t h e r i n s t a n c e is a l r e a d y c h e c k i n g the c l o c k d r i f t p e r i o d i c a l l y ’ , 3) ;
84 return ;
85 }
86 P r o p e r t y . s e t P r o p e r t y ( ’ c h e c k i n g C l o c k D r i f t ’ , true ) ;
87 timeDriftCheckImpl ( ) ;
88 }
89
90 function t i m e D r i f t C h e c k I m p l ( ) {
91 var h o s t = P r o p e r t y . g e t P r o p e r t y ( ’ s e r v e r A d d r e s s ’ ) ;
92 var p o r t = P r o p e r t y . g e t P r o p e r t y ( ’ s e r v e r P o r t ’ ) ;
93 i f ( h o s t === n u l l | | p o r t === n u l l ) {
94 log ( ’ S e r v e r not s p e c i f i e d . ’ , 3) ;
95 return ;
96 }
97 l o g ( ’ C o n n e c t i n g to ’ + host + ’ : ’ + port , 1) ;
98 var s o c k e t = new Tc pSoc ket ( ) ;
99 s o c k e t . c o n n e c t ( h o s t , p o r t , function ( s t a t e ) {
100 if ( state ) {
101 log ( ’ C o n n e c t e d ’ , 1) ;
102 s o c k e t . s e n d ( ’ < t i m e / > ’ , function ( b y t e s S e n t ) {
103 log ( ’ Sent ’ , 1) ;
104 i f ( bytesSent > 0) {
105 s o c k e t . r e c e i v e L i n e ( 1 0 2 4 , function ( d a t a ) {
106 log ( ’ R e c e i v e d data ’ , 1) ;
107 l o g ( data , 2 ) ;
108 var xmlDoc = new REXML( d a t a ) ;
109 i f ( xmlDoc !== n u l l && xmlDoc . r o o t E l e m e n t !== n u l l && xmlDoc . r o o t E l e m e n t .
t y p e === ’ e l e m e n t ’ ) {
110 i f ( xmlDoc . r o o t E l e m e n t . name === ’ t i m e ’ ) {
111 var now = new Date ( ) ;
112 var t i m e = xmlDoc . r o o t E l e m e n t . t e x t ;
113 log ( ’ Local Time : ’ + now . toUTCString ( ) , 0 ) ;
114 t i m e = new Date ( t i m e ) ;
115 l o g ( ’ S e r v e r T i m e : ’ + t i m e . toUTCString ( ) , 0 ) ;
116 var d r i f t = Math . a b s ( now . getTime ( ) − t i m e . getTime ( ) ) ;
117 log ( ’ D r i f t : ’ + d r i f t + ’ ms ’ , 0) ;
118 i f ( d r i f t < 10000) {
119 P r o p e r t y . s e t P r o p e r t y ( ’ c l o c k D r i f t O K ’ , true ) ;
120 startup () ;
121 }
122 else {
123 log ( ’ C l o c k d r i f t is too l a r g e . W a i t i n g 60 s . ’ , 0) ;
B. Source Code 8
true ) ;
204 Property . s t o r e ( ) ;
205 d t = 1 0 ; // t h e s y s t e m h a s to s e t t l e f i r s t
206 }
207 var e v e n t = new TimedEvent ( ’ s m a r t - g r i d ’ , ’ + ’ + d t , {action type : ’
s h o r t O f f R e s e t ’ , dsid : dsid }) ;
208 var s h o r t O f f E v e n t I d = e v e n t . r a i s e ( ) ;
209
210 // n o t n e e d e d on c r a s h
211 Property . setProperty ( ’ d e v i c e s / ’ + dsid + ’ / s h o r t O f f E v e n t I d ’ ,
shortOffEventId ) ;
212 }
213 }
214 }
215 e l s e i f ( t y p e !== n u l l && t y p e === ’ o n ’ ) {
216 var on = P r o p e r t y . g e t P r o p e r t y ( ’ d e v i c e s / ’ + d s i d + ’ / d e l a y O n ’ ) ;
217 i f ( on !== n u l l && on ) {
218 // s c h e d u l e d e l a y O n R e s e t e v e n t
219 var onTime = P r o p e r t y . g e t P r o p e r t y ( ’ d e v i c e s / ’ + d s i d + ’ / d e l a y O n T i m e ’ ) ;
220 var minOnTime = P r o p e r t y . g e t P r o p e r t y ( ’ d e v i c e s / ’ + d s i d + ’ / c o n f i g / o n T i m e ’ ) ;
221 onTime = (new Date ( onTime ) ) . getTime ( ) ;
222 var o f f T i m e = onTime + minOnTime ∗ 1 0 0 0 ;
223 var d e l t a T = Math . f l o o r ( ( o f f T i m e − now . getTime ( ) ) / 1 0 0 0 ) ;
224 i f ( deltaT < 10) {
225 d e l t a T = 1 0 ; // t h e s y s t e m h a s t o s e t t l e f i r s t
226 }
227 log ( ’ S t o p p i n g on d e v i c e ’ + dsid + ’ in ’ + deltaT + ’ s ’ , 3) ;
228 var s t o p p E v e n t = new TimedEvent ( ’ s m a r t - g r i d ’ , ’ + ’ + d e l t a T , { a c t i o n t y p e : ’
d e l a y O n R e s e t ’ , dsid : dsid }) ;
229 var d e l a y O n R e s e t E v e n t I d = s t o p p E v e n t . r a i s e ( ) ;
230
231 Property . setProperty ( ’ d e v i c e s / ’ + dsid + ’ / d e l a y O n R e s e t E v e n t I d ’ ,
delayOnResetEventId ) ;
232 }
233 else {
234 // s c h e d u l e d e l a y O n S t a r t e v e n t
235 var s t a r t T i m e = P r o p e r t y . g e t P r o p e r t y ( ’ d e v i c e s / ’ + d s i d + ’ / c o n f i g / s t a r t T i m e ’
);
236 i f ( s t a r t T i m e !== n u l l ) {
237 // s c h e d u l e d e l a y O n S t a r t e v e n t
238 var plannedOn = P r o p e r t y . g e t P r o p e r t y ( ’ d e v i c e s / ’ + d s i d + ’ /
delayOnPlannedTime ’) ;
239 plannedOn = new Date ( plannedOn ) ;
240 var ddt = Math . f l o o r ( ( plannedOn . getTime ( ) − now . getTime ( ) ) / 1 0 0 0 ) ;
241 i f ( ddt < 1 0 ) {
242 ddt = 1 0 ; // t h e s y s t e m h a s t o s e t t l e f i r s t
243 }
244 l o g ( ’ S t a r t i n g o n d e v i c e ’ + d s i d + ’ i n ’ + ddt + ’ s ’ , 3 ) ;
245 var s t a r t E v e n t = new TimedEvent ( ’ s m a r t - g r i d ’ , ’ + ’ + ddt , { a c t i o n t y p e : ’
d e l a y O n S t a r t ’ , dsid : dsid }) ;
246 var d e l a y O n E v e n t I d = s t a r t E v e n t . r a i s e ( ) ;
247
248 // n o t n e e d e d on c r a s h
249 Property . s e t P r o p e r t y ( ’ d e v i c e s / ’ + d s i d + ’ / d e l a y O n E v e n t I d ’ , delayOnEventId
);
250 }
251 }
252 }
253 }) ;
254 P r o p e r t y . s e t P r o p e r t y ( ’ s t a r t u p P e r f o r m e d ’ , true ) ;
255 }
256
257 getJSONToken ( ) ;
258
259 persistentConnection () ;
260
261
262 // s t a r t p o l l i n g
263 raiseNextPollEvent () ;
264 } // s t a r t u p
265
266 function c o n v e r t O l d E v e n t s ( ) {
267 /∗TODO∗/
268 }
269
270
271 function j s o n C a l l ( path , c a l l b a c k , c a l l b a c k A r g u m e n t ) {
272 var t o k e n = ’ ’ ;
273 var TOKEN = P r o p e r t y . g e t P r o p e r t y ( ’ t o k e n ’ ) ;
274 i f (TOKEN !== n u l l ) {
275 i f ( path . i n d e x O f ( ’ ? ’ ) === −1) {
276 t o k e n = ’ ? t o k e n = ’ + TOKEN;
277 }
278 else {
B. Source Code 10
361 if ( d a t a . ok ) {
362 log ( ’ D e v i c e ’ + dsid + ’ is p r e s e n t ’ , 5) ;
363 var t a r g e t s = P r o p e r t y . getNode ( ’ d e v i c e s T o O b s e r v e / ’ + d s i d ) . g e t C h i l d r e n ( ) ;
364 var now = new Date ( ) ;
365 var j ;
366 f o r ( j = 0 ; j < t a r g e t s . l e n g t h ; j ++) {
367 var t a r g e t = t a r g e t s [ j ] . name ;
368 var s t a r t T i m e = P r o p e r t y . g e t P r o p e r t y ( ’ d e v i c e s / ’ + t a r g e t + ’ / c o n f i g / s t a r t T i m e ’
);
369 i f ( s t a r t T i m e === n u l l ) {
370 P r o p e r t y . s e t P r o p e r t y ( ’ d e v i c e s / ’ + t a r g e t + ’ / c o n f i g / s t a r t T i m e ’ , now .
toUTCString ( ) ) ;
371 P r o p e r t y . s e t F l a g ( ’ d e v i c e s / ’ + t a r g e t + ’ / c o n f i g / s t a r t T i m e ’ , ’ A R C H I V E ’ , true )
;
372
373 P r o p e r t y . s e t P r o p e r t y ( ’ d e v i c e s / ’ + t a r g e t + ’ / d e v i c e D e t e c t e d A t ’ , now .
toUTCString ( ) ) ;
374 P r o p e r t y . s e t F l a g ( ’ d e v i c e s / ’ + t a r g e t + ’ / d e v i c e D e t e c t e d A t ’ , ’ A R C H I V E ’ , true )
;
375
376 var l e n g t h = P r o p e r t y . g e t P r o p e r t y ( ’ d e v i c e s / ’ + t a r g e t + ’ / c o n f i g / l e n g t h ’ ) ;
377 var onTime = P r o p e r t y . g e t P r o p e r t y ( ’ d e v i c e s / ’ + t a r g e t + ’ / c o n f i g / o n T i m e ’ ) ;
378 var l a t e s t = now . getTime ( ) + ( l e n g t h − onTime ) ∗ 1 0 0 0 ;
379 l a t e s t = new Date ( l a t e s t ) ;
380 delayOn ( t a r g e t , l a t e s t . toUTCString ( ) ) ;
381 }
382 }
383 Property . s t o r e ( ) ;
384 Property . setProperty ( ’ s e n d R e q u e s t ’ , ’ n e w C o n f i g ’ ) ;
385 }
386 else {
387 i f ( data . message . indexOf ( ’ C o u l d n o t f i n d d e v i c e w i t h d s i d \ ’ ’ ) === 0 ) {
388 log ( ’ T o k e n e x p i r e d . R e t r i e v i n g a new one ’ , 0) ;
389 getJSONToken ( ) ;
390 }
391 else {
392 log ( ’ D e v i c e ’ + dsid + ’ not p r e s e n t ’ , 5) ;
393 l o g ( ’ M e s s a g e : ’ + d a t a . message , 8 ) ;
394 }
395 }
396 }
397
398
399
400
401 // c h e c k i f t c p c o n n e c t i o n s t i l l o p e n
402 var t i m e = P r o p e r t y . g e t P r o p e r t y ( ’ t i m e L a s t D a t a R e c e i v e d ’ ) ;
403 i f ( t i m e !== n u l l ) {
404 var now = new Date ( ) ;
405 var d t = Math . round ( ( now . getTime ( ) − t i m e ) / 1 0 0 0 ) ;
406 l o g ( ’ H e a r d n o t h i n g f r o m s e r v e r f o r ’ + dt + ’ s ’ , 10) ;
407 var p o l l I n t e r v a l = P r o p e r t y . g e t P r o p e r t y ( ’ p o l l I n t e r v a l ’ ) ;
408 i f ( p o l l I n t e r v a l === n u l l ) {
409 pollInterval = 60;
410 }
411 i f ( dt > p o l l I n t e r v a l ∗ 2) {
412 l o g ( ’ H e a r d n o t h i n g f r o m s e r v e r f o r ’ + dt + ’ s ’ , 3) ;
413 log ( ’ The c o n n e c t i o n p r o b a b l y died . O p e n i n g a new one ... ’ , 3) ;
414 persistentConnection () ;
415 }
416 }
417 else {
418 log ( ’ No t i m e L a s t D a t a R e c e i v e d node . O p e n i n g a new c o n n e c t i o n ... ’ , 3) ;
419 persistentConnection () ;
420 }
421 } // p o l l
422
423 function r a i s e N e x t P o l l E v e n t ( ) {
424 var p o l l I n t e r v a l = P r o p e r t y . g e t P r o p e r t y ( ’ p o l l I n t e r v a l ’ ) ;
425 i f ( p o l l I n t e r v a l === n u l l ) {
426 pollInterval = 60;
427 }
428 // r e g i s t e r new p o l l e v e n t
429 var e v e n t = new TimedEvent ( ’ s m a r t - g r i d ’ , ’ + ’ + p o l l I n t e r v a l , {action type : ’ p o l l ’ })
;
430 var p o l l E v e n t I d = e v e n t . r a i s e ( ) ;
431 Property . setProperty ( ’ p o l l E v e n t I d ’ , pollEventId ) ;
432 }
433
434 function u p d a t e C o n f i g ( c o n f i g ) {
435 Property . setProperty ( ’ s e r v e r A d d r e s s ’ , c o n f i g . s e r v e r ) ;
436 P r o p e r t y . s e t F l a g ( ’ s e r v e r A d d r e s s ’ , ’ A R C H I V E ’ , true ) ;
437 Property . setProperty ( ’ p o l l I n t e r v a l ’ , c o n f i g . p o l l ) ;
438 P r o p e r t y . s e t F l a g ( ’ p o l l I n t e r v a l ’ , ’ A R C H I V E ’ , true ) ;
B. Source Code 12
514 shortOffSlotTime = 0;
515 }
516 else {
517 s h o r t O f f S l o t S t a r t = new Date ( s h o r t O f f S l o t S t a r t ) ;
518 var temp = new Date ( ) ;
519 temp . s e t T i m e ( s h o r t O f f S l o t S t a r t . getTime ( ) + ( s h o r t O f f S l o t L e n g t h ∗ 1 0 0 0 ) ) ;
520 i f ( temp . getTime ( ) − now . getTime ( ) < 0 ) {
521 s h o r t O f f S l o t S t a r t = now ;
522 shortOffSlotTime = 0;
523 }
524 else {
525 shortOffSlotTime = Property . getProperty ( ’ d e v i c e s / ’ + dsid + ’ / s h o r t O f f S l o t T i m e ’ )
;
526 i f ( s h o r t O f f S l o t T i m e === n u l l ) {
527 shortOffSlotTime = 0;
528 }
529 }
530 }
531 var maxTime = s h o r t O f f M a x O f f − s h o r t O f f S l o t T i m e ;
532 i f ( s e c o n d s === ’ ’ ) {
533 s e c o n d s = maxTime ;
534 }
535 else {
536 seconds = p a r s e I n t ( seconds , 10) ;
537 }
538 i f ( s e c o n d s > maxTime ) {
539 l o g ( ’ T i m e t o o l a r g e f o r d e v i c e ’ + d s i d + ’ m a x ’ + maxTime , 0 ) ;
540 return true ;
541 }
542
543 if ( s e c o n d s <= 0 ) {
544 log ( ’ Time ’ + seconds + ’ not turning off device ’ + dsid , 0) ;
545 return true ;
546 }
547
548 log ( ’ Turning off device ’ + dsid + ’ for ’ + seconds + ’ s ’ , 3) ;
549 device . turnOff () ;
550
551 var e v e n t = new TimedEvent ( ’ s m a r t - g r i d ’ , ’ + ’ + s e c o n d s , {action type : ’
s h o r t O f f R e s e t ’ , dsid : dsid }) ;
552 var s h o r t O f f E v e n t I d = e v e n t . r a i s e ( ) ;
553
554 // n o t n e e d e d on c r a s h
555 Property . setProperty ( ’ d e v i c e s / ’ + dsid + ’ / s h o r t O f f E v e n t I d ’ , shortOffEventId ) ;
556
557 Property . setProperty ( ’ d e v i c e s / ’ + dsid + ’ / s h o r t O f f S l o t S t a r t ’ , s h o r t O f f S l o t S t a r t .
toUTCString ( ) ) ;
558 P r o p e r t y . s e t F l a g ( ’ d e v i c e s / ’ + d s i d + ’ / s h o r t O f f S l o t S t a r t ’ , ’ A R C H I V E ’ , true ) ;
559
560 P r o p e r t y . s e t P r o p e r t y ( ’ d e v i c e s / ’ + d s i d + ’ / s h o r t O f f ’ , true ) ;
561 P r o p e r t y . s e t F l a g ( ’ d e v i c e s / ’ + d s i d + ’ / s h o r t O f f ’ , ’ A R C H I V E ’ , true ) ;
562
563 Property . setProperty ( ’ d e v i c e s / ’ + dsid + ’ / s h o r t O f f S l o t T i m e ’ , ( shortOffSlotTime +
seconds ) ) ;
564 P r o p e r t y . s e t F l a g ( ’ d e v i c e s / ’ + d s i d + ’ / s h o r t O f f S l o t T i m e ’ , ’ A R C H I V E ’ , true ) ;
565
566 Property . setProperty ( ’ d e v i c e s / ’ + dsid + ’ / a c t u a l S h o r t O f f T i m e ’ , seconds ) ;
567 P r o p e r t y . s e t F l a g ( ’ d e v i c e s / ’ + d s i d + ’ / a c t u a l S h o r t O f f T i m e ’ , ’ A R C H I V E ’ , true ) ;
568
569 P r o p e r t y . s e t P r o p e r t y ( ’ d e v i c e s / ’ + d s i d + ’ / a c t u a l S h o r t O f f S t a r t ’ , now . toUTCString ( ) ) ;
570 P r o p e r t y . s e t F l a g ( ’ d e v i c e s / ’ + d s i d + ’ / a c t u a l S h o r t O f f S t a r t ’ , ’ A R C H I V E ’ , true ) ;
571
572 Property . s t o r e ( ) ;
573
574 return true ;
575 }
576
577 function s h o r t O f f R e s e t ( d s i d ) {
578 var d e v i c e = g e t D e v i c e s ( ) . byDSID ( d s i d ) ;
579 log ( ’ R e a c t i v a t i n g s h o r t off d e v i c e ’ + dsid , 3) ;
580 d e v i c e . turnOn ( ) ;
581 Property . setProperty ( ’ d e v i c e s / ’ + dsid + ’ / s h o r t O f f ’ , f a l s e ) ;
582 P r o p e r t y . s e t F l a g ( ’ d e v i c e s / ’ + d s i d + ’ / s h o r t O f f ’ , ’ A R C H I V E ’ , true ) ;
583 Property . s t o r e ( ) ;
584 }
585
586 function delayOn ( d s i d , a t S t r i n g ) {
587 var now = new Date ( ) ;
588
589 // c h e c k i f t h e d e v i c e i s c o n f i g u r e d on
590 var t y p e = P r o p e r t y . g e t P r o p e r t y ( ’ d e v i c e s / ’ + d s i d + ’ / c o n f i g / t y p e ’ ) ;
591 i f ( t y p e === n u l l | | t y p e !== ’ o n ’ ) {
592 log ( ’ D e v i c e ’ + dsid + ’ is not c o n f i g u r e d d e l a y O n ’ , 0) ;
593 return ;
B. Source Code 14
594 }
595
596 // c h e c k i f t h e d e v i c e i s a l r e a d y on
597 var delayOnProp = P r o p e r t y . g e t P r o p e r t y ( ’ d e v i c e s / ’ + d s i d + ’ / d e l a y O n ’ ) ;
598 i f ( delayOnProp !== n u l l && delayOnProp ) {
599 log ( ’ D e v i c e ’ + dsid + ’ is a l r e a d y d e l a y O n ’ , 0) ;
600 return ;
601 }
602
603 var a t = now ;
604 i f ( a t S t r i n g !== ’ ’ ) {
605 var temp = new Date ( a t S t r i n g ) ;
606 // c h e c k t h a t t h e g i v e n t i m e i s n o t i n t h e past
607 i f ( now . getTime ( ) < temp . getTime ( ) ) {
608 a t = temp ;
609 }
610 }
611
612 // c h e c k t h a t t h e c u r r e n t s l o t i s n o t y e t d o n e a l r e a d y
613 var s l o t S t a r t T i m e = P r o p e r t y . g e t P r o p e r t y ( ’ d e v i c e s / ’ + d s i d + ’ / c o n f i g / s t a r t T i m e ’ ) ;
614 i f ( s l o t S t a r t T i m e === n u l l ) {
615 log ( ’ The slot is a l r e a d y done ’ , 0) ;
616 return ;
617 }
618 s l o t S t a r t T i m e = new Date ( s l o t S t a r t T i m e ) ;
619
620 // c h e c k i f t h e s p e c i f i e d t i m e i s n o t t o o l a t e
621 var s l o t L e n g t h = P r o p e r t y . g e t P r o p e r t y ( ’ d e v i c e s / ’ + d s i d + ’ / c o n f i g / l e n g t h ’ ) ;
622 var onTime = P r o p e r t y . g e t P r o p e r t y ( ’ d e v i c e s / ’ + d s i d + ’ / c o n f i g / o n T i m e ’ ) ;
623 var l a t e s t S t a r t = s l o t S t a r t T i m e . getTime ( ) + ( s l o t L e n g t h − onTime ) ∗ 1 0 0 0 ;
624 i f ( a t . getTime ( ) > l a t e s t S t a r t ) {
625 l a t e s t S t a r t = new Date ( l a t e s t S t a r t ) ;
626 l o g ( ’ T i m e ’ + a t . toUTCString ( ) + ’ i s t o o l a t e . S t a r t i n g a t ’ + l a t e s t S t a r t .
toUTCString ( ) , 0 ) ;
627 at = l a t e s t S t a r t ;
628 }
629
630 // c h e c k t h a t t h e s l o t a l r e a d y s t a r t e t a t t h e t i m e s p e c i f i e d
631 i f ( a t . getTime ( ) < s l o t S t a r t T i m e . getTime ( ) ) {
632 log ( ’ The slot did not s t a r t at the g i v e n time ’ , 0) ;
633 return ;
634 }
635
636 // g e t e v e n t i d o f t h e a l r e a d y s c h e d u l e d e v e n t
637 var o l d E v e n t = P r o p e r t y . g e t P r o p e r t y ( ’ d e v i c e s / ’ + d s i d + ’ / d e l a y O n E v e n t I d ’ ) ;
638 i f ( o l d E v e n t !== n u l l ) {
639 // d e l e t e t h e e v e n t
640 P r o p e r t y . getNode ( ’ / s y s t e m / E v e n t I n t e r p r e t e r / S c h e d u l e d E v e n t s ’ ) . r e m o v e C h i l d ( o l d E v e n t )
;
641 log ( ’ R e s c h e d u l i n g d e v i c e ’ + dsid , 3) ;
642 }
643
644 var d t = a t . getTime ( ) − now . getTime ( ) ;
645 d t = Math . f l o o r ( d t / 1 0 0 0 ) ;
646 l o g ( ’ T u r n i n g on d e v i c e ’ + d s i d + ’ in ’ + dt + ’ s ’ , 3) ;
647 i f ( d t <= 0 ) {
648 delayOnStart ( dsid ) ;
649 }
650 else {
651 var e v e n t = new TimedEvent ( ’ s m a r t - g r i d ’ , ’ + ’ + d t , { a c t i o n t y p e : ’ delayOnStart ’ ,
dsid : dsid }) ;
652 var d e l a y O n E v e n t I d = e v e n t . r a i s e ( ) ;
653
654 // n o t n e e d e d on c r a s h
655 Property . s e t P r o p e r t y ( ’ d e v i c e s / ’ + d s i d + ’ / d e l a y O n E v e n t I d ’ , delayOnEventId ) ;
656
657 P r o p e r t y . s e t P r o p e r t y ( ’ d e v i c e s / ’ + d s i d + ’ / d e l a y O n P l a n n e d T i m e ’ , a t . toUTCString ( ) )
;
658 P r o p e r t y . s e t F l a g ( ’ d e v i c e s / ’ + d s i d + ’ / d e l a y O n P l a n n e d T i m e ’ , ’ A R C H I V E ’ , true ) ;
659 Property . s t o r e ( ) ;
660 }
661 }
662
663 function d e l a y O n S t a r t ( d s i d ) {
664 log ( ’ T u r n i n g on d e v i c e ’ + dsid , 3) ;
665 g e t D e v i c e s ( ) . byDSID ( d s i d ) . turnOn ( ) ;
666
667 // s c h e d u l e o f f e v e n t
668 var onTime = P r o p e r t y . g e t P r o p e r t y ( ’ d e v i c e s / ’ + d s i d + ’ / c o n f i g / o n T i m e ’ ) ;
669 l o g ( ’ a n d t u r n i n g i t o f f i n ’ + onTime + ’ s ’ , 3 ) ;
670 var e v e n t = new TimedEvent ( ’ s m a r t - g r i d ’ , ’ + ’ + onTime , { a c t i o n t y p e : ’ d e l a y O n R e s e t ’ ,
dsid : dsid }) ;
671 var d e l a y O n R e s e t E v e n t I d = e v e n t . r a i s e ( ) ;
672
B. Source Code 15
837 l o g ( ’NAK ’ , 0) ;
838 }
839 }) ;
840 }
841 b u i l d S e r v e r S o c k e t ( ) ; ∗/
842
843 // add a l i s t e n e r t o a p r o p e r t y t o b e a b l e t o b e woken up on a e v e n t and s e n d stuff
844 // t h i s d o e s n o t w o r k p r o p e r l y e i t h e r −> g o i n g b a c k t o p o l l i n g
845 /∗ v a r l i s t e n e r I d = P r o p e r t y . g e t P r o p e r t y ( ’ l i s t e n e r I d ’ ) ;
846 i f ( l i s t e n e r I d !== n u l l ) {
847 Property . removeListener ( l i s t e n e r I d ) ;
848 }
849 Property . setProperty ( ’ sendRequest ’ , ’ ’) ;
850 l i s t e n e r I d = Property . s e t L i s t e n e r ( ’ sendRequest ’ , function () {
851 var requestType = Property . getProperty ( ’ sendRequest ’) ;
852 i f ( r e q u e s t T y p e === ’ n e w C o n f i g ’ ) {
853 l o g ( ’ S e n d i n g new c o n f i g ’ , 3 ) ;
854 // t h e o l d r e c e i v e g e t s somehow k i l l e d
855 s o c k e t . s e n d ( getConfigXML ( ) , s e n t ) ;
856 }
857 e l s e i f ( r e q u e s t T y p e === ’ m e a s u r e m e n t s ’ ) {
858 // l o g ( ’ S e n d i n g m e a s u r e m e n t v a l u e s ’ , 3 ) ;
859 s o c k e t . send ( getMeterValues () , s e n t ) ;
860 }
861 else {
862 l o g ( ’ Unknown s e n d r e q u e s t ’ + r e q u e s t T y p e , 0 ) ;
863 }
864 }) ;
865 P r o p e r t y . s e t P r o p e r t y ( ’ l i s t e n e r I d ’ , l i s t e n e r I d ) ; ∗/
866
867 function u p d a t e L a s t R e c e i v e d T i m e ( ) {
868 var now = new Date ( ) ;
869 myLastTime = " "+now . getTime ( ) ;
870 P r o p e r t y . s e t P r o p e r t y ( ’ t i m e L a s t D a t a R e c e i v e d ’ , myLastTime ) ;
871 }
872 function r e c e i v e ( ) {
873 var r e q u e s t T y p e = P r o p e r t y . g e t P r o p e r t y ( ’ s e n d R e q u e s t ’ ) ;
874 i f ( r e q u e s t T y p e === ’ n e w C o n f i g ’ ) {
875 log ( ’ S e n d i n g new c o n f i g ’ , 3) ;
876 Property . setProperty ( ’ s e n d R e q u e s t ’ , ’ ’ ) ;
877 // t h e o l d r e c e i v e g e t s somehow k i l l e d
878 s o c k e t . s e n d ( getConfigXML ( ) , s e n t ) ;
879 return ;
880 }
881 s o c k e t . r e c e i v e L i n e ( 1 0 2 4 , function ( d a t a ) {
882 i f ( h o s t !== P r o p e r t y . g e t P r o p e r t y ( ’ s e r v e r A d d r e s s ’ ) | | p o r t !== P r o p e r t y .
getProperty ( ’ s e r v e r P o r t ’ ) ) {
883 log ( ’ The a d d r e s s of the s e r v e r c h a n g e d . C l o s i n g c o n n e c t i o n ’ , 3) ;
884 return ;
885 }
886
887 if ( P r o p e r t y . g e t P r o p e r t y ( ’ t i m e L a s t D a t a R e c e i v e d ’ ) === myLastTime ) {
888 updateLastReceivedTime ( ) ;
889 i f ( d a t a === ’ ’ ) {
890 // e r r o r
891 log ( ’ R e m o t e side c l o s e d c o n n e c t i o n ’ , 3) ;
892 socket . close () ;
893 }
894 else {
895 var xmlDoc = new REXML( d a t a ) ;
896 i f ( xmlDoc . r o o t E l e m e n t . t y p e === ’ e l e m e n t ’ ) {
897 var name = xmlDoc . r o o t E l e m e n t . name ;
898 i f ( name === ’ p i n g ’ ) {
899 var d e l t a = n u l l ;
900 var now = new Date ( ) ;
901 i f ( l a s t M e t e r T i m e !== n u l l ) {
902 d e l t a = now . getTime ( ) − l a s t M e t e r T i m e . getTime ( ) ;
903 }
904 else {
905 delta = 10000000;
906 }
907 log ( d e l t a + ’ ’ , 11) ;
908 l a s t M e t e r T i m e = now ;
909 log ( ’ R e c e i v e d p in g ’ , 20) ;
910 s o c k e t . send ( getMeterValues ( d e l t a ) , s e n t ) ;
911 }
912 e l s e i f ( name === ’ s h o r t o f f ’ ) {
913 s h o r t O f f ( xmlDoc ) ;
914 receive () ;
915 }
916 e l s e i f ( name === ’ d e l a y o n ’ ) {
917 delayOn ( xmlDoc . r o o t E l e m e n t . t e x t , xmlDoc . r o o t E l e m e n t . a t t r i b u t e ( ’ a t ’ ) ) ;
918 receive () ;
919 }
B. Source Code 18
920 else {
921 l o g ( data , 3 ) ;
922 receive () ;
923 }
924 }
925 else {
926 l o g ( data , 3 ) ;
927 receive () ;
928 }
929 }
930 }
931 else {
932 log ( ’ Another tcp connection is open . I will c l o s e ’ , 3) ;
933 }
934 } , ’\n ’) ;
935 }
936 function s e n t ( b y t e s S e n t ) {
937 i f ( bytesSent > 0) {
938 log ( ’ S en t the m e s s a g e ’ , 20) ;
939 receive () ;
940 }
941 else {
942 log ( ’ C o u l d not send the m e s s a g e ’ , 0) ;
943 }
944 }
945
946 var h o s t = P r o p e r t y . g e t P r o p e r t y ( ’ s e r v e r A d d r e s s ’ ) ;
947 var p o r t = P r o p e r t y . g e t P r o p e r t y ( ’ s e r v e r P o r t ’ ) ;
948 i f ( h o s t === n u l l | | p o r t === n u l l ) {
949 log ( ’ D e b u g : S e r v e r not s p e c i f i e d ’ , 3) ;
950 return ;
951 }
952 updateLastReceivedTime ( ) ;
953 s o c k e t . c o n n e c t ( h o s t , p o r t , function ( s t a t e ) {
954 if ( state ) {
955 log ( ’ C o n n e c t e d ’ , 10) ;
956 Property . setProperty ( ’ s e n d R e q u e s t ’ , ’ n e w C o n f i g ’ ) ;
957 receive () ;
958 }
959 else {
960 log ( ’ C o n n e c t i o n f a i l e d ’ , 0) ;
961 }
962 }) ;
963 } // p e r s i s t e n t C o n n e c t i o n
964
965 function objToXml ( o b j ) {
966 var r S t r i n g=’ ’ , i ;
967 i f ( typeof o b j === ’ o b j e c t ’ ) {
968 i f ( o b j . c o n s t r u c t o r . t o S t r i n g ( ) . i n d e x O f ( ’ A r r a y ’ ) !== −1) {
969 f o r ( i = 0 ; i < o b j . l e n g t h ; i ++) {
970 r S t r i n g = r S t r i n g + ( ’ < i t e m > ’ + objToXml ( o b j [ i ] ) + ’ < / i t e m > ’ ) ;
971 }
972 }
973 else {
974 f o r ( i in o b j ) {
975 var v a l = objToXml ( o b j [ i ] ) ;
976 i f ( ! val ) {
977 return f a l s e ;
978 }
979 r S t r i n g += ’ < ’ + i + ’ > ’ + v a l + ’ < / ’ + i + ’ > ’ ;
980 }
981 }
982 }
983 e l s e i f ( typeof o b j === ’ s t r i n g ’ ) {
984 rS t r i ng = obj ;
985 }
986 else i f ( obj . toString ) {
987 rS t r i ng = obj . toString () ;
988 }
989 else {
990 return f a l s e ;
991 }
992 return r S t r i n g ;
993 }
994
995 function getConfigXML ( ) {
996 log ( ’ E n t e r i n g g e t C o n f i g X M L ’ , 20) ;
997 var d e v i c e s = [ ] ;
998 g e t D e v i c e s ( ) . p e r f o r m ( function ( d e v i c e ) {
999 var t y p e = P r o p e r t y . g e t P r o p e r t y ( ’ d e v i c e s / ’ + d e v i c e . d s i d + ’ / c o n f i g / t y p e ’ ) ;
1000 var c o n f i g = { } ;
1001 c o n f i g . type = type ;
1002 config . id = device . dsid ;
1003 i f ( t y p e === ’ o n ’ ) {
B. Source Code 19
1077
1078 Property . setProperty ( ’ d e v i c e s / ’ + dsid + ’ / c o n f i g / all ’ , c o n f i g ) ;
1079 P r o p e r t y . s e t F l a g ( ’ d e v i c e s / ’ + d s i d + ’ / c o n f i g / a l l ’ , ’ A R C H I V E ’ , true ) ;
1080
1081 if ( t y p e === ’ o n ’ ) {
1082 var l e n g t h = 60 ∗ ( c o n f i g O b j e c t . l e n g t h H o u r s ∗ 60 + c o n f i g O b j e c t . l e n g t h M i n u t e s ) ;
1083 Property . setProperty ( ’ d e v i c e s / ’ + dsid + ’ / c o n f i g / l e n g t h ’ , length ) ;
1084 P r o p e r t y . s e t F l a g ( ’ d e v i c e s / ’ + d s i d + ’ / c o n f i g / l e n g t h ’ , ’ A R C H I V E ’ , true ) ;
1085
1086 var onTime = 60 ∗ ( c o n f i g O b j e c t . onHours ∗ 60 + c o n f i g O b j e c t . onMi nut es ) ;
1087 P r o p e r t y . s e t P r o p e r t y ( ’ d e v i c e s / ’ + d s i d + ’ / c o n f i g / o n T i m e ’ , onTime ) ;
1088 P r o p e r t y . s e t F l a g ( ’ d e v i c e s / ’ + d s i d + ’ / c o n f i g / o n T i m e ’ , ’ A R C H I V E ’ , true ) ;
1089
1090 log ( configObject . startDetection , 10) ;
1091 i f ( c o n f i g O b j e c t . s t a r t D e t e c t i o n === ’ s i n g l e S l o t ’ ) {
1092 var d a t e = c o n f i g O b j e c t . d a t e . r e p l a c e (/−/g , ’ / ’ ) . s p l i t ( ’ T ’ ) [ 0 ] + ’ ’ +
configObject . startHours + ’: ’ + configObject . startMinutes + ’ :0 ’ ;
1093 var s t a r t t i m e = new Date ( d a t e ) ;
1094 Property . setProperty ( ’ d e v i c e s / ’ + dsid + ’ / c o n f i g / s t a r t T i m e ’ , s t a r t t i m e .
toUTCString ( ) ) ;
1095 P r o p e r t y . s e t F l a g ( ’ d e v i c e s / ’ + d s i d + ’ / c o n f i g / s t a r t T i m e ’ , ’ A R C H I V E ’ , true ) ;
1096
1097 var l a t e s t = s t a r t t i m e . getTime ( ) + ( l e n g t h − onTime ) ∗ 1 0 0 0 ;
1098 l a t e s t = new Date ( l a t e s t ) ;
1099 delayOn ( d s i d , l a t e s t . toUTCString ( ) ) ;
1100 }
1101 e l s e i f ( c o n f i g O b j e c t . s t a r t D e t e c t i o n === ’ d e v i c e ’ ) {
1102 // t h i s i s n o t a new c o n f i g we j u s t h a v e t o d e t e c t a s l o t s t a r t
1103 var d e v i c e = c o n f i g O b j e c t . o n D e t e c t i o n D e v i c e ;
1104 log ( ’ D e v i c e d e t e c t i o n with d e v i c e ’ + device , 5) ;
1105 P r o p e r t y . s e t P r o p e r t y ( ’ d e v i c e s T o O b s e r v e / ’ + d e v i c e + ’ / ’ + d s i d , true ) ;
1106 P r o p e r t y . s e t F l a g ( ’ d e v i c e s T o O b s e r v e / ’ + d e v i c e + ’ / ’ + d s i d , ’ A R C H I V E ’ , true ) ;
1107
1108 Property . setProperty ( ’ d e v i c e s / ’ + dsid + ’ / c o n f i g / o n D e t e c t i o n D e v i c e ’ , device ) ;
1109 Property . setFlag ( ’ d e v i c e s / ’ + dsid + ’ / c o n f i g / o n D e t e c t i o n D e v i c e ’ , ’ A R C H I V E ’ ,
true ) ;
1110 }
1111 }
1112 e l s e i f ( t y p e === ’ o f f ’ ) {
1113 var s l o t L e n g t h = 60 ∗ ( c o n f i g O b j e c t . s l o t L e n g t h H o u r s ∗ 60 + c o n f i g O b j e c t .
slotLengthMinutes ) ;
1114 Property . setProperty ( ’ d e v i c e s / ’ + dsid + ’ / c o n f i g / s l o t L e n g t h ’ , slotLength ) ;
1115 P r o p e r t y . s e t F l a g ( ’ d e v i c e s / ’ + d s i d + ’ / c o n f i g / s l o t L e n g t h ’ , ’ A R C H I V E ’ , true ) ;
1116
1117 var o f f T i m e = 60 ∗ ( c o n f i g O b j e c t . o f f T i m e H o u r s ∗ 60 + c o n f i g O b j e c t . o f f T i m e M i n u t e s ) ;
1118 Property . setProperty ( ’ d e v i c e s / ’ + dsid + ’ / c o n f i g / o f f T i m e ’ , offTime ) ;
1119 P r o p e r t y . s e t F l a g ( ’ d e v i c e s / ’ + d s i d + ’ / c o n f i g / o f f T i m e ’ , ’ A R C H I V E ’ , true ) ;
1120 }
1121 log ( ’ New c o n f i g s a v e d for ’ + dsid , 4) ;
1122 Property . setProperty ( ’ s e n d R e q u e s t ’ , ’ n e w C o n f i g ’ ) ;
1123
1124 Property . s t o r e ( ) ;
1125 } // n e w C o n f i g
1126
1127 function main ( ) {
1128 i f ( r a i s e d E v e n t . name === ’ r u n n i n g ’ ) {
1129 // P r e p a r e app
1130 Property . load ( ) ;
1131 LOG. l o g l n ( ’ ’ ) ;
1132 LOG. l o g l n ( ’ = = = = = = = = = = = = = = = = = = = = = = = = ’ ) ;
1133 LOG. l o g l n ( ’ # smart - grid running #’) ;
1134 LOG. l o g l n ( ’ = = = = = = = = = = = = = = = = = = = = = = = = ’ ) ;
1135
1136 timeDriftCheck () ;
1137 return ;
1138 }
1139
1140 var a c t i o n t y p e = r a i s e d E v e n t . p a r a m e t e r . a c t i o n t y p e ;
1141 i f ( a c t i o n t y p e === ’ c o n f i g ’ ) {
1142 log ( ’ D e b u g : U p d a t i n g the s e r v e r c o n f i g u r a t i o n ’ , 5) ;
1143 l o g ( r a i s e d E v e n t . p a r a m e t e r . params , 5 ) ;
1144 u p d a t e C o n f i g (JSON . p a r s e ( r a i s e d E v e n t . p a r a m e t e r . params ) ) ;
1145 return ;
1146 }
1147
1148
1149 var clockOK = P r o p e r t y . g e t P r o p e r t y ( ’ c l o c k D r i f t O K ’ ) ;
1150 i f ( clockOK !== n u l l && clockOK ) {
1151 i f ( a c t i o n t y p e === ’ p o l l ’ ) {
1152 log ( ’ D e b u g : D o i n g a p o ll to the e l e c t r i c i t y p r o v i d e r ’ , 20) ;
1153 poll () ;
1154 raiseNextPollEvent () ;
1155 }
1156 e l s e i f ( a c t i o n t y p e === ’ c o n f i g D e v i c e ’ ) {
B. Source Code 21
46 mouseWheelEnabled : f a l s e
47 }, {
48 name : ’ p o l l I n t e r v a l ’ ,
49 fieldLabel : ( " Poll interval " ) ,
50 xtype : ’ n u m b e r f i e l d ’ ,
51 minValue : 1 0 , // p r e v e n t s l o w e r v a l u e s t h a n 10
52 allowBlank : false ,
53
54 // Remove s p i n n e r b u t t o n s , and a r r o w k e y and mouse w h e e l listeners
55 h i d e T r i g g e r : true ,
56 keyNavEnabled : f a l s e ,
57 mouseWheelEnabled : f a l s e
58 }
59 ],
60
61 /∗ ∗ f o o t e r b a r ∗/
62 fbar : {
63 items : [
64 {
65 text : ( " Cancel " ) ,
66 id : ’ btn - c a n c e l ’
67 },
68 {
69 text : ( " Save " ) ,
70 id : ’ btn - s a v e ’
71 }
72 ]
73 },
74
75 c o n s t r u c t o r : function ( c o n f i g ) {
76 this . i n i t C o n f i g ( config ) ;
77 t h i s . c a l l P a r e n t ( arguments ) ;
78 },
79
80 i n i t C o m p o n e n t : function ( ) {
81 var me = t h i s ;
82 me . addEvents ( {
83 e v e n t h i d e : true
84 }) ;
85
86 me . c a l l P a r e n t ( a r g u m e n t s ) ;
87 me . i n i t P a g e ( ) ;
88 },
89
90
91 i n i t P a g e : function ( ) {
92 var me = t h i s ;
93
94 Ext . getCmp ( ’ b t n - s a v e ’ ) . h a n d l e r = function ( ) {
95 var form = me . getForm ( ) ;
96 i f ( form . i s V a l i d ( ) ) {
97 me . s a v e I t ( form ) ;
98 }
99 };
100 Ext . getCmp ( ’ b t n - c a n c e l ’ ) . h a n d l e r = function ( ) {
101 me . f i r e E v e n t ( ’ e v e n t h i d e ’ ) ;
102 };
103 },
104
105 s a v e I t : function ( form ) {
106 var me = t h i s ;
107
108 var d a t a = form . g e t F i e l d V a l u e s ( ) ;
109 var s e r v e r A d d r e s s = me . down ( ’ [ n a m e = s e r v e r A d d r e s s ] ’ ) ;
110 var p o l l I n t e r v a l = me . down ( ’ [ n a m e = p o l l I n t e r v a l ] ’ ) ;
111 var s e r v e r P o r t = me . down ( ’ [ n a m e = s e r v e r P o r t ] ’ ) ;
112 serverAddress . resetOriginalValue () ;
113 pollInterval . resetOriginalValue () ;
114 serverPort . resetOriginalValue () ;
115
116
117 var params = {
118 p o l l : data . p o l l I n t e r v a l ,
119 s e r v e r : data . serverAddress ,
120 port : data . s e r v e r P o r t
121 };
122
123 var e v e n t = Ext . c r e a t e ( ’ D S S . j s o n . E v e n t ’ , {name : ’ smart - g r i d ’ }) ;
124 event . r a i s e ({
125 action type : ’ config ’ ,
126 params : Ext . JSON . e n c o d e ( params )
127 }, {
128 s u c c e s s : function ( ) {
129 me . f i r e E v e n t ( ’ e v e n t h i d e ’ ) ;
B. Source Code 23
130 },
131 f a i l u r e : function ( ) {
132 Ext . Msg . a l e r t ( ( ’ E r r o r ’ ) , ( ’ Couldn \’t create timed event on server ’) ) ;
133 }
134 }) ;
135 },
136
137 g e t F i e l d : function ( path , s u c c e s s ) {
138 var me = t h i s ;
139 Ext . Ajax . r e q u e s t ( {
140 d i s a b l e C a c h i n g : true ,
141 method : ’ G E T ’ ,
142 timeout : 20000 ,
143 u r l : ’ / j s o n / ’ + path ,
144 s u c c e s s : function ( r e s p o n s e ) {
145 var d a t a = Ext . JSON . d e c o d e ( r e s p o n s e . r e s p o n s e T e x t ) ;
146 i f ( d a t a . ok ) {
147 s u c c e s s ( data . r e s u l t . value ) ;
148 }
149 else {
150 me . e n a b l e ( ) ;
151 }
152 },
153 f a i l u r e : function ( ) {
154 me . e n a b l e ( ) ;
155 }
156 }) ;
157 },
158
159
160 b e f o r e S h o w : function ( ) {
161 var me = t h i s ;
162 i f ( ! me . f e t c h e d D a t a ) {
163 me . d i s a b l e ( ) ;
164 me . f e t c h e d D a t a = true ;
165 me . g e t F i e l d ( " p r o p e r t y / g e t I n t e g e r ? p a t h = / s c r i p t s / s m a r t - g r i d / p o l l I n t e r v a l " ,
function ( d a t a ) {
166 var p o l l I n t e r v a l = me . down ( ’ [ n a m e = p o l l I n t e r v a l ] ’ ) ;
167 p o l l I n t e r v a l . setRawValue ( d a t a ) ;
168 pollInterval . resetOriginalValue () ;
169 me . g e t F i e l d ( " p r o p e r t y / g e t S t r i n g ? p a t h = / s c r i p t s / s m a r t - g r i d / s e r v e r A d d r e s s " ,
function ( d a t a ) {
170 var s e r v e r A d d r e s s = me . down ( ’ [ n a m e = s e r v e r A d d r e s s ] ’ ) ;
171 s e r v e r A d d r e s s . setRawValue ( d a t a ) ;
172 serverAddress . resetOriginalValue () ;
173 me . g e t F i e l d ( " p r o p e r t y / g e t I n t e g e r ? p a t h = / s c r i p t s / s m a r t - g r i d / s e r v e r P o r t " ,
function ( d a t a ) {
174 var s e r v e r P o r t = me . down ( ’ [ n a m e = s e r v e r P o r t ] ’ ) ;
175 s e r v e r P o r t . setRawValue ( d a t a ) ;
176 serverPort . resetOriginalValue () ;
177 me . e n a b l e ( ) ;
178 }) ;
179 }) ;
180 }) ;
181 }
182 else {
183 me . getForm ( ) . r e s e t ( ) ;
184 }
185 }
186 }) ;
187 f o r m P a n e l = Ext . c r e a t e ( ’ c o n f i g P a n e l ’ , { p r o p e r t y : me . p r o p e r t y } ) ;
188 me . i t e m s = f o r m P a n e l ;
189 me . i t e m s . on ( {
190 e v e n t h i d e : function ( ) {
191 me . h i d e ( ) ;
192 }
193 }) ;
194
195 me . a d d L i s t e n e r ( ’ b e f o r e s h o w ’ , function ( ) {
196 formPanel . beforeShow ( ) ;
197 }) ;
198
199 me . c a l l P a r e n t ( a r g u m e n t s ) ;
200 }
201 }) ;
1 Ext . d e f i n e ( ’ D S S . a d d o n . S m a r t G r i d . D e v i c e W i n d o w ’ , {
2 extend : ’ Ext . w i n d o w . W i n d o w ’ ,
3 t i t l e : ’ SmartGrid ’ ,
4 layout : ’ fit ’ ,
B. Source Code 24
5 closeAction : ’ hide ’ ,
6
7 /∗ ∗ The s t o r e object is received with the config parameter in the c o n s t r u c t o r ∗/
8 s t o r e : null ,
9
10 /∗ ∗ c u r r e n t l y edited d e v i c e ∗/
11 d e v i c e : null ,
12
13 c o n s t r u c t o r : function ( c o n f i g ) {
14 this . i n i t C o n f i g ( config ) ;
15 t h i s . c a l l P a r e n t ( arguments ) ;
16 },
17
18 items : [
19 {
20 xtype : ’ f o r m ’ ,
21 id : ’ form ’ ,
22 bodyPadding : 5 ,
23 items : [
24 {
25 boxLabel : (" Excluded ") ,
26 name : ’ type ’ ,
27 inputValue : ’ exclude ’ ,
28 id : ’ exclude ’ ,
29 xtype : ’ radiofield ’ ,
30 width : 130
31 },
32 {
33 xtype : ’ c o n t a i n e r ’ ,
34 layout : ’ column ’ ,
35 items : [
36 {
37 boxLabel : ( " D e l a y e d ON " ) ,
38 name : ’ type ’ ,
39 inputValue : ’ on ’ ,
40 id : ’ on ’ ,
41 xtype : ’ radiofield ’ ,
42 width : 130
43 },
44 {
45 xtype : ’ c o n t a i n e r ’ ,
46 id : ’ onContainer ’ ,
47 items : [
48 {
49 xtype : ’ f i e l d c o n t a i n e r ’ ,
50 fieldLabel : ( " Slot start detection " ) ,
51 labelWidth : 120 ,
52 items : [
53 {
54 xtype : ’ c o n t a i n e r ’ ,
55 layout : ’ column ’ ,
56 items : [
57 {
58 boxLabel : ( " Single slot " ) ,
59 id : ’ onSingleSlot ’ ,
60 name : ’ startDetection ’ ,
61 inputValue : ’ s i n g l e S l o t ’ ,
62 xtype : ’ r a d i o f i e l d ’
63 },
64 {
65 xtype : ’ c o n t a i n e r ’ ,
66 id : ’ s t a r t T i m e C o n t a i n e r ’ ,
67 layout : ’ column ’ ,
68 items : [
69 {
70 id : ’ o n S i n g l e S l o t D a t e ’ ,
71 name : ’ d a t e ’ ,
72 xtype : ’ d a t e f i e l d ’ ,
73 margin : ’ 0 0 0 5 ’ ,
74 allowBlank : false
75 },
76 {
77 id : ’ o n S i n g l e S l o t T i m e ’ ,
78 name : ’ s t a r t ’ ,
79 xtype : ’ d s s T i m e S e l e c t i o n ’
80 }
81 ]
82 }
83 ]
84 },
85 {
86 xtype : ’ c o n t a i n e r ’ ,
87 layout : ’ column ’ ,
88 id : ’ s t a r t D e t e c t i o n C o n t a i n e r ’ ,
B. Source Code 25
89 items : [
90 {
91 boxLabel : ( " On device p r e s e n c e " ) ,
92 id : ’ onDetection ’ ,
93 name : ’ startDetection ’ ,
94 inputValue : ’ d e v i c e ’ ,
95 xtype : ’ r a d i o f i e l d ’ ,
96 margin : ’0 5 0 0 ’
97 }
98 ]
99 }
100 ]
101 },
102 {
103 xtype : ’ f i e l d c o n t a i n e r ’ ,
104 labelWidth : 120 ,
105 fieldLabel : ( " Slot length " ) ,
106 items : [
107 {
108 id : ’ onSlotLength ’ ,
109 name : ’ l e n g t h ’ ,
110 xtype : ’ d s s T i m e S e l e c t i o n ’ ,
111 type : ’ l e n g t h ’
112 }
113 ]
114 },
115 {
116 xtype : ’ f i e l d c o n t a i n e r ’ ,
117 labelWidth : 120 ,
118 fieldLabel : ( " ON time " ) ,
119 items : [
120 {
121 id : ’ onOnTime ’ ,
122 name : ’ o n ’ ,
123 xtype : ’ d s s T i m e S e l e c t i o n ’ ,
124 type : ’ l e n g t h ’
125 }
126 ]
127 } /∗ ,
128 {
129 xtype : ’ fieldcontainer ’ ,
130 fieldLabel : (” I n t e r r u p t i o n a l l o w e d ”) ,
131 l a b e l W i d t h : 120 ,
132 items : [
133 {
134 boxLabel : ( ” Yes ” ) ,
135 id : ’ interruptTrue ’ ,
136 name : ’ interrupt ’ ,
137 inputValue : ” yes ” ,
138 xtype : ’ r a d i o f i e l d ’ ,
139 },
140 {
141 boxLabel : ( ” No , d e v i c e n e e d s t o r u n i n a row ” ) ,
142 id : ’ interruptFalse ’ ,
143 name : ’ interrupt ’ ,
144 i n p u t V a l u e : ” no ” ,
145 xtype : ’ r a d i o f i e l d ’ ,
146 }
147 ]
148 } ∗/
149 ]
150 }
151 ]
152 },
153 {
154 xtype : ’ c o n t a i n e r ’ ,
155 layout : ’ column ’ ,
156 items : [
157 {
158 boxLabel : ( " Short Period OFF " ) ,
159 name : ’ type ’ ,
160 inputValue : ’ off ’ ,
161 id : ’ off ’ ,
162 xtype : ’ radiofield ’ ,
163 width : 130
164 },
165 {
166 xtype : ’ c o n t a i n e r ’ ,
167 id : ’ offContainer ’ ,
168 items : [
169 {
170 xtype : ’ f i e l d c o n t a i n e r ’ ,
171 fieldLabel : ( " Slot length " ) ,
172 labelWidth : 120 ,
B. Source Code 26
173 items : [
174 {
175 id : ’ offSlotLength ’ ,
176 name : ’ s l o t L e n g t h ’ ,
177 xtype : ’ d s s T i m e S e l e c t i o n ’ ,
178 type : ’ l e n g t h ’
179 }
180 ]
181 },
182 {
183 xtype : ’ f i e l d c o n t a i n e r ’ ,
184 fieldLabel : ( " OFF time " ) ,
185 labelWidth : 120 ,
186 items : [
187 {
188 id : ’ offOffTime ’ ,
189 name : ’ o f f T i m e ’ ,
190 xtype : ’ d s s T i m e S e l e c t i o n ’ ,
191 type : ’ l e n g t h ’
192 }
193 ]
194 }
195 ]
196 }
197 ]
198 }
199 ],
200 buttons : [
201 {
202 text : ( " Cancel " ) ,
203 id : ’ btn - c a n c e l ’
204 },
205 {
206 text : ( " Save " ) ,
207 id : ’ btn - s a v e ’
208 }
209 ]
210 }
211 ],
212
213
214 i n i t C o m p o n e n t : function ( ) {
215 var me = t h i s ;
216 me . c a l l P a r e n t ( a r g u m e n t s ) ;
217 me . i n i t P a g e ( ) ;
218 },
219
220 e n a b l e O f f : function ( e n a b l e ) {
221 Ext . getCmp ( ’ o f f O f f T i m e ’ ) . e n a b l e ( e n a b l e ) ;
222 Ext . getCmp ( ’ o f f S l o t L e n g t h ’ ) . e n a b l e ( e n a b l e ) ;
223 },
224
225 enableOn : function ( e n a b l e ) {
226 Ext . getCmp ( ’ o n S l o t L e n g t h ’ ) . e n a b l e ( e n a b l e ) ;
227 Ext . getCmp ( ’ o n O n T i m e ’ ) . e n a b l e ( e n a b l e ) ;
228 i f ( enable ){
229 Ext . getCmp ( ’ o n S i n g l e S l o t ’ ) . e n a b l e ( ) ;
230 Ext . getCmp ( ’ o n D e t e c t i o n ’ ) . e n a b l e ( ) ;
231 Ext . getCmp ( ’ o n D e t e c t i o n ’ ) . s e t V a l u e ( f a l s e ) ;
232 Ext . getCmp ( ’ o n D e t e c t i o n ’ ) . s e t V a l u e ( true ) ;
233 }
234 else {
235 Ext . getCmp ( ’ o n S i n g l e S l o t ’ ) . d i s a b l e ( ) ;
236 Ext . getCmp ( ’ o n S i n g l e S l o t D a t e ’ ) . d i s a b l e ( ) ;
237 Ext . getCmp ( ’ o n D e t e c t i o n D e v i c e ’ ) . d i s a b l e ( ) ;
238 Ext . getCmp ( ’ o n D e t e c t i o n ’ ) . d i s a b l e ( ) ;
239 Ext . getCmp ( ’ o n S i n g l e S l o t T i m e ’ ) . e n a b l e ( f a l s e ) ;
240 }
241 },
242
243 i n i t P a g e : function ( ) {
244 var me = t h i s ;
245 Ext . getCmp ( ’ b t n - c a n c e l ’ ) . h a n d l e r = function ( ) {
246 me . h i d e ( ) ;
247 };
248 Ext . getCmp ( ’ b t n - s a v e ’ ) . h a n d l e r = function ( ) {
249 var form = Ext . getCmp ( ’ f o r m ’ ) . getForm ( ) ;
250 i f ( form . i s V a l i d ( ) ) {
251 var t y p e = ’ ’ ;
252 i f ( Ext . getCmp ( ’ o n ’ ) . g e t V a l u e ( ) ) {
253 var l e n g t h = Ext . getCmp ( ’ o n S l o t L e n g t h ’ ) . g e t V a l u e ( ) ;
254 var onTime = Ext . getCmp ( ’ o n O n T i m e ’ ) . g e t V a l u e ( ) ;
255 type = ’ on ’ ;
256 i f ( onTime > l e n g t h ) {
B. Source Code 27
257 Ext . Msg . a l e r t ( ( " E r r o r " ) , ( " ON time has to be smaller than the slot
length " ) ) ;
258 return ;
259 }
260 }
261 e l s e i f ( Ext . getCmp ( ’ o f f ’ ) . g e t V a l u e ( ) ) {
262 var o f f T i m e = Ext . getCmp ( ’ o f f O f f T i m e ’ ) . g e t V a l u e ( ) ;
263 var l e n g t h = Ext . getCmp ( ’ o f f S l o t L e n g t h ’ ) . g e t V a l u e ( ) ;
264 type = ’ off ’ ;
265 i f ( offTime > length ) {
266 Ext . Msg . a l e r t ( ( " E r r o r " ) , ( " OFF time has to be s m a l l e r than the slot
length " ) ) ;
267 return ;
268 }
269 }
270
271 var d a t a = form . g e t F i e l d V a l u e s ( ) ;
272 d a t a = Ext . JSON . e n c o d e ( d a t a ) ;
273 me . s e t L o a d i n g ( true ) ;
274 var e v e n t = Ext . c r e a t e ( ’ D S S . j s o n . E v e n t ’ , {name : ’ s m a r t - g r i d ’ } ) ;
275 event . r a i s e (
276 {
277 action type : ’ configDevice ’ ,
278 d e v i c e I d : me . d e v i c e . g e t ( ’ i d ’ ) ,
279 c o n f i g : data
280 },
281 {
282 s u c c e s s : function ( ) {
283 var model = me . s t o r e . g e t B y I d (me . d e v i c e . g e t ( ’ i d ’ ) ) ;
284 model . s e t ( ’ s m a r t G r i d T y p e ’ , t y p e ) ;
285 model . commit ( ) ;
286 me . s e t L o a d i n g ( f a l s e ) ;
287 me . h i d e ( ) ;
288 },
289 f a i l u r e : function ( ) {
290 Ext . Msg . a l e r t ( ( " E r r o r " ) , ( " Couldn \ ’ t send event to DSS " ) ) ;
291 me . s e t L o a d i n g ( f a l s e ) ;
292 me . h i d e ( ) ;
293 }
294 }
295 );
296 }
297 };
298 Ext . getCmp ( ’ e x c l u d e ’ ) . h a n d l e r = function ( ) {
299 i f ( Ext . getCmp ( ’ e x c l u d e ’ ) . g e t V a l u e ( ) ) {
300 me . e n a b l e O f f ( f a l s e ) ;
301 me . enableOn ( f a l s e ) ;
302 }
303 };
304 Ext . getCmp ( ’ o n ’ ) . h a n d l e r = function ( ) {
305 i f ( Ext . getCmp ( ’ o n ’ ) . g e t V a l u e ( ) ) {
306 me . e n a b l e O f f ( f a l s e ) ;
307 me . enableOn ( true ) ;
308 }
309 };
310 Ext . getCmp ( ’ o n S i n g l e S l o t ’ ) . h a n d l e r = function ( ) {
311 i f ( Ext . getCmp ( ’ o n S i n g l e S l o t ’ ) . g e t V a l u e ( ) ) {
312 Ext . getCmp ( ’ o n S i n g l e S l o t D a t e ’ ) . e n a b l e ( ) ;
313 Ext . getCmp ( ’ o n S i n g l e S l o t T i m e ’ ) . e n a b l e ( true ) ;
314 }
315 else {
316 Ext . getCmp ( ’ o n S i n g l e S l o t D a t e ’ ) . d i s a b l e ( ) ;
317 Ext . getCmp ( ’ o n S i n g l e S l o t T i m e ’ ) . e n a b l e ( f a l s e ) ;
318 }
319 };
320 Ext . getCmp ( ’ o n D e t e c t i o n ’ ) . h a n d l e r = function ( ) {
321 i f ( Ext . getCmp ( ’ o n D e t e c t i o n ’ ) . g e t V a l u e ( ) ) {
322 Ext . getCmp ( ’ o n D e t e c t i o n D e v i c e ’ ) . e n a b l e ( ) ;
323 }
324 else {
325 Ext . getCmp ( ’ o n D e t e c t i o n D e v i c e ’ ) . d i s a b l e ( ) ;
326 }
327 }
328 Ext . getCmp ( ’ o f f ’ ) . h a n d l e r = function ( ) {
329 i f ( Ext . getCmp ( ’ o f f ’ ) . g e t V a l u e ( ) ) {
330 me . e n a b l e O f f ( true ) ;
331 me . enableOn ( f a l s e ) ;
332 }
333 };
334
335 var i c o n T p l = Ext . c r e a t e ( ’ E x t . T e m p l a t e ’ , [
336 // The p i c s a r e 16 x16 , +5 p a d d i n g = 21
337 ’ < div style =" ’ ,
338 ’ < tpl if =" icon " > ’ ,
B. Source Code 28
339 ’ b a c k g r o u n d : l e f t c e n t e r no - r e p e a t u r l (\ ’ i m a g e s / d s s / { i c o n } \ ’ ) ; ’ ,
340 ’ </ tpl > ’ ,
341 ’ min - h e i g h t : 1 6 ; ’ ,
342 ’ padding - left :21 px ; ’ ,
343 ’ < tpl if =" i s P r e s e n t === f a l s e " > c o l o r : g r a y ; </ tpl > ’ ,
344 ’ " >{ t e x t } </ div > ’
345 ]
346 );
347 var combo = Ext . c r e a t e ( ’ E x t . f o r m . f i e l d . C o m b o B o x ’ , {
348 fieldLabel : ’’ ,
349 name : ’ o n D e t e c t i o n D e v i c e ’ ,
350 id : ’ o n D e t e c t i o n D e v i c e ’ ,
351 editable : false ,
352 s t o r e : me . s t o r e ,
353 queryMode : ’ l o c a l ’ ,
354 displayField : ’ name ’ ,
355 valueField : ’ id ’ ,
356 l i s t C o n f i g : { itemTpl : iconTpl } ,
357 f o r c e S e l e c t i o n : true
358 }) ;
359 combo . on ( ’ r e n d e r ’ , function ( t h i s B o x ) {
360 // a l s o c r e a t e and r e n d e r t h e p i c k e r on b o x r e n d e r i n g
361 // o t h e r w i s e r e n d e r −t i m e s e l e c t i o n i s n o t a v a i l a b l e
362 var p i c k e r = t h i s B o x . g e t P i c k e r ( ) ;
363 p i c k e r . doAutoRender ( ) ;
364 }) ;
365 combo . on ( ’ s e l e c t ’ , function ( f i e l d , v a l u e , o p t i o n s ) {
366 // d i s p l a y t h e i c o n
367 var bg = ’ b a c k g r o u n d : n o n e ; ’ ;
368 var i c o n = ( v a l u e . l e n g t h > 0 ? v a l u e [ 0 ] . g e t ( ’ i c o n ’ ) : n u l l ) ;
369 i f ( icon ) {
370 var u r l = ’ i m a g e s / d s s / ’ + i c o n ;
371 bg = " b a c k g r o u n d : l e f t c e n t e r n o - r e p e a t u r l ( ’ "+ u r l +" ’ ) ; " ;
372 }
373 f i e l d . s e t F i e l d S t y l e ( bg + ’ p a d d i n g - l e f t : 2 1 p x ; ’ ) ;
374 }) ;
375
376
377 Ext . getCmp ( ’ s t a r t D e t e c t i o n C o n t a i n e r ’ ) . add ( combo ) ;
378 },
379
380 a j a x : function ( path , s u c c e s s ) {
381 var me = t h i s ;
382 Ext . Ajax . r e q u e s t ( {
383 d i s a b l e C a c h i n g : true ,
384 method : ’ G E T ’ ,
385 timeout : 20000 ,
386 u r l : ’ / j s o n / ’ + path ,
387 success : success ,
388 f a i l u r e : function ( ) {
389 Ext . Msg . a l e r t ( ( " A t e r r i b l e error happend . Aborting ") ) ;
390 me . s e t L o a d i n g ( f a l s e ) ;
391 me . h i d e ( ) ;
392 }
393 }) ;
394 },
395
396 o p e n D e v i c e : function ( d e v i c e ) {
397 var me = t h i s ;
398 me . d e v i c e = d e v i c e ;
399 me . s e t T i t l e ( d e v i c e . g e t ( ’ n a m e ’ ) ) ;
400 me . show ( ) ;
401 me . s e t L o a d i n g ( true ) ;
402 me . a j a x ( " p r o p e r t y / g e t S t r i n g ? p a t h = / s c r i p t s / s m a r t - g r i d / d e v i c e s / " + d e v i c e . g e t ( ’ i d ’ )
+ " / c o n f i g / a l l " , function ( r e s p o n s e ) {
403 var d a t a = Ext . JSON . d e c o d e ( r e s p o n s e . r e s p o n s e T e x t ) ;
404 Ext . getCmp ( ’ o n D e t e c t i o n ’ ) . s e t V a l u e ( f a l s e ) ;
405 Ext . getCmp ( ’ o n D e t e c t i o n ’ ) . s e t V a l u e ( true ) ;
406 // E x t . getCmp ( ’ i n t e r r u p t T r u e ’ ) . s e t V a l u e ( t r u e ) ;
407 Ext . getCmp ( ’ e x c l u d e ’ ) . s e t V a l u e ( f a l s e ) ;
408 Ext . getCmp ( ’ e x c l u d e ’ ) . s e t V a l u e ( true ) ;
409 i f ( d a t a . ok ) {
410 d a t a = Ext . JSON . d e c o d e ( d a t a . r e s u l t . v a l u e ) ;
411 Ext . getCmp ( ’ f o r m ’ ) . getForm ( ) . s e t V a l u e s ( d a t a ) ;
412 i f ( d a t a . d a t e !== u n d e f i n e d ) {
413 var d t = new Date ( d a t a . d a t e ) ;
414 Ext . getCmp ( ’ o n S i n g l e S l o t D a t e ’ ) . s e t V a l u e ( d t ) ;
415 }
416 i f ( d a t a . o n D e t e c t i o n D e v i c e !== u n d e f i n e d ) {
417 var box = Ext . getCmp ( ’ o n D e t e c t i o n D e v i c e ’ ) ;
418 box . f i r e E v e n t ( ’ s e l e c t ’ , box , [ me . s t o r e . f i n d R e c o r d ( ’ i d ’ , d a t a .
onDetectionDevice ) ] , null ) ;
419 }
420 }
B. Source Code 29
421 me . s e t L o a d i n g ( f a l s e ) ;
422 }) ;
423 }
424 }) ;
68 }
69 }
70 somethingChanged = true ;
71 d e v i c e s . put ( i d , D e v i c e . c r e a t e D e v i c e ( params , this ) ) ;
72 }
73 else {
74 LOG. l o g ( ” R e c e i v e d strange device spec without id ” , 0) ;
75 }
76 }
77
78 // r e m o v e d e v i c e s t h a t a r e g o n e
79 I t e r a t o r <S t r i n g > i t = d e v i c e s . k e y S e t ( ) . i t e r a t o r ( ) ;
80 while ( i t . hasNext ( ) ) {
81 S t r i n g id = i t . next ( ) ;
82 i f ( ! ne wIds . c o n t a i n s ( i d ) ) {
83 i t . remove ( ) ;
84 }
85 }
86
87
88 // n o t i f y s e r v e r t h a t i r e c e i v e d a new c o n f i g if something changed
89 i f ( somethingChanged ) s e r v e r . new Con fig ( ) ;
90 }
91
92 p r i v a t e void newConsumptions ( Document dom ) {
93 N o d e L i s t d e v i c e s N o d e L i s t = dom . getElementsByTagName ( ” i t e m ” ) ;
94 HashMap<Date , Double> newValues = new HashMap<Date , Double >() ;
95 LOG. l o g ( ” v a l u e s ” + d e v i c e s N o d e L i s t . g e t L e n g t h ( ) , 2 0 ) ;
96 f o r ( i n t i =0; i <d e v i c e s N o d e L i s t . g e t L e n g t h ( ) ; i ++){
97 NodeList c h i l d r e n = d e v i c e s N o d e L i s t . item ( i ) . getChildNodes ( ) ;
98 Node timestamp = n u l l ;
99 Node v a l u e = n u l l ;
100 f o r ( i n t j = 0 ; j <c h i l d r e n . g e t L e n g t h ( ) ; j ++){
101 i f ( c h i l d r e n . i t e m ( j ) . getNodeName ( ) == ” v a l u e ” ) {
102 value = c h i l d r e n . item ( j ) ;
103 }
104 e l s e i f ( c h i l d r e n . i t e m ( j ) . getNodeName ( ) == ” timestamp ” ) {
105 timestamp = c h i l d r e n . i t e m ( j ) ;
106 }
107 }
108 i f ( timestamp == n u l l | | v a l u e == n u l l ) {
109 continue ;
110 }
111 S t r i n g t i m e = timestamp . g e t T e x t C o n t e n t ( ) ;
112 try {
113 Date d a t e = S i n g l e t o n U t i l . i n s t a n c e ( ) . gmtDateFormat . p a r s e ( t i m e ) ;
114 double v = Double . p a r s e D o u b l e ( v a l u e . g e t T e x t C o n t e n t ( ) ) ;
115 newValues . put ( d a t e , v ) ;
116 LOG. l o g ( S i n g l e t o n U t i l . i n s t a n c e ( ) . formatTime ( d a t e ) + ” ” + v , 2 0 ) ;
117 } catch ( P a r s e E x c e p t i o n e ) {
118 continue ;
119 }
120 }
121 t h i s . s e r v e r . newConsumptions ( newValues , t h i s ) ;
122 }
123
124 public void s e n d ( S t r i n g d a t a ) {
125 s e r v e r . send ( channel , data . getBytes ( ) ) ;
126 }
127
128 p r i v a t e void removeCommands ( ) {
129 i n t f i r s t = s t r i n g B u i l d e r . i n d e x O f ( ”<” ) ;
130 f o r ( i n t i = 0 ; i < f i r s t ; i ++){
131 i f ( Character . i s W h i t e s p a c e ( s t r i n g B u i l d e r . charAt ( 0 ) ) ) {
132 s t r i n g B u i l d e r . deleteCharAt (0) ;
133 }
134 else {
135 System . e r r . p r i n t l n ( ” R e c e i v e d d a t a n o t e x p e c t e d ” ) ;
136 s e r v e r . closeConnection ( channel ) ;
137 return ;
138 }
139 }
140
141
142 i n t l a s t = s t r i n g B u i l d e r . i n d e x O f ( ”>” ) ;
143 S t r i n g xml = n u l l ;
144 i f ( l a s t != −1){
145 S t r i n g root = s t r i n g B u i l d e r . s u b s t r i n g (1 , l a s t ) . trim ( ) ;
146 i f ( ! r o o t . endsWith ( ” / ” ) ) {
147 l a s t = s t r i n g B u i l d e r . indexOf ( root , l a s t ) ;
148 i f ( l a s t != −1){
149 l a s t = s t r i n g B u i l d e r . i n d e x O f ( ”>” , l a s t ) ;
150 }
151 }
B. Source Code 31
152 i f ( l a s t != −1){
153 xml = s t r i n g B u i l d e r . s u b s t r i n g ( 0 , l a s t +1) ;
154 s t r i n g B u i l d e r . d e l e t e ( 0 , l a s t +1) ;
155 }
156 }
157 i f ( xml != n u l l ) {
158 S t r i n g R e a d e r r e a d e r = new S t r i n g R e a d e r ( xml ) ;
159 I n p u t S o u r c e i n p u t S o u r c e = new I n p u t S o u r c e ( r e a d e r );
160 Document dom = n u l l ;
161 try {
162 dom = d o m B u i l d e r . p a r s e ( i n p u t S o u r c e ) ;
163 } catch ( E x c e p t i o n e ) {
164 e . printStackTrace () ;
165 s e r v e r . closeConnection ( channel ) ;
166 return ;
167 }
168
169 S t r i n g r o o t = dom . getDocumentElement ( ) . getNodeName ( ) ;
170 i f ( root . equals (” config ”) ){
171 newC onfi g ( dom ) ;
172 }
173 else i f ( root . e q u a l s ( ” consumptions ” ) ) {
174 newConsumptions ( dom ) ;
175 }
176 e l s e i f ( r o o t . e q u a l s ( ” time ” ) ) {
177 s e n d ( ”<time>” + S i n g l e t o n U t i l . i n s t a n c e ( ) . formatTime (new Date ( ) ) + ”</time >\n” )
;
178 }
179 else {
180 LOG. l o g ( ” R e c e i v e d unknown xml d a t a ” , 0 ) ;
181 LOG. l o g ( xml , 1 ) ;
182 }
183 reader . close () ;
184 }
185 }
186
187 public HashSet<S h o r t O f f D e v i c e > g e t S h o r t O f f D e v i c e s ( ) {
188 HashSet<S h o r t O f f D e v i c e > r e s u l t = new HashSet<S h o r t O f f D e v i c e >() ;
189 synchronized ( d e v i c e s ) {
190 I t e r a t o r <D e v i c e> i t = d e v i c e s . v a l u e s ( ) . i t e r a t o r ( ) ;
191 while ( i t . hasNext ( ) ) {
192 Device d e v i c e = i t . next ( ) ;
193 i f ( d e v i c e instanceof ShortOffDevice ) {
194 ShortOffDevice d = ( ShortOffDevice ) device ;
195 r e s u l t . add ( d ) ;
196 }
197 }
198 }
199 return r e s u l t ;
200 }
201
202 public T r e e S e t <DelayOnDevice> g e t D e l a y O n D e v i c e s ( ) {
203 T r e e S e t <DelayOnDevice> r e s u l t = new T r e e S e t <DelayOnDevice >( S i n g l e t o n U t i l . i n s t a n c e
( ) . delayOnComparator ) ;
204 synchronized ( d e v i c e s ) {
205 I t e r a t o r <D e v i c e> i t = d e v i c e s . v a l u e s ( ) . i t e r a t o r ( ) ;
206 while ( i t . hasNext ( ) ) {
207 Device d e v i c e = i t . next ( ) ;
208 i f ( d e v i c e i n s t a n c e o f DelayOnDevice ) {
209 DelayOnDevice d = ( DelayOnDevice ) d e v i c e ;
210 r e s u l t . add ( d ) ;
211 }
212 }
213 }
214 return r e s u l t ;
215 }
216
217 public S t r i n g g e t I d ( ) {
218 return t h i s . c h a n n e l . s o c k e t ( ) . g e t R e m o t e S o c k e t A d d r e s s ( ) . t o S t r i n g ( ) . s u b s t r i n g ( 1 ) ;
219 }
220 }
1 package ch . e t h z . baumachr . e n e r g y P r o v i d e r ;
2
3 import java . i o . IOException ;
4 import java . u t i l . Calendar ;
5 import java . u t i l . Date ;
6 import java . u t i l . GregorianCalendar ;
7 import java . u t i l . HashMap ;
8 import java . u t i l . Observable ;
B. Source Code 32
9 import j a v a . u t i l . O b s e r v e r ;
10
11 import j a v a x . xml . p a r s e r s . D o c u m en t B u i ld e r ;
12 import j a v a x . xml . p a r s e r s . D o c u m e n t B u i l d e r F a c t o r y ;
13 import j a v a x . xml . p a r s e r s . P a r s e r C o n f i g u r a t i o n E x c e p t i o n ;
14
15 import org . w3c . dom . Document ;
16 import org . w3c . dom . Node ;
17 import org . w3c . dom . N o d e L i s t ;
18 import org . xml . s a x . SAXException ;
19
20 public c l a s s C o n t r o l l e r implements Runnable , Observer {
21 public s t a t i c f i n a l i n t LOG LEVEL = 1 0 ;
22
23 private f i n a l DSSServer s e r v e r ;
24 private f i n a l IntradayMarketDataPoint [ ] data ;
25 private f i n a l HashMap<Date , Double> dataMapping ;
26
27 p r i v a t e D o c um e n t Bu i l d e r d o m B u i l d e r ;
28
29 private final L o g g e r LOG;
30
31 p r i v a t e boolean d o S c h e d u l i n g = f a l s e ;
32
33 public C o n t r o l l e r ( DSSServer s ) {
34 LOG = S i n g l e t o n U t i l . i n s t a n c e ( ) .LOG;
35 this . server = s ;
36 d a t a = new I n t r a d a y M a r k e t D a t a P o i n t [ 4 8 ] ;
37 dataMapping = new HashMap<Date , Double >() ;
38 try {
39 DocumentBuilderFactory dbf = DocumentBuilderFactory . newInstance ( ) ;
40 d b f . setNamespaceAware ( f a l s e ) ;
41 dbf . s e t V a l i d a t i n g ( f a l s e ) ;
42 d b f . s e t F e a t u r e ( ” h t t p : / / xml . o r g / s a x / f e a t u r e s / n a m e s p a c e s ” , f a l s e ) ;
43 d b f . s e t F e a t u r e ( ” h t t p : / / xml . o r g / s a x / f e a t u r e s / v a l i d a t i o n ” , f a l s e ) ;
44 d b f . s e t F e a t u r e ( ” h t t p : / / a p a c h e . o r g / xml / f e a t u r e s / n o n v a l i d a t i n g / l o a d −dtd−grammar ” ,
false ) ;
45 d b f . s e t F e a t u r e ( ” h t t p : / / a p a c h e . o r g / xml / f e a t u r e s / n o n v a l i d a t i n g / l o a d −e x t e r n a l −dtd ” ,
false ) ;
46 d o m B u i l d e r = d b f . newDocumentBuilder ( ) ;
47 } catch ( P a r s e r C o n f i g u r a t i o n E x c e p t i o n e ) {
48 e . printStackTrace () ;
49 }
50
51 // add m y s e l f t o r e c e i v e u p d a t e calls from t h e s e r v e r on c o n f i g change
52 s e r v e r . addObserver ( this ) ;
53 }
54
55 p r i v a t e boolean g e t M a r k e t D a t a ( ) {
56 boolean n o t h i n g C h a n g e d = true ;
57 try {
58 //TODO c h a n g e i n d a t a l a y o u t
59 i f ( false ){
60 Document dom = d o m B u i l d e r . p a r s e ( ” h t t p : / /www. e p e x s p o t . com/ en / market−d a t a / i n t r a d a y
/ i n t r a d a y −t a b l e /−/DE” ) ;
61 N o d e L i s t rows = dom . getElementsByTagName ( ” t r ” ) ;
62 System . o u t . p r i n t l n ( rows . g e t L e n g t h ( ) ) ;
63 f o r ( i n t i = 3 ; i < rows . g e t L e n g t h ( ) − 2 ; i ++){
64 N o d e L i s t columns = rows . i t e m ( i ) . g e t C h i l d N o d e s ( ) ;
65 int index = 0 ;
66 int columnIndex = i − 3 ;
67 i f ( d a t a [ c o l u m n I n d e x ] == n u l l ) {
68 C a l e n d a r c a l = new G r e g o r i a n C a l e n d a r ( ) ;
69 c a l . s e t T i m e (new Date ( ) ) ;
70 c a l . s e t ( C a l e n d a r . HOUR OF DAY, c o l u m n I n d e x ) ;
71 c a l . s e t ( C a l e n d a r . MINUTE, 3 0 ) ;
72 c a l . s e t ( C a l e n d a r . SECOND, 0 ) ;
73 c a l . s e t ( C a l e n d a r . MILLISECOND , 0 ) ;
74
75 d a t a [ c o l u m n I n d e x ] = new I n t r a d a y M a r k e t D a t a P o i n t ( ) ;
76 d a t a [ c o l u m n I n d e x ] . s e t H o u r ( c a l . getTime ( ) ) ;
77
78 c a l . add ( C a l e n d a r . DAY OF MONTH, 1 ) ;
79 d a t a [ c o l u m n I n d e x + 2 4 ] = new I n t r a d a y M a r k e t D a t a P o i n t ( ) ;
80 d a t a [ c o l u m n I n d e x + 2 4 ] . s e t H o u r ( c a l . getTime ( ) ) ;
81 }
82 IntradayMarketDataPoint today = data [ columnIndex ] ;
83 I n t r a d a y M a r k e t D a t a P o i n t tomorow = d a t a [ c o l u m n I n d e x + 2 4 ] ;
84 f o r ( i n t j = 0 ; j < columns . g e t L e n g t h ( ) ; j ++){
85 Node c e l l N o d e = columns . i t e m ( j ) ;
86 i f ( c e l l N o d e . getNodeType ( ) == Node .ELEMENT NODE) {
87 S t r i n g c e l l = cellNode . getTextContent ( ) . trim ( ) ;
88
89 I n t r a d a y M a r k e t D a t a P o i n t column = tomorow ;
B. Source Code 33
90 switch ( i n d e x ) {
91 case 0 : // h o u r (01 −02)
92 break ;
93 case 1 : // l o w t o d a y
94 case 8 : // l o w t o m o r r o w
95 break ;
96 case 2 : // h i g h t o d a y
97 case 9 : // h i g h t o m o r r o w
98 break ;
99 case 3 : // l a s t t o d a y
100 column = t o d a y ;
101 // b r e a k t r o u g h i n t e n d e d
102 case 1 0 : // l a s t t o m o r r o w
103 try {
104 double l a s t = Double . p a r s e D o u b l e ( c e l l ) ;
105 i f ( ! column . i s S a m e L a s t ( l a s t ) ) {
106 LOG. l o g ( ” L a s t f o r ” +
107 S i n g l e t o n U t i l . i n s t a n c e ( ) . formatTime ( column . g e t D a t e ( ) ) +
108 ” changed from ” + column . g e t L a s t ( ) + ” t o ” + c e l l , 1 5 ) ;
109 column . s e t L a s t ( Double . p a r s e D o u b l e ( c e l l ) ) ;
110 nothingChanged = f a l s e ;
111 }
112 }
113 catch ( NumberFormatException e ) {}
114 break ;
115 case 4 : // a v g
116 break ;
117 }
118 i n d e x ++;
119 }
120 }
121 }
122 i f ( ! nothingChanged ) {
123 LOG. l o g ( ” Market d a t a changed ” , 8 ) ;
124 f o r ( i n t i = 0 ; i < d a t a . l e n g t h ; i ++){
125 i f ( data [ i ] . a v a i l a b l e ( ) ) {
126 dataMapping . put ( d a t a [ i ] . g e t D a t e ( ) , d a t a [ i ] . g e t L a s t ( ) ) ;
127 }
128 }
129 s e r v e r . newMarketData ( dataMapping ) ;
130 }
131 }
132 } catch ( SAXException e 2 ) {
133 e2 . p r i n t S t a c k T r a c e ( ) ;
134 } catch ( I O E x c e p t i o n e 2 ) {
135 e2 . p r i n t S t a c k T r a c e ( ) ;
136 }
137 return ! n o t h i n g C h a n g e d ;
138 }
139
140 p r i v a t e void s c h e d u l e D e v i c e s ( ) {
141 /∗LOG. l o g ( ” D o i n g s c h e d u l i n g ” , 6 ) ;
142 T r e e S e t <D e l a y O n D e v i c e > d e v i c e s = s e r v e r . g e t D e l a y O n D e v i c e s ( ) ;
143 I t e r a t o r <D e l a y O n D e v i c e > i t = d e v i c e s . i t e r a t o r ( ) ;
144
145 Calendar startTime = Calendar . g e t I n s t a n c e () ;
146 // s e t t l e down f i r s t
147 s t a r t T i m e . add ( C a l e n d a r . SECOND, 6 0 0 ) ;
148 w h i l e ( i t . hasNext () ){
149 DelayOnDevice dev = i t . n e x t ( ) ;
150 Calendar d e a d l i n e = dev . g e t D e a d l i n e () ;
151 i f ( startTime . a f t e r ( deadline ) ){
152 d e v . turnOn ( d e a d l i n e . g e t T i m e ( ) ) ;
153 }
154 else{
155 d e v . turnOn ( s t a r t T i m e . g e t T i m e ( ) ) ;
156 s t a r t T i m e . add ( C a l e n d a r . SECOND, d e v . getOnTime ( ) ) ;
157 }
158 } ∗/
159 }
160
161 @Ove rri de
162 public void run ( ) {
163 C a l e n d a r nextMarketUpdate = C a l e n d a r . g e t I n s t a n c e ( ) ;
164 while ( true ) {
165 try {
166 boolean s c h e d u l e = f a l s e ;
167 synchronized ( t h i s ) {
168 i f ( doScheduling ) {
169 doScheduling = false ;
170 s c h e d u l e = true ;
171 }
172 }
173 i f ( schedule ) scheduleDevices () ;
B. Source Code 34
174
175 C a l e n d a r now = C a l e n d a r . g e t I n s t a n c e ( ) ;
176 long d t = nextMarketUpdate . g e t T i m e I n M i l l i s ( ) − now . g e t T i m e I n M i l l i s ( ) ;
177 boolean marketChanged = f a l s e ;
178 i f ( d t <= 0 ) {
179 LOG. l o g ( ” U p d a t e i n g market d a t a ” , 1 8 ) ;
180 int minutes = 5 ;
181 marketChanged = g e t M a r k e t D a t a ( ) ;
182 nextMarketUpdate = now ;
183 nextMarketUpdate . add ( C a l e n d a r . MINUTE, m i n u t e s ) ;
184 d t = m i n u t e s ∗ 60 ∗ 1 0 0 0 ;
185 }
186
187 LOG. l o g ( ” W a i t i n g ” + d t / 1 0 0 0 + ” s ” , 2 5 ) ;
188 synchronized ( t h i s ) {
189 i f ( marketChanged ) {
190 d o S c h e d u l i n g = true ;
191 }
192 i f ( ! doScheduling ) {
193 t h i s . wait ( dt ) ;
194 }
195 }
196 } catch ( I n t e r r u p t e d E x c e p t i o n e ) {
197 e . printStackTrace () ;
198 }
199 }
200 }
201
202 @Ove rri de
203 public void u p d a t e ( O b s e r v a b l e a r g 0 , Object arg1 ) {
204 synchronized ( t h i s ) {
205 t h i s . d o S c h e d u l i n g = true ;
206 this . n o t i f y () ;
207 }
208 }
209 }
1 package ch . e t h z . baumachr . e n e r g y P r o v i d e r ;
2
3 import j a v a . u t i l . HashMap ;
4 import j a v a . u t i l . I t e r a t o r ;
5 import j a v a . u t i l . Map ;
6
7 public a b s t r a c t c l a s s D e v i c e {
8 public s t a t i c f i n a l i n t LOG LEVEL = 1 ;
9 protected f i n a l S t r i n g i d ;
10 protected f i n a l HashMap<S t r i n g , S t r i n g > params ;
11 protected f i n a l C l i e n t c l i e n t ;
12
13 protected f i n a l L o g g e r LOG;
14
15
16 public D e v i c e ( f i n a l HashMap<S t r i n g , S t r i n g > params , Client c ){
17 t h i s . i d = params . g e t ( ” i d ” ) ;
18 t h i s . params = params ;
19 this . c l i e n t = c ;
20 t h i s .LOG = S i n g l e t o n U t i l . i n s t a n c e ( ) .LOG;
21 print () ;
22 }
23
24 public s t a t i c D e v i c e c r e a t e D e v i c e ( HashMap<S t r i n g , S t r i n g > params , Client c ){
25 S t r i n g t y p e = params . g e t ( ” t y p e ” ) ;
26 i f ( t y p e == n u l l ) {
27 return n u l l ;
28 }
29 try {
30 i f ( t y p e . e q u a l s ( ” on ” ) ) {
31 return new DelayOnDevice ( params , c ) ;
32 }
33 else i f ( type . e q u a l s ( ” o f f ” ) ) {
34 return new S h o r t O f f D e v i c e ( params , c ) ;
35 }
36 }
37 catch ( WrongParameterException e ) {
38 e . printStackTrace () ;
39 return n u l l ;
40 }
41 return n u l l ;
42 }
43
B. Source Code 35
1 package ch . e t h z . baumachr . e n e r g y P r o v i d e r ;
2
3 import java . text . ParseException ;
4 import java . util . Calendar ;
5 import java . util . Date ;
6 import java . util . GregorianCalendar ;
7 import java . util . HashMap ;
8
9 public c l a s s DelayOnDevice extends D e v i c e {
10
11 public s t a t i c final i n t LOG LEVEL = 1 0 ;
12
13 private final L o g g e r LOG = S i n g l e t o n U t i l . i n s t a n c e ( ) .LOG;
14
15 p r i v a t e Date s c h e d u l e d A t = n u l l ;
16
17 private f i n a l S t r i n g [ ] keys = {
18 // ” s t a r t D e t e c t i o n ” ,
19 // ” i n t e r r u p t ” ,
20 ” onTime ” ,
21 ” slotLength ” ,
22 ” startTime ”
23 };
24
25 public DelayOnDevice ( HashMap<S t r i n g , S t r i n g > params , C l i e n t c ) throws
WrongParameterException {
26 super ( params , c ) ;
27 checkParams ( ” on ” , k e y s ) ;
28 }
29
B. Source Code 36
30 public Date g e t S t a r t T i m e ( ) {
31 try {
32 return S i n g l e t o n U t i l . i n s t a n c e ( ) . gmtDateFormat . p a r s e ( params . g e t ( ” s t a r t T i m e ” ) ) ;
33 } catch ( P a r s e E x c e p t i o n e ) {
34 e . printStackTrace () ;
35 }
36 return n u l l ;
37 }
38
39 public C a l e n d a r g e t D e a d l i n e ( ) {
40 C a l e n d a r s t a r t = new G r e g o r i a n C a l e n d a r ( ) ;
41 s t a r t . setTime ( getStartTime ( ) ) ;
42 s t a r t . add ( C a l e n d a r . SECOND, I n t e g e r . p a r s e I n t ( params . g e t ( ” s l o t L e n g t h ” ) ) − I n t e g e r .
p a r s e I n t ( params . g e t ( ” onTime ” ) ) ) ;
43 return s t a r t ;
44 }
45
46 public i n t getOnTime ( ) {
47 return I n t e g e r . p a r s e I n t ( params . g e t ( ” onTime ” ) ) ;
48 }
49
50 public Date g e t S c h e d u l e d T i m e ( ) {
51 return s c h e d u l e d A t ;
52 }
53
54 public void turnOn ( Date t i m e ) {
55 i f ( s c h e d u l e d A t == n u l l ) {
56 r e s c h e d u l e ( time ) ;
57 }
58 }
59
60 public void r e s c h e d u l e ( Date t i m e ) {
61 S t r i n g a t = ( t i m e != n u l l ) ? ” a t =’ ” + S i n g l e t o n U t i l . i n s t a n c e ( ) . formatTime ( t i m e ) + ”
’ ” : ”” ;
62 c l i e n t . s e n d ( ”<d e l a y o n ” + a t + ”>” + i d + ”</d e l a y o n >\n” ) ;
63 LOG. l o g ( ” Turning on d e v i c e ” + i d , 4 ) ;
64 LOG. l o g ( ” \t@” + ( ( t i m e==n u l l ) ? ”now” : S i n g l e t o n U t i l . i n s t a n c e ( ) . formatTime ( t i m e ) ) , 4 )
;
65 scheduledAt = time ;
66 }
67 }
1 package ch . e t h z . baumachr . e n e r g y P r o v i d e r ;
2
3 import j a v a . u t i l . HashMap ;
4
5 public c l a s s S h o r t O f f D e v i c e extends D e v i c e {
6
7 private f i n a l S t r i n g [ ] keys = {
8 ” offTime ” ,
9 ” slotLength ”
10 };
11
12 public S h o r t O f f D e v i c e ( HashMap<S t r i n g , S t r i n g > params , C l i e n t c ) throws
WrongParameterException {
13 super ( params , c ) ;
14 checkParams ( ” o f f ” , k e y s ) ;
15 }
16
17 public void t u r n O f f ( i n t s e c o n d s ) {
18 S t r i n g s = ( s e c o n d s > 0 ) ? ” s e c o n d s =’ ” + s e c o n d s + ” ’ ” : ” ” ;
19 c l i e n t . s e n d ( ”< s h o r t o f f ” + s + ”>” + i d + ”</ s h o r t o f f >\n” ) ;
20 }
21
22 public void turnOn ( ) {
23 c l i e n t . s e n d ( ”< s h o r t o f f s e c o n d s =’0 ’ > ” + i d + ”</ s h o r t o f f >\n” ) ;
24 }
25 }
1 package ch . e t h z . baumachr . e n e r g y P r o v i d e r ;
2
3
4 import java . i o . IOException ;
5 import java . net . InetSocketAddress ;
6 import java . net . Socket ;
7 import java . nio . ByteBuffer ;
B. Source Code 37
92 }
93
94 public T r e e S e t <DelayOnDevice> g e t D e l a y O n D e v i c e s ( ) {
95 T r e e S e t <DelayOnDevice> r e s u l t = new T r e e S e t <DelayOnDevice >( S i n g l e t o n U t i l . i n s t a n c e
( ) . delayOnComparator ) ;
96 synchronized ( c l i e n t s ) {
97 I t e r a t o r <S o c k e t C h a n n e l > i t = c l i e n t s . i t e r a t o r ( ) ;
98 while ( i t . hasNext ( ) ) {
99 SocketChannel channel = i t . next ( ) ;
100 C l i e n t c = ( C l i e n t ) c h a n n e l . keyFor ( s e l e c t o r ) . a t t a c h m e n t ( ) ;
101 T r e e S e t <DelayOnDevice> l = c . g e t D e l a y O n D e v i c e s ( ) ;
102 r e s u l t . addAll ( l ) ;
103 }
104 }
105 return r e s u l t ;
106 }
107
108 @Ove rri de
109 public void run ( ) {
110 try {
111 while ( ! Thread . i n t e r r u p t e d ( ) ) {
112
113 // i t e r a t e t h r o u g h t h e w r i t e R e q u e s t s L i s t and mark c l i e n t s t h a t want t o w r i t e
114 synchronized ( t h i s . w r i t e R e q u e s t s ) {
115 I t e r a t o r <S o c k e t C h a n n e l > w r i t e R e q u e s t K e y s = t h i s . w r i t e R e q u e s t s . k e y S e t ( ) .
iterator () ;
116 while ( w r i t e R e q u e s t K e y s . hasNext ( ) ) {
117 SocketChannel c = writeRequestKeys . next ( ) ;
118 i f ( ! w r i t e R e q u e s t s . g e t ( c ) . isEmpty ( ) ) {
119 c . keyFor ( s e l e c t o r ) . i n t e r e s t O p s ( S e l e c t i o n K e y . OP WRITE) ;
120 }
121 }
122 }
123
124 //TODO s o l v e t h i s i n a b e t t e r way
125 // t h i s d o e s n o t w o r k i f e v e r y 9 s e c o n d s another client connects
126 // t o t h e s e l e c t c a l l w i t h a t i m e o u t
127 s e l e c t o r . s e l e c t (10000) ;
128
129 Set<S e l e c t i o n K e y > s e l e c t e d = s e l e c t o r . s e l e c t e d K e y s ( ) ;
130
131 // c h e c k i f t h e t i m e o u t o f s e l e c t e x p i r e d o r i f t h e r e is a action g o i n g on
132 i f ( s e l e c t e d . isEmpty ( ) ) {
133 // s e n d a p i n g m e s s a g e t o a l l c l i e n t s
134 synchronized ( c l i e n t s ) {
135 I t e r a t o r <S o c k e t C h a n n e l > i t = c l i e n t s . i t e r a t o r ( ) ;
136 while ( i t . hasNext ( ) ) {
137 SocketChannel c = i t . next ( ) ;
138 s e n d I t ( c , ”<p i n g />\n” . g e t B y t e s ( ) ) ;
139 }
140 }
141 continue ;
142 }
143
144 // a n a l y z e a l l s e l e c t e d k e y s
145 I t e r a t o r <S e l e c t i o n K e y > i t r = s e l e c t e d . i t e r a t o r ( ) ;
146 while ( i t r . hasNext ( ) ) {
147 S e l e c t i o n K e y key = i t r . n e x t ( ) ;
148 i f ( key . i s A c c e p t a b l e ( ) ) {
149 a c c e p t ( key ) ;
150 }
151 e l s e i f ( key . i s R e a d a b l e ( ) ) {
152 r e a d ( key ) ;
153 }
154 e l s e i f ( key . i s W r i t a b l e ( ) ) {
155 w r i t e ( key ) ;
156 }
157 else {
158 System . e r r . p r i n t l n ( ” s t r a n g e ” ) ;
159 }
160 }
161 // c l e a r t h e k e y s f r o m t h e s e t s i n c e t h e y a r e a l r e a d y processed
162 selected . clear () ;
163 }
164 }
165 catch ( E x c e p t i o n ex ) {
166 ex . p r i n t S t a c k T r a c e ( ) ;
167 }
168 }
169
170 p r i v a t e void a c c e p t ( S e l e c t i o n K e y key ) throws I O E x c e p t i o n ,
ParserConfigurationException {
171 SocketChannel c = s e r v e r S o c k e t . accept ( ) ;
172 Socket s = c . socket ( ) ;
B. Source Code 39
173 LOG. l o g ( s . g e t I n e t A d d r e s s ( ) . g e t H o s t A d d r e s s ( ) + ” : ” + s . g e t P o r t ( ) + ” c o n n e c t e d ” , 3 )
;
174 c . configureBlocking ( false ) ;
175 S e l e c t i o n K e y s k = c . r e g i s t e r ( s e l e c t o r , S e l e c t i o n K e y . OP READ) ;
176 C l i e n t c l i e n t = new C l i e n t ( t h i s , c ) ;
177
178 // add t h e c l i e n t t o t h e l o c a l c l i e n t s List
179 synchronized ( c l i e n t s ) {
180 c l i e n t s . add ( c ) ;
181 }
182 // a t t a c h t h e c l i e n t t o t h e k e y
183 sk . attach ( c l i e n t ) ;
184
185 gui . connected ( c l i e n t . getId ( ) ) ;
186 }
187
188 p r i v a t e void r e a d ( S e l e c t i o n K e y key ) throws P a r s e r C o n f i g u r a t i o n E x c e p t i o n {
189 S o c k e t C h a n n e l c = ( S o c k e t C h a n n e l ) key . c h a n n e l ( ) ;
190 reusableBuffer . clear () ;
191 int bytesRead = 0 ;
192 try {
193 bytesRead = c . read ( r e u s a b l e B u f f e r ) ;
194 } catch ( I O E x c e p t i o n e ) {
195 closeConnection ( c ) ;
196 return ;
197 }
198 i f ( bytesRead < 0) {
199 closeConnection ( c ) ;
200 return ;
201 }
202 i f ( bytesRead > 0) {
203 C l i e n t c l i e n t = ( C l i e n t ) key . a t t a c h m e n t ( ) ;
204 byte [ ] s u b s t r i n g = new byte [ b y t e s R e a d ] ;
205 reusableBuffer . f l i p () ;
206 reusableBuffer . get ( substring ) ;
207 c l i e n t . newData ( s u b s t r i n g ) ;
208 }
209 }
210
211 public void c l o s e C o n n e c t i o n ( S o c k e t C h a n n e l c ) {
212 S e l e c t i o n K e y s k = c . keyFor ( s e l e c t o r ) ;
213 C l i e n t c l i e n t O b j e c t = ( C l i e n t ) sk . attachment ( ) ;
214 gui . disconnected ( clientObject . getId () ) ;
215 Socket s = c . socket ( ) ;
216 LOG. l o g ( s . g e t I n e t A d d r e s s ( ) . g e t H o s t A d d r e s s ( ) + ” : ” + s . g e t P o r t ( ) + ” d i s c o n n e c t e d ” ,
3) ;
217 synchronized ( w r i t e R e q u e s t s ) {
218 w r i t e R e q u e s t s . remove ( c ) ;
219 }
220 c l i e n t s . remove ( c ) ;
221 try {
222 c . close () ;
223 } catch ( I O E x c e p t i o n e ) {
224 e . printStackTrace () ;
225 }
226 return ;
227 }
228
229 p r i v a t e void w r i t e ( S e l e c t i o n K e y key ) throws I O E x c e p t i o n ,
ParserConfigurationException {
230 S o c k e t C h a n n e l c = ( S o c k e t C h a n n e l ) key . c h a n n e l ( ) ;
231 synchronized ( w r i t e R e q u e s t s ) {
232 L i s t <B y t e B u f f e r > l i s t = w r i t e R e q u e s t s . g e t ( c ) ;
233 while ( ! l i s t . isEmpty ( ) ) {
234 ByteBuffer buf = l i s t . get ( 0 ) ;
235 c . w r i t e ( buf ) ;
236 i f ( buf . remaining ( ) > 0) {
237 // s o c k e t ’ s b u f f e r f i l l s up
238 break ;
239 }
240 l i s t . remove ( 0 ) ;
241 }
242 i f ( l i s t . isEmpty ( ) ) {
243 // We w r o t e away a l l d a t a , s o we ’ r e no l o n g e r i n t e r e s t e d
244 // i n w r i t i n g on t h i s s o c k e t . S w i t c h b a c k t o w a i t i n g f o r
245 // d a t a .
246 key . i n t e r e s t O p s ( S e l e c t i o n K e y . OP READ) ;
247 }
248 }
249 }
250
251 public void newConsumptions ( HashMap<Date , Double> newValues , Client c ) {
252 g u i . addConsumptionValues ( newValues , c . g e t I d ( ) ) ;
253 }
B. Source Code 40
254
255 public void newMarketData ( HashMap<Date , Double> dataMapping ) {
256 g u i . newMarketData ( dataMapping ) ;
257 }
258
259 public void ne wCon fig ( ) {
260 th is . setChanged ( ) ;
261 this . notifyObservers () ;
262 this . clearChanged ( ) ;
263 }
264 }
1 package ch . e t h z . baumachr . e n e r g y P r o v i d e r ;
2
3 import java . awt . B o r d e r L a y o u t ;
4 import java . awt . C o l o r ;
5 import java . awt . Dimension ;
6 import java . awt . DisplayMode ;
7 import java . awt . G r a p h i c s D e v i c e ;
8 import java . awt . G r a p h i c s E n v i r o n m e n t ;
9 import java . awt . M o u s e I n f o ;
10 import java . awt . P o i n t ;
11 import java . awt . e v e n t . A c t i o n E v e n t ;
12 import java . awt . e v e n t . A c t i o n L i s t e n e r ;
13 import java . u t i l . Calendar ;
14 import java . u t i l . Date ;
15 import java . u t i l . HashMap ;
16 import java . u t i l . HashSet ;
17 import java . util . Iterator ;
18 import java . u t i l . TreeSet ;
19
20 import javax . swing . BorderFactory ;
21 import javax . swing . BoxLayout ;
22 import javax . swing . JButton ;
23 import javax . swing . JFrame ;
24 import javax . swing . JPanel ;
25
26 import org . jfree . chart . ChartFactory ;
27 import org . jfree . c h a r t . ChartPanel ;
28 import org . jfree . c h a r t . JFreeChart ;
29 import org . jfree . c h a r t . a x i s . NumberAxis ;
30 import org . jfree . chart . a x i s . ValueAxis ;
31 import org . jfree . c h a r t . p l o t . XYPlot ;
32 import org . jfree . c h a r t . r e n d e r e r . xy . XYLineAndShapeRenderer ;
33 import org . jfree . data . time . M i l l i s e c o n d ;
34 import org . jfree . d a t a . t i m e . Second ;
35 import org . jfree . data . time . TimeSeries ;
36 import org . jfree . data . time . T i m e S e r i e s C o l l e c t i o n ;
37 import org . jfree . ui . ApplicationFrame ;
38
39 public c l a s s E n e r g y P r o v i d e r extends A p p l i c a t i o n F r a m e {
40 p r i v a t e s t a t i c f i n a l long s e r i a l V e r s i o n U I D = 1L ;
41
42 p r i v a t e f i n a l DSSServer d S S s e r v e r ;
43 private f i n a l T i m e S e r i e s C o l l e c t i o n consumptionDataset ;
44 p r i v a t e f i n a l T i m e S e r i e s consumptionSum ;
45 p r i v a t e f i n a l HashMap<S t r i n g , T i m e S e r i e s > c o n s u m p t i o n S e r i e s ;
46 p r i v a t e f i n a l HashMap<S t r i n g , Long> c o n s u m p t i o n A l r e a d y A d d e d U n t i l ;
47 private T i m e S e r i e s m a r k e t S e r i e s ;
48 p r i v a t e f i n a l L o g g e r LOG;
49
50 final private ChartPanel consumptionChartPanel ;
51
52 public E n e r g y P r o v i d e r ( S t r i n g title ) {
53 super ( t i t l e ) ;
54
55 LOG = S i n g l e t o n U t i l . i n s t a n c e ( ) .LOG;
56
57 JButton u n d e r r u n = new JButton ( ” Underrun ” ) ;
58 u n d e r r u n . a d d A c t i o n L i s t e n e r (new A c t i o n L i s t e n e r ( ) {
59 @Ov err ide
60 public void a c t i o n P e r f o r m e d ( A c t i o n E v e n t e ) {
61 T r e e S e t <DelayOnDevice> d e l a y O n s = d S S s e r v e r . g e t D e l a y O n D e v i c e s ( ) ;
62 I t e r a t o r <DelayOnDevice> o n I t = d e l a y O n s . i t e r a t o r ( ) ;
63 while ( o n I t . hasNext ( ) ) {
64 DelayOnDevice d e v i c e = o n I t . n e x t ( ) ;
65 device . r e s c h e d u l e ( null ) ;
66 }
67 HashSet<S h o r t O f f D e v i c e > s h o r t O f f s = d S S s e r v e r . g e t S h o r t O f f D e v i c e s ( ) ;
68 I t e r a t o r <S h o r t O f f D e v i c e > o f f I t = s h o r t O f f s . i t e r a t o r ( ) ;
B. Source Code 41
69 while ( o f f I t . hasNext ( ) ) {
70 ShortOffDevice d e v i c e = o f f I t . next ( ) ;
71 LOG. l o g ( ” Turning o f f d e v i c e ” + d e v i c e . i d , 4) ;
72 d e v i c e . turnOn ( ) ;
73 }
74 }
75 }) ;
76
77 JButton o v e r r u n = new JButton ( ” Overrun ” ) ;
78 o v e r r u n . a d d A c t i o n L i s t e n e r (new A c t i o n L i s t e n e r ( ) {
79 @Ov erri de
80 public void a c t i o n P e r f o r m e d ( A c t i o n E v e n t e ) {
81 HashSet<S h o r t O f f D e v i c e > d e v i c e s = d S S s e r v e r . g e t S h o r t O f f D e v i c e s ( ) ;
82 I t e r a t o r <S h o r t O f f D e v i c e > i t = d e v i c e s . i t e r a t o r ( ) ;
83 while ( i t . hasNext ( ) ) {
84 ShortOffDevice d e v i c e = i t . next ( ) ;
85 LOG. l o g ( ” Turning o f f d e v i c e ” + d e v i c e . i d , 4 ) ;
86 device . turnOff (0) ;
87 }
88 }
89 }) ;
90
91 c o n s u m p t i o n S e r i e s = new HashMap<S t r i n g , T i m e S e r i e s >() ;
92 c o n s u m p t i o n A l r e a d y A d d e d U n t i l = new HashMap<S t r i n g , Long >() ;
93 consumptionSum = new T i m e S e r i e s ( ”Sum” ) ;
94 consumptionSum . setMaximumItemCount ( 4 0 0 ) ;
95 c o n s u m p t i o n D a t a s e t = new T i m e S e r i e s C o l l e c t i o n ( consumptionSum ) ;
96 J F r e e C h a r t c h a r t = C h a r t F a c t o r y . c r e a t e T i m e S e r i e s C h a r t ( ” Energy Consumption ” , //
title
97 ”Time” , // l a b e l o f x−a x i s
98 ” Energy c o n s u m p t i o n [W] ” , // l a b e l o f y−a x i s
99 consumptionDataset ,
100 true , // l e g e n d
101 true , // t o o l t i p s
102 f a l s e // u r l s
103 );
104 c o n s u m p t i o n C h a r t P a n e l = new C h a r t P a n e l ( c r e a t e T i m e S e r i e s C h a r t ( c h a r t , 5 ∗ 60 ∗
1000 , f a l s e ) ) ;
105 c o n s u m p t i o n C h a r t P a n e l . s e t P r e f e r r e d S i z e ( new Dimension ( 6 0 0 , 250 ) ) ;
106
107 /∗ t h i s . m a r k e t S e r i e s = new T i m e S e r i e s ( ” M a r k e t ” ) ;
108 T i m e S e r i e s C o l l e c t i o n d a t a s e t = new T i m e S e r i e s C o l l e c t i o n ( t h i s . m a r k e t S e r i e s ) ;
109 c h a r t = C h a r t F a c t o r y . c r e a t e T i m e S e r i e s C h a r t ( ” I n t r a d a y M a r k e t ” , // t i t l e
110 ” Time ” , // l a b e l o f x−a x i s
111 ” C o s t [ Euro /kWh ] ” , // l a b e l o f y−a x i s
112 dataset ,
113 f a l s e , // l e g e n d
114 t r u e , // t o o l t i p s
115 f a l s e // u r l s
116 );
117 C h a r t P a n e l m a r k e t C h a r t P a n e l = new C h a r t P a n e l ( c r e a t e T i m e S e r i e s C h a r t ( c h a r t , 24 ∗ 60
∗ 60 ∗ 1 0 0 0 , n u l l , t r u e ) ) ;
118 m a r k e t C h a r t P a n e l . s e t P r e f e r r e d S i z e ( new D i m e n s i o n ( 6 0 0 , 250 ) ) ; ∗/
119
120
121 J P a n e l pu = new J P a n e l ( ) ;
122 pu . add ( u n d e r r u n ) ;
123
124 J P a n e l po = new J P a n e l ( ) ;
125 po . add ( o v e r r u n ) ;
126
127
128 J P a n e l mainPanel = new J P a n e l ( ) ;
129 mainPanel . s e t L a y o u t (new BoxLayout ( mainPanel , BoxLayout . Y AXIS ) ) ;
130 mainPanel . s e t B o r d e r ( B o r d e r F a c t o r y . c r e a t e E m p t y B o r d e r ( 1 0 , 1 0 , 1 0 , 1 0 ) ) ;
131 // m a i n P a n e l . add ( m a r k e t C h a r t P a n e l ) ;
132 mainPanel . add ( c o n s u m p t i o n C h a r t P a n e l ) ;
133 mainPanel . add ( pu ) ;
134 mainPanel . add ( po ) ;
135
136
137 this . s e tR e si za b le ( false ) ;
138 t h i s . g e t C o n t e n t P a n e ( ) . add ( mainPanel , B o r d e r L a y o u t .CENTER) ;
139 t h i s . s e t D e f a u l t C l o s e O p e r a t i o n ( JFrame . EXIT ON CLOSE ) ;
140
141 // a d j u s t window s i z e t o t h e c o n t e n t .
142 t h i s . pack ( ) ;
143 positionAtCenterOfActiveScreen () ;
144
145
146 // s t a r t o t h e r t h r e a d s
147 d S S s e r v e r = new DSSServer ( 5 0 0 0 7 , t h i s ) ;
148 Thread d S S t h r e a d = new Thread ( d S S s e r v e r ) ;
149 dSSthread . s t a r t ( ) ;
B. Source Code 42
150 C o n t r o l l e r c o n t r o l l e r = new C o n t r o l l e r ( d S S s e r v e r ) ;
151 Thread c o n t r o l l e r T h r e a d = new Thread ( c o n t r o l l e r ) ;
152 controllerThread . start () ;
153 }
154
155 /∗ ∗
156 ∗ Creates a sample c h a r t .
157 ∗
158 ∗ @param d a t a s e t the dataset .
159 ∗
160 ∗ @return A sample c h a r t .
161 ∗/
162 p r i v a t e J F r e e C h a r t c r e a t e T i m e S e r i e s C h a r t ( J F r e e C h a r t c h a r t , double xRange , boolean
shapes ) {
163 f i n a l XYPlot p l o t = c h a r t . getXYPlot ( ) ;
164 // p l o t . s e t B a c k g r o u n d P a i n t ( C o l o r . l i g h t G r a y ) ;
165 p l o t . setDomainGridlinePaint ( Color . white ) ;
166 p l o t . setRangeGridlinePaint ( Color . white ) ;
167
168 f i n a l XYLineAndShapeRenderer r e n d e r e r = new XYLineAndShapeRenderer ( ) ;
169 r e n d e r e r . s e t B a s e L i n e s V i s i b l e ( true ) ;
170 // r e n d e r e r . s e t S e r i e s L i n e s V i s i b l e ( 0 , t r u e ) ;
171 renderer . setBaseShapesVisible ( shapes ) ;
172 // r e n d e r e r . s e t S e r i e s S h a p e s V i s i b l e ( 0 , s h a p e s ) ;
173 plot . setRenderer ( renderer ) ;
174
175 // c h a n g e t h e a u t o t i c k u n i t s e l e c t i o n t o i n t e g e r u n i t s o n l y . . .
176 f i n a l V a l u e A x i s rangeX = p l o t . getDomainAxis ( ) ;
177 // rangeX . s e t S t a n d a r d T i c k U n i t s ( NumberAxis . c r e a t e I n t e g e r T i c k U n i t s ( ) ) ;
178 // rangeX . s e t R a n g e ( 0 , 9 9 ) ;
179 rangeX . setAutoRange ( true ) ;
180 rangeX . s e t F i x e d A u t o R a n g e ( xRange ) ; // 5 m i n u t e s
181
182 f i n a l NumberAxis rangeY = ( NumberAxis ) p l o t . g e t R a n g e A x i s ( ) ;
183 rangeY . s e t S t a n d a r d T i c k U n i t s ( NumberAxis . c r e a t e S t a n d a r d T i c k U n i t s ( ) ) ;
184
185 // rangeY . s e t A u t o R a n g e ( t r u e ) ;
186
187 // c h a r t . s e t B a c k g r o u n d P a i n t ( C o l o r . w h i t e ) ;
188 return c h a r t ;
189 }
190
191 p r i v a t e void p o s i t i o n A t C e n t e r O f A c t i v e S c r e e n ( ) {
192 // c o m p u t e t h e c e n t e r o f t h e s c r e e n and move t h e window t h e r e
193 P o i n t mouse = M o u s e I n f o . g e t P o i n t e r I n f o ( ) . g e t L o c a t i o n ( ) ;
194 GraphicsDevice [ ] gds = GraphicsEnvironment . getLocalGraphicsEnvironment ( ) .
getScreenDevices () ;
195
196 // h a c k t o a l w a y s o p e n t h e window on my s e c o n d screen
197 // mouse . y = 1 2 0 0 ;
198 // mouse . x = 1 0 ;
199
200 int sc ree n = 0 ;
201 int h = 0 ;
202 int w = 0 ;
203 f o r ( i n t i =0; i <g d s . l e n g t h ; i ++){
204 DisplayMode m = g d s [ i ] . g e t D i s p l a y M o d e ( ) ;
205 i n t tempW = m. getWidth ( ) + w ;
206 i n t tempH = m. g e t H e i g h t ( ) + h ;
207 i f ( mouse . x < tempW && mouse . y < tempH ) {
208 screen = i ;
209 break ;
210 }
211 i f ( mouse . x >= tempW) {
212 w += m. getWidth ( ) ;
213 }
214 i f ( mouse . y >= tempH ) {
215 h += m. g e t H e i g h t ( ) ;
216 }
217 }
218 LOG. l o g ( ” S c r e e n ” + s c r e e n + ” w i d t h ” + w + ” h e i g h t ” + h , 10) ;
219
220 P o i n t p = new P o i n t ( ) ;
221 G r a p h i c s D e v i c e gd = g d s [ s c r e e n ] ;
222 i n t s c r e e n W i d t h = gd . g e t D i s p l a y M o d e ( ) . getWidth ( ) ;
223 i n t s c r e e n H e i g h t = gd . g e t D i s p l a y M o d e ( ) . g e t H e i g h t ( ) ;
224 int hight = this . getHeight ( ) ;
225 i n t w i d t h = t h i s . getWidth ( ) ;
226 double c e n t r e X = s c r e e n W i d t h / 2 + w ;
227 double c e n t r e Y = s c r e e n H e i g h t / 2 + h ;
228 p . s e t L o c a t i o n ( c e n t r e X−w i d t h / 2 , c e n t r e Y−h i g h t / 2 ) ;
229 this . setLocation (p) ;
230 }
231
B. Source Code 43
1 package ch . e t h z . baumachr . e n e r g y P r o v i d e r ;
2
3 import j a v a . l a n g . r e f l e c t . F i e l d ;
4 import j a v a . t e x t . SimpleDateFormat ;
5 import j a v a . u t i l . Date ;
6
7 public c l a s s L o g g e r {
8
9 public f i n a l i n t LEVEL = 1 ;
10
11 private final S t r i n g className ;
12
13 public L o g g e r ( ) {
14 className = t h i s . g e t C l a s s ( ) . getCanonicalName ( ) ;
15 }
16
17 public synchronized void l o g ( f i n a l S t r i n g s , i n t l e v e l ) {
18 i n t LOG LEVEL = LEVEL ;
19 S t r i n g callerName = ”” ;
20 S t r i n g methodName = ” ” ;
21 int lineNumber = 0 ;
22 try {
23 throw new E x c e p t i o n ( ) ;
24 }
25 catch ( E x c e p t i o n e ) {
26 StackTraceElement [ ] t r a c e = e . getStackTrace ( ) ;
27 f o r ( i n t i =0; i <t r a c e . l e n g t h ; i ++){
28 i f ( ! c l a s s N a m e . e q u a l s ( t r a c e [ i ] . getClassName ( ) ) ) {
29 S t r i n g f u l l C a l l e r N a m e = t r a c e [ i ] . getClassName ( ) ;
30 String [ ] callerClassNameArray = fullCallerName . s p l i t ( ” \\. ” ) ;
31 callerName = callerClassNameArray [ callerClassNameArray . length − 1 ] ;
32 methodName = t r a c e [ i ] . getMethodName ( ) ;
33 l i n e N u m b e r = t r a c e [ i ] . getLineNumber ( ) ;
34
35 try {
36 F i e l d f = C l a s s . forName ( f u l l C a l l e r N a m e ) . g e t F i e l d ( ”LOG LEVEL” ) ;
37 LOG LEVEL = f . g e t I n t ( n u l l ) ;
38 } catch ( E x c e p t i o n e 1 ) {}
39
40 break ;
41 }
42 }
43 }
44 i f ( l e v e l < LOG LEVEL) {
45 // [2011 −10 −27 0 9 : 2 0 : 3 6 ] [ p o l l : 4 4 1 ]
46 f i n a l SimpleDateFormat s d f = new SimpleDateFormat ( ” [ yyyy−MM−dd HH:mm: s s ] ” ) ;
47 f i n a l Date d = new Date ( ) ;
48 System . o u t . p r i n t ( s d f . f o r m a t ( d ) ) ;
49 System . o u t . p r i n t ( ” [ ” + c a l l e r N a m e + ” . ” + methodName + ” : ” + l i n e N u m b e r + ” ] ” ) ;
50 System . o u t . p r i n t l n ( s ) ;
51 }
52 }
53 }
1 package ch . e t h z . baumachr . e n e r g y P r o v i d e r ;
2
3 import java . text . SimpleDateFormat ;
4 import java . util . Calendar ;
5 import java . util . Comparator ;
6 import java . util . Date ;
7 import java . util . Locale ;
8 import java . util . TimeZone ;
9
10 public c l a s s SingletonUtil {
11
12 private s t a t i c SingletonUtil i n s t a n c e = null ;
13
14 public s t a t i c S i n g l e t o n U t i l i n s t a n c e ( ) {
15 i f ( i n s t a n c e == n u l l ) {
16 i n s t a n c e = new S i n g l e t o n U t i l ( ) ;
17 }
18 return i n s t a n c e ;
19 }
20
21 public f i n a l SimpleDateFormat gmtDateFormat ;
22 public L o g g e r LOG;
23 public f i n a l Comparator<DelayOnDevice> delayOnComparator ;
24
25 private SingletonUtil (){
B. Source Code 45
1 package ch . e t h z . baumachr . e n e r g y P r o v i d e r ;
2
3 import j a v a . u t i l . Date ;
4
5 public c l a s s I n t r a d a y M a r k e t D a t a P o i n t {
6 p r i v a t e Date d a t e ;
7 p r i v a t e double l a s t ;
8 p r i v a t e boolean l a s t S e t ;
9
10 public I n t r a d a y M a r k e t D a t a P o i n t ( ) {
11 lastSet = false ;
12 }
13
14 public Date g e t D a t e ( ) {
15 return d a t e ;
16 }
17 public void s e t H o u r ( Date d ) {
18 date = d ;
19 }
20
21 public boolean a v a i l a b l e ( ) {
22 return l a s t S e t ;
23 }
24
25 public void s e t L a s t ( double l ) {
26 this . l a s t = l ;
27 t h i s . l a s t S e t = true ;
28 }
29 public double g e t L a s t ( ) {
30 return l a s t ;
31 }
32 public boolean i s S a m e L a s t ( double l ) {
33 return l==l a s t ;
34 }
35 }
B.3 Simulation
1 import random
2
3 class Device ( o b j e c t ) :
4 def init ( self ) :
5 s e l f . on = random . c h o i c e ( [ True , F a l s e ] )
6 s e l f . c o n s u m p t i o n = random . r a n d i n t ( 0 , 2 0 0 0 )
7
8 def isOn ( s e l f , t i m e ) :
9 r = random . random ( )
10 if r > 0.9:
11 s e l f . on = not s e l f . on
B. Source Code 46
12 return s e l f . on
13
14 def s h u t O f f ( s e l f , time ) :
15 pass
16
17 def powerOn ( s e l f , time ) :
18 pass
19
20 def g et C on s um p ti o n ( s e l f , t i m e ) :
21 return s e l f . c o n s u m p t i o n i f s e l f . isOn ( t i m e ) else 0
22
23
24 class ShortOff ( Device ) :
25 def init ( self ) :
26 super ( ShortOff , s e l f ) . init ()
27 s e l f . on = True
28 s e l f . o f f T i m e = random . r a n d i n t ( 6 0 , 60 ∗ 60 ∗ 4 )
29 s e l f . s l o t L e n g t h = random . r a n d i n t ( s e l f . o f f T i m e , 60 ∗ 60 ∗ 2 4 )
30 s e l f . alreadyOffInSlot = 0
31 self . slotStart = 0
32 self . lastOffInSlot = 0
33
34 def isOn ( s e l f , t i m e ) :
35 i f not s e l f . on :
36 o f f S i n c e L a s t O f f = ( time − s e l f . l a s t O f f I n S l o t )
37 i f s e l f . offTime − ( s e l f . a l r e a d y O f f I n S l o t + o f f S i n c e L a s t O f f ) < 0 :
38 s e l f . a l r e a d y O f f I n S l o t += o f f S i n c e L a s t O f f
39 s e l f . on = True
40 return s e l f . on
41
42 def s h u t O f f ( s e l f , t i m e ) :
43 i f s e l f . on :
44 slotEnd = s e l f . s l o t S t a r t + s e l f . slotLength
45 i f slotEnd < time :
46 s e l f . alreadyOffInSlot = 0
47 s e l f . s l o t S t a r t = time
48 s e l f . l a s t O f f I n S l o t = time
49 s e l f . on = F a l s e
50 e l i f s e l f . a l r e a d y O f f I n S l o t < s e l f . offTime :
51 s e l f . l a s t O f f I n S l o t = time
52 s e l f . on = F a l s e
53
54 def s h u t O f f P o s s i b l e ( s e l f , t i m e ) :
55 slotEnd = s e l f . s l o t S t a r t + s e l f . slotLength
56 return s e l f . on and ( s l o t E n d < t i m e or s e l f . a l r e a d y O f f I n S l o t < s e l f . o f f T i m e )
57
58 def powerOn ( s e l f , t i m e ) :
59 i f not s e l f . on :
60 o f f S i n c e L a s t O f f = ( time − s e l f . l a s t O f f I n S l o t )
61 s e l f . on = True
62 s e l f . a l r e a d y O f f I n S l o t += o f f S i n c e L a s t O f f
63
64 c l a s s DelayOn ( D e v i c e ) :
65 def init ( self ) :
66 s u p e r ( DelayOn , s e l f ) . init ()
67 s e l f . s l o t S t a r t I n t e r v a l = 60 ∗ 60 ∗ 24
68 s e l f . s l o t S t a r t = random . r a n d i n t ( 0 , s e l f . s l o t S t a r t I n t e r v a l )
69 s e l f . onTime = random . r a n d i n t ( 6 0 , 60 ∗ 60 ∗ 4 )
70 s e l f . s l o t L e n g t h = random . r a n d i n t ( s e l f . onTime , 60 ∗ 60 ∗ 8 )
71
72 s e l f . a c t u a l S t a r t = s e l f . s l o t S t a r t + s e l f . s l o t L e n g t h − s e l f . onTime
73
74 def isOn ( s e l f , t i m e ) :
75 i f t i m e < s e l f . s l o t S t a r t + s e l f . s l o t L e n g t h − s e l f . onTime :
76 return ( s e l f . a c t u a l S t a r t <= t i m e ) and ( t i m e < s e l f . a c t u a l S t a r t + s e l f . onTime )
77 else :
78 s e l f . a c t u a l S t a r t = time
79 s e l f . s l o t S t a r t += s e l f . s l o t L e n g t h + random . r a n d i n t ( 0 , s e l f . s l o t S t a r t I n t e r v a l )
80 return True
81
82 def powerOn ( s e l f , t i m e ) :
83 i f s e l f . powerOnPossible ( time ) :
84 s e l f . a c t u a l S t a r t = time
85 s e l f . s l o t S t a r t += s e l f . s l o t L e n g t h + random . r a n d i n t ( 0 , self . slotStartInterval )
86
87 def p o w e r O n P o s s i b l e ( s e l f , t i m e ) :
88 return ( s e l f . s l o t S t a r t <= t i m e ) and ( t i m e <= s e l f . s l o t S t a r t + s e l f . s l o t L e n g t h −
s e l f . onTime )
89
90 def s c h e d u l a b l e ( s e l f , t i m e ) :
91 return t i m e > s e l f . s l o t S t a r t
92
93 ””” d = DelayOn ( )
94 p r i n t d . s l o t S t a r t , d . s l o t L e n g t h , d . onTime
B. Source Code 47
95
96
97 p r e v i o u s = −1
98 f o r t i n x r a n g e ( 0 , 60 ∗ 60 ∗ 24 ∗ 7 , 1 0 ) :
99 temp = d . g e t C o n s u m p t i o n ( t )
100 d . powerOn ( t )
101 i f p r e v i o u s != temp :
102 p r i n t t , d . getConsumption ( t )
103 p r e v i o u s = temp ”””
1 #! / u s r / b i n / p y t h o n
2
3 import random
4 from m u l t i p r o c e s s i n g import P r o c e s s , Queue
5 import s y s
6 from d e v i c e import D e v i c e , S h o r t O f f , DelayOn
7
8
9 numberOfDevices = 2 0 0 0 0 0
10
11 f a c t o r = 1730
12 t i m e s t e p = 60
13 points = [
14 ( 0 ∗ 60 ∗ 6 0 , 49669.6409090909 ∗ factor ) ,
15 ( 1 ∗ 60 ∗ 6 0 , 48519.3590909091 ∗ factor ) ,
16 ( 2 ∗ 60 ∗ 6 0 , 47920.1045454546 ∗ factor ) ,
17 ( 3 ∗ 60 ∗ 6 0 , 47784.0590909091 ∗ factor ) ,
18 ( 4 ∗ 60 ∗ 6 0 , 48360.1181818182 ∗ factor ) ,
19 ( 5 ∗ 60 ∗ 6 0 , 50001.2045454546 ∗ factor ) ,
20 ( 6 ∗ 60 ∗ 6 0 , 54132.3454545455 ∗ factor ) ,
21 ( 7 ∗ 60 ∗ 6 0 , 59275.2136363636 ∗ factor ) ,
22 ( 8 ∗ 60 ∗ 6 0 , 61325.8181818182 ∗ factor ) ,
23 ( 9 ∗ 60 ∗ 6 0 , 62002.9818181818 ∗ factor ) ,
24 ( 1 0 ∗ 60 ∗ 6 0 , 63282.1454545454 ∗ factor ) ,
25 ( 1 1 ∗ 60 ∗ 6 0 , 64865.1090909091 ∗ factor ) ,
26 ( 1 2 ∗ 60 ∗ 6 0 , 64989.1181818182 ∗ factor ) ,
27 ( 1 3 ∗ 60 ∗ 6 0 , 64551.2727272727 ∗ factor ) ,
28 ( 1 4 ∗ 60 ∗ 6 0 , 63373.5590909091 ∗ factor ) ,
29 ( 1 5 ∗ 60 ∗ 6 0 , 62300.2000000000 ∗ factor ) ,
30 ( 1 6 ∗ 60 ∗ 6 0 , 62997.7681818182 ∗ factor ) ,
31 ( 1 7 ∗ 60 ∗ 6 0 , 65050.3954545455 ∗ factor ) ,
32 ( 1 8 ∗ 60 ∗ 6 0 , 65487.3136363636 ∗ factor ) ,
33 ( 1 9 ∗ 60 ∗ 6 0 , 64111.5318181818 ∗ factor ) ,
34 ( 2 0 ∗ 60 ∗ 6 0 , 61880.1090909091 ∗ factor ) ,
35 ( 2 1 ∗ 60 ∗ 6 0 , 58534.3909090909 ∗ factor ) ,
36 ( 2 2 ∗ 60 ∗ 6 0 , 56449.8636363636 ∗ factor ) ,
37 ( 2 3 ∗ 60 ∗ 6 0 , 52865.5363636364 ∗ factor ) ,
38 ( 2 4 ∗ 60 ∗ 6 0 , 49669.6409090909 ∗ factor )
39 ]
40
41 def g e t A v a i l a b i l i t y ( t ) :
42 d a i l y T i m e = t % ( 2 4 ∗ 60 ∗ 6 0 )
43 f o r ( time , v a l u e ) i n p o i n t s :
44 i f time > dailyTime :
45 return o l d V a l u e + ( ( v a l u e − o l d V a l u e ) ∗ ( d a i l y T i m e − oldTime ) / ( t i m e − oldTime
) )
46 oldValue = value
47 oldTime = t i m e
48
49
50
51 def main ( ) :
52 devices = [ ]
53 shortOff = [ ]
54 nowOff = {}
55 delayOn = [ ]
56 f o r j i n x r a n g e ( 0 , numberOfDevices ) :
57 rand = random . c h o i c e ( [ 1 , 2 , 3 ] )
58 i f rand == 1 :
59 s h o r t O f f . append ( S h o r t O f f ( ) )
60 e l i f rand == 2 :
61 delayOn . append ( DelayOn ( ) )
62 e l i f rand == 3 :
63 d e v i c e s . append ( D e v i c e ( ) )
64
65 s y s . s t d e r r . w r i t e ( ”Number o f delayOn : ”+s t r ( l e n ( delayOn ) )+” \n” )
66 sys . stderr . flush ()
67
68 c o n s t a n t C o n s u m p t i o n = l e n ( s h o r t O f f ) ∗ 1000 + l e n ( d e v i c e s ) ∗ 500
69 s y s . s t d e r r . w r i t e ( ” C o n s t a n t c o n s u m p t i o n ”+s t r ( c o n s t a n t C o n s u m p t i o n ) + ” \n” )
B. Source Code 48
154
155 d . powerOn ( s t a r t A t )
156 f o r duringOn i n x r a n g e ( s t a r t A t , s t a r t A t + d . onTime , timestep ) :
157 i f duringOn i n a l r e a d y S c h e d u l e d :
158 a l r e a d y S c h e d u l e d [ duringOn ] += d . c o n s u m p t i o n
159 else :
160 a l r e a d y S c h e d u l e d [ duringOn ] = d . c o n s u m p t i o n
161
162 sys . stderr . write ( ” Scheduling ” + s t r ( c o u n t e r ) + ” d e v i c e s \n” )
163 sys . stderr . flush ()
164
165
166 f o r t i n x r a n g e ( 6 0 ∗ 60 ∗ 24 ∗ 7 , 2 ∗ 60 ∗ 60 ∗ 24 ∗ 7 , t i m e s t e p ) :
167 available = getAvailability ( t )
168 consumption = 0
169 for d in d e v i c e s :
170 c o n s u m p t i o n += d . g e tC o ns u mp t i on ( t )
171 for d in s h o r t O f f :
172 c o n s u m p t i o n += d . g e tC o ns u mp t i on ( t )
173 f o r d i n delayOn :
174 c o n s u m p t i o n += d . g e tC o ns u mp t i on ( t )
175 p r i n t t , a v a i l a b l e , consumption , a v a i l a b l e −c o n s u m p t i o n
176
177 nowOff = {}
178 f o r t i n x r a n g e ( 2 ∗ 60 ∗ 60 ∗ 24 ∗ 7 , 3 ∗ 60 ∗ 60 ∗ 24 ∗ 7 , timestep ) :
179 available = getAvailability ( t )
180 consumption = 0
181 for d in d e v i c e s :
182 c o n s u m p t i o n += d . g e tC o ns u mp t i on ( t )
183 for d in s h o r t O f f :
184 c o n s u m p t i o n += d . g e tC o ns u mp t i on ( t )
185 f o r d i n delayOn :
186 c o n s u m p t i o n += d . g e tC o ns u mp t i on ( t )
187 delta = a v a i l a b l e −c o n s u m p t i o n
188 p r i n t t , a v a i l a b l e , consumption , d e l t a
189
190 powerOnNumber = 0
191 shutOffNumber = 0
192 i f consumption > a v a i l a b l e :
193 d e l t a = consumption − a v a i l a b l e
194 shutOffNumber = i n t ( d e l t a / 1 0 0 0 )
195 e l i f consumption < a v a i l a b l e :
196 d e l t a = a v a i l a b l e − consumption
197 powerOnNumber = i n t ( d e l t a / 1 0 0 0 )
198
199
200 i = 0
201 while i < l e n ( s h o r t O f f ) and shutOffNumber > 0 :
202 i f shortOff [ i ] . shutOffPossible ( t ) :
203 shortOff [ i ] . shutOff ( t )
204 shutOffNumber −= 1
205 i f not i i n nowOff :
206 nowOff [ i ] = True
207 i += 1
208
209 i = 0
210 lenNowOff = l e n ( nowOff )
211 while i < lenNowOff and powerOnNumber > 0 :
212 ( key , v a l u e ) = nowOff . popitem ( )
213 i f not s h o r t O f f [ key ] . isOn ( t ) :
214 s h o r t O f f [ key ] . powerOn ( t )
215 powerOnNumber −= 1
216 i += 1
217 i = 0
218 while i < l e n ( delayOn ) and powerOnNumber > 0 :
219 i f delayOn [ i ] . p o w e r O n P o s s i b l e ( t ) :
220 delayOn [ i ] . powerOn ( t )
221 powerOnNumber −= 1
222 i += 1
223
224
225
226
227
228
229
230
231
232
233 main ( )
1 #! / u s r / b i n / p y t h o n
2
3 import s y s
4
5 f = open ( s y s . a r g v [ 1 ] , ” r ” )
6 integral = 0
7 for l i n e in f :
8 l = line . s p l i t ()
9 time = l [ 0 ]
10 available = float ( l [1])
11 consumption = f l o a t ( l [ 2 ] )
12 d e l t a = abs ( a v a i l a b l e − consumption )
13 i n t e g r a l += d e l t a ∗ ( 6 . 0 / 3 6 0 . 0 )
14 p r i n t time , a v a i l a b l e , consumption , i n t e g r a l