From 677641bbfa3872176c3d6d5cff621a5e3b27b324 Mon Sep 17 00:00:00 2001
From: rschoene <rene.schoene@tu-dresden.de>
Date: Sun, 20 Jun 2021 12:18:30 +0200
Subject: [PATCH] preparing for master/main update

- also add version to eraser.starter
---
 .gitlab-ci.yml                                |  2 +-
 README.md                                     | 11 +------
 eraser.starter/build.gradle                   | 25 +++++++++++++++
 .../inf/st/eraser/starter/EraserStarter.java  | 31 +++++++++++++++----
 .../src/main/resources/eraser.properties      |  2 ++
 pages/.gitignore                              |  1 +
 pages/custom_theme/footer.html                |  4 +--
 pages/docs/DSL.md                             |  6 ++--
 pages/docs/MachineLearning.md                 |  2 +-
 pages/docs/Model-description.md               | 27 ++++++++++------
 pages/docs/index.md                           |  2 +-
 pages/main.py                                 | 25 +++++++++++++++
 pages/mkdocs.yml                              |  7 +++--
 13 files changed, 110 insertions(+), 35 deletions(-)
 create mode 100644 eraser.starter/src/main/resources/eraser.properties
 create mode 100644 pages/main.py

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 1fd92e48..8fbc29ce 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -119,7 +119,7 @@ pages:
     - cd pages && mkdocs build
   only:
     - dev
-    - master
+    - main
   artifacts:
     paths:
       - "public"
diff --git a/README.md b/README.md
index be3f3b86..af4d2c9d 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@
 There are the following subprojects in this repository:
 
 - Base
-	- **eraser-base**: The core part of the framework containing the [grammar](/../../blob/master/eraser-base/src/main/jastadd/main.relast), various attributes, the [parser](/../../blob/master/eraser-base/src/main/jastadd/eraser.parser) for model specification files, and Java classes for the [openHAB communication](/../../tree/master/eraser-base/src/main/java/de/tudresden/inf/st/eraser/openhab2) via [MQTT](/../../blob/master/eraser-base/src/main/java/de/tudresden/inf/st/eraser/openhab2/mqtt/MQTTUpdater.java)
+	- **eraser-base**: The core part of the framework containing the [grammar](/../../blob/main/eraser-base/src/main/jastadd/main.relast), various attributes, the [parser](/../../blob/main/eraser-base/src/main/jastadd/eraser.parser) for model specification files, and Java classes for the [openHAB communication](/../../tree/main/eraser-base/src/main/java/de/tudresden/inf/st/eraser/openhab2) via [MQTT](/../../blob/main/eraser-base/src/main/java/de/tudresden/inf/st/eraser/openhab2/mqtt/MQTTUpdater.java)
 - Utility
 	- **commons.color**: Utilities for converting color spaces (XYZ, RGB, HSB)
 	- **eraser.rest** and **eraser.spark**: REST-API to communicate with the framework
@@ -25,15 +25,6 @@ There are the following subprojects in this repository:
 
 This project uses Gradle as the build tool. For detailed information, see [setup guidelines](/../../wikis/setup)
 
-## Running the demo
-
-There is a demo project, as explained [above](#overview) to showcase the framework.
-To start it, run `./gradlew :skywriter-hue-integration:run`
-
-This demo is intended to run with a pre-configured openHAB instance and has some hard-coded settings.
-It will first try to connect to an MQTT broker (with a hard-coded IP) to listen on changes of item states.
-There is one rule implemented, namely to listen on changes of the item `skywriter_xyz` expecting MQTT messages of the form `XVALUE,YVALUE,ZVALUE`, and to change to state of another item `iris1_item` representing the HSB value of a Hue Iris.
-
 ## Trivia
 
 The name *Eraser* is a small pun on the term *eRACR*, which is an extension of *RACR* for event recognition. It was chosen to ease the search for a good repository image as it is based on a [film](https://en.wikipedia.org/wiki/Eraser_(film)).
diff --git a/eraser.starter/build.gradle b/eraser.starter/build.gradle
index 739e399f..26a03642 100644
--- a/eraser.starter/build.gradle
+++ b/eraser.starter/build.gradle
@@ -19,6 +19,31 @@ dependencies {
 
 }
 
+def versionFile = 'src/main/resources/eraser.properties'
+def oldProps = new Properties()
+
+try {
+    file(versionFile).withInputStream { stream -> oldProps.load(stream) }
+    version = oldProps['version']
+} catch (e) {
+    // this happens, if either the properties file is not present, or cannot be read from
+    throw new GradleException("File ${versionFile} not found or unreadable. Aborting.", e)
+}
+
+task printVersion() {
+    doLast {
+        println(version)
+    }
+}
+
+task newVersion() {
+    doFirst {
+        def props = new Properties()
+        props['version'] = value
+        props.store(file(versionFile).newWriter(), null)
+    }
+}
+
 application.mainClass = 'de.tudresden.inf.st.eraser.starter.EraserStarter'
 
 import io.github.httpbuilderng.http.HttpTask
diff --git a/eraser.starter/src/main/java/de/tudresden/inf/st/eraser/starter/EraserStarter.java b/eraser.starter/src/main/java/de/tudresden/inf/st/eraser/starter/EraserStarter.java
index ce6e008b..83815a11 100644
--- a/eraser.starter/src/main/java/de/tudresden/inf/st/eraser/starter/EraserStarter.java
+++ b/eraser.starter/src/main/java/de/tudresden/inf/st/eraser/starter/EraserStarter.java
@@ -24,8 +24,11 @@ import org.apache.logging.log4j.Logger;
 
 import java.io.File;
 import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
 import java.net.MalformedURLException;
 import java.net.URL;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.locks.Condition;
 import java.util.concurrent.locks.Lock;
@@ -52,8 +55,12 @@ public class EraserStarter {
 
   private static final Logger logger = LogManager.getLogger(EraserStarter.class);
 
-  @SuppressWarnings("ResultOfMethodCallIgnored")
   public static void main(String[] args) {
+    EraserStarter starter = new EraserStarter();
+    starter.run(args);
+  }
+
+  public void run(String[] args) {
     ArgumentParser parser = ArgumentParsers.newFor("eraser").build()
         .defaultHelp(true)
         .description("Starts the knowledge-base of OpenLicht");
@@ -79,7 +86,7 @@ public class EraserStarter {
       System.exit(1);
       return;
     }
-    logger.info("Starting ERASER");
+    logger.info("Starting ERASER " + readVersion());
     boolean startRest = settings.rest.use;
 
     Root root;
@@ -102,7 +109,7 @@ public class EraserStarter {
       default:
         try {
           root = ParserUtils.load(settings.load.realURL());
-          model = root.getSmartHomeEntityModel();
+          root.getSmartHomeEntityModel();
         } catch (IOException | Parser.Exception e) {
           logger.error("Problems parsing the given file {}", settings.load.file);
           logger.catching(e);
@@ -194,6 +201,7 @@ public class EraserStarter {
       logger.info("No REST server this time");
       System.out.println("Hit [Enter] to exit");
       try {
+        //noinspection ResultOfMethodCallIgnored
         System.in.read();
       } catch (IOException e) {
         e.printStackTrace();
@@ -222,7 +230,7 @@ public class EraserStarter {
     logger.info("I'm done here.");
   }
 
-  private static MachineLearningHandlerFactory createFactory(MachineLearningHandlerFactory.MachineLearningHandlerFactoryTarget target, Setting.MLContainer config, Root root) {
+  private MachineLearningHandlerFactory createFactory(MachineLearningHandlerFactory.MachineLearningHandlerFactoryTarget target, Setting.MLContainer config, Root root) {
     MachineLearningHandlerFactory factory;
     String niceTargetName = target.toString().toLowerCase().replace("_", " ");
     if (config.dummy || config.factory == null) {
@@ -232,10 +240,11 @@ public class EraserStarter {
       try {
         Class<? extends MachineLearningHandlerFactory> clazz = Class.forName(config.factory)
             .asSubclass(MachineLearningHandlerFactory.class);
-        factory = clazz.newInstance();
+        factory = clazz.getDeclaredConstructor().newInstance();
         factory.setKnowledgeBaseRoot(root);
         factory.initializeFor(target, config.realURL());
-      } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | IOException e) {
+      } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | IOException |
+          NoSuchMethodException | InvocationTargetException e) {
         logger.error("Could not instantiate machine learning factory for {} with class '{}'.",
             niceTargetName, config);
         logger.catching(e);
@@ -250,4 +259,14 @@ public class EraserStarter {
     }
     return factory;
   }
+
+  private String readVersion() {
+    try {
+      ResourceBundle resources = ResourceBundle.getBundle("eraser");
+      return resources.getString("version");
+    } catch (MissingResourceException e) {
+      return "version ?";
+    }
+  }
+
 }
diff --git a/eraser.starter/src/main/resources/eraser.properties b/eraser.starter/src/main/resources/eraser.properties
new file mode 100644
index 00000000..8066d340
--- /dev/null
+++ b/eraser.starter/src/main/resources/eraser.properties
@@ -0,0 +1,2 @@
+#Sun Jun 20 11:43:25 CEST 2021
+version=1.0.0
diff --git a/pages/.gitignore b/pages/.gitignore
index a95071c4..14338f39 100644
--- a/pages/.gitignore
+++ b/pages/.gitignore
@@ -1 +1,2 @@
 /docs/ragdoc/
+__pycache__
diff --git a/pages/custom_theme/footer.html b/pages/custom_theme/footer.html
index e76f0a2b..2d6c1646 100644
--- a/pages/custom_theme/footer.html
+++ b/pages/custom_theme/footer.html
@@ -4,8 +4,8 @@
 {% endif %}
 <hr>
 Built with <a href="https://www.mkdocs.org/">MkDocs</a> using a <a href="https://github.com/snide/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>.
-{% if page and page.meta and page.meta.revision_date %}
-<small><br><i>Last updated {{ page.meta.revision_date.strftime('%B %d, %Y at %H:%M') }}</i></small>
+{% if page and page.meta and page.meta.git_revision_date_localized %}
+<small><br><i>Last updated {{ page.meta.git_revision_date_localized }}</i></small>
 {% endif %}
 </p>
 {% endblock %}
diff --git a/pages/docs/DSL.md b/pages/docs/DSL.md
index c58ec900..7ac5c9f9 100644
--- a/pages/docs/DSL.md
+++ b/pages/docs/DSL.md
@@ -1,11 +1,11 @@
 # The eraser-DSL
 
-Find a general description in the [Model description](Model-description) page, and the parser ([dev](https://git-st.inf.tu-dresden.de/OpenLicht/eraser/blob/dev/eraser-base/src/main/jastadd/eraser.parser), [master](https://git-st.inf.tu-dresden.de/OpenLicht/eraser/blob/master/eraser-base/src/main/jastadd/eraser.parser)) and printing ([dev](https://git-st.inf.tu-dresden.de/OpenLicht/eraser/blob/dev/eraser-base/src/main/jastadd/Printing.jrag), [master](https://git-st.inf.tu-dresden.de/OpenLicht/eraser/blob/master/eraser-base/src/main/jastadd/Printing.jrag)).
+Find a general description in the [Model description](Model-description) page, and the parser ([dev](https://git-st.inf.tu-dresden.de/OpenLicht/eraser/blob/dev/eraser-base/src/main/jastadd/eraser.parser), [main](https://git-st.inf.tu-dresden.de/OpenLicht/eraser/blob/main/eraser-base/src/main/jastadd/eraser.parser)) and printing ([dev](https://git-st.inf.tu-dresden.de/OpenLicht/eraser/blob/dev/eraser-base/src/main/jastadd/Printing.jrag), [main](https://git-st.inf.tu-dresden.de/OpenLicht/eraser/blob/main/eraser-base/src/main/jastadd/Printing.jrag)).
 
 The DSL is line-based, so on each line, one model element will be defined.
 All shown specifications for one element are optional and can be reordered, but at least `id` must be present to identify the element.
 References to other elements are done by using their IDs as strings, and can be forward references.
-The following elements can be described (in the master branch if not otherwise noted):
+The following elements can be described (in the main branch if not otherwise noted):
 
 ## ChannelType
 
@@ -15,7 +15,7 @@ ChannelType: id="" label="" description="" itemType="" category="" readyOnly;
 
 - The item type has to be one of the [item names defined for Eclipse Smart Home](https://www.eclipse.org/smarthome/documentation/concepts/items.html)
 - The category can either be one of the [categories defined for Eclipse Smart Home](https://www.eclipse.org/smarthome/documentation/concepts/categories.html#channel-categories), or a custom one.
-- Both item type and category are defined as enums ([dev](https://git-st.inf.tu-dresden.de/OpenLicht/eraser/blob/dev/eraser-base/src/main/jastadd/enums.jadd), [master](https://git-st.inf.tu-dresden.de/OpenLicht/eraser/blob/master/eraser-base/src/main/jastadd/enums.jadd))
+- Both item type and category are defined as enums ([dev](https://git-st.inf.tu-dresden.de/OpenLicht/eraser/blob/dev/eraser-base/src/main/jastadd/enums.jadd), [main](https://git-st.inf.tu-dresden.de/OpenLicht/eraser/blob/main/eraser-base/src/main/jastadd/enums.jadd))
 - The flag `readOnly` is currently without any effect
 
 ## Channel
diff --git a/pages/docs/MachineLearning.md b/pages/docs/MachineLearning.md
index de5ab065..ff7f416c 100644
--- a/pages/docs/MachineLearning.md
+++ b/pages/docs/MachineLearning.md
@@ -1,6 +1,6 @@
 # Machine Learning Basics
 
-The relevant parts of the grammar ([dev](https://git-st.inf.tu-dresden.de/OpenLicht/eraser/blob/dev/eraser-base/src/main/jastadd/main.relast) | [master](https://git-st.inf.tu-dresden.de/OpenLicht/eraser/blob/dev/eraser-base/src/main/jastadd/main.relast)) are the following (updated on Feburary, 11th 2019):
+The relevant parts of the grammar ([dev](https://git-st.inf.tu-dresden.de/OpenLicht/eraser/blob/dev/eraser-base/src/main/jastadd/main.relast) | [main](https://git-st.inf.tu-dresden.de/OpenLicht/eraser/blob/dev/eraser-base/src/main/jastadd/main.relast)) are the following (updated on Feburary, 11th 2019):
 
 ## General information machine learning
 
diff --git a/pages/docs/Model-description.md b/pages/docs/Model-description.md
index f3edf840..58d86723 100644
--- a/pages/docs/Model-description.md
+++ b/pages/docs/Model-description.md
@@ -1,14 +1,14 @@
 # Model description
 
-The latest version of the model: [master](https://git-st.inf.tu-dresden.de/rschoene/eraser/blob/master/eraser-base/src/main/jastadd/main.relast) | [dev](https://git-st.inf.tu-dresden.de/rschoene/eraser/blob/dev/eraser-base/src/main/jastadd/main.relast)
+The latest version of the model: [main](https://git-st.inf.tu-dresden.de/rschoene/eraser/blob/main/eraser-base/src/main/jastadd/main.relast) | [dev](https://git-st.inf.tu-dresden.de/rschoene/eraser/blob/dev/eraser-base/src/main/jastadd/main.relast)
 
 Below, all parts of the model are described in more detail. Each part resides in a separate grammar file.
 
 ## Main
 
-Root ::= OpenHAB2Model User* MqttRoot InfluxRoot MachineLearningRoot Rule* Location* ;
+`Root ::= SmartHomeEntityModel User* MqttRoot InfluxRoot MachineLearningRoot Rule* Location* ;`
 
-- `OpenHAB2Model`: Content from openHAB
+- `SmartHomeEntityModel`: Smart home entities
 - `User*`: Users in the system (work in progress)
 - `MqttRoot`: Everything needed for MQTT (communication with openHAB)
 - `InfluxRoot`: Everything needed for Influx (time series database for item state history)
@@ -16,16 +16,16 @@ Root ::= OpenHAB2Model User* MqttRoot InfluxRoot MachineLearningRoot Rule* Locat
 - `Rule*`: Self-made ECA rules
 - `Location*`: Locations associated with users, activities, preferences (work in progress)
 
-## openHAB
+## Smart Home Entity Model
 
-> OpenHAB2Model ::= Thing* Group* ThingType* ChannelType* ChannelCategory* ItemCategory* /ActivityItem:Item/
+`SmartHomeEntityModel ::= Thing* Group* ThingType* Parameter* ChannelType* Channel* ItemCategory* /ActivityItem:Item/ FrequencySetting* ;`
 
 The structure is mostly extracted from openHAB. There are some abstract superclasses to share common token, such as `ID`, `label` or `description`. Some differences to openHAB include:
 
-- Links are not modelled explicitely, but instead the items are directly referenced within channels
+- Links are not modelled explicitly, but instead the items are directly referenced within channels
 - Item type was reified instead of a token describing the type. This has the advantage, that the state can be used in a more type-safe way. On the downside, more code is required in some instances, such as for item history, and there is no easy `getState` method.
 
-Explainations for the other types:
+Explanations for the other types:
 
 - **Things** represent physical entities, such as a Hue lamp, a complex (or simple) sensor, a monitor, a webservice. They are typed and described by ThingTypes.
 - **ThingTypes** describe the blueprint for a Thing, like a class does for objects in OO languages. They also have **ChannelTypes** describing possible capabilities.
@@ -46,13 +46,22 @@ Basically, here are just some tokens containing information for connection to In
 
 Handling of machine learning models currently undergoes a change.
 
-There is a distinction between internal and external models, both implement a encoder interface to get data into those models, and decoder interface to extract data from the models.
+There is a distinction between internal and external models, both implement an encoder interface to get data into those models, and decoder interface to extract data from the models.
 There are two internal models which are supported: decision trees and neural networks.
 
-Decision tree are modelled straight-forward, there are inner nodes and leafs. Inner nodes reference an item and check a certain condition for this item to decide whether to follow the left or the right path of the inner node. The classification is equal to the leaf node at the end of the path.
+Decision tree are modelled straight-forward, there are inner nodes and leaves. Inner nodes reference an item and check a certain condition for this item to decide whether to follow the left or the right path of the inner node. The classification is equal to the leaf node at the end of the path.
 
 Neural networks are also straight-forward, but probably inefficient for bigger networks in the current implementation. Every neuron is a non-terminal which has ingoing and outgoing connections (using bidirectional relations), input neurons reference an item and propagate its state, hidden and output neurons have an activation function, bias neurons always return a constant value. The output layer contains all output neurons and has a combinator function to calculate the classification result.
 
 ## Rules
 
 Simple ECA rules can be modelled. A rule has a list of conditions and a list of actions. An event can be triggered by some items (via their ItemObserver), i.e., whenever an item changes its state to a different value. Conditions use a logical expression, which can contain simple mathematical expressions, comparisons, and simple logical operations. Actions are organized currently by their purpose, but are wll be simplified to reference only affected items and a number expression to calculate the new value for those items.
+
+### StateSyncGroup
+
+#### What does it do?
+Item states can be synchronized through StateSyncGroups. Once an item belongs to such a group, all of its state changes will be applied and then sent to other items in that group.
+The behavior of the other items in the group following the order to change the state is up to the item type. This is how state transfers between different item types can be managed. For example if a ColorItem (currently at `1%` brightness) and a SwitchItem (currently at value `false`) are in a StateSyncGroup and the SwitchItem is changing to `true` then the ColorItem won't change to 100%. Instead, it keeps its old value (`1%`).
+
+#### How does it work?
+The StateSyncGroup as an entity does only exist while parsing. After resolving all references, it is rewritten (using JastAdd rewrites). As a result, an ECA rule emerges that has conditions and actions whose functionality correspond to the explained behavior in the previous paragraph.
diff --git a/pages/docs/index.md b/pages/docs/index.md
index a341cbda..afb6bbd8 100644
--- a/pages/docs/index.md
+++ b/pages/docs/index.md
@@ -1,6 +1,6 @@
 # Documentation of Eraser
 
-First, setup eraser following the README in the main repository: [dev](https://git-st.inf.tu-dresden.de/OpenLicht/eraser/blob/dev/README.md) | [master](https://git-st.inf.tu-dresden.de/OpenLicht/eraser/blob/master/README.md)
+First, setup eraser following the README in the main repository: [dev](https://git-st.inf.tu-dresden.de/OpenLicht/eraser/blob/dev/README.md) | [main](https://git-st.inf.tu-dresden.de/OpenLicht/eraser/blob/main/README.md)
 To configure the system, read the [configuration page](config).
 
 For an overview of the model, check out the [Model description](Model-description).
diff --git a/pages/main.py b/pages/main.py
new file mode 100644
index 00000000..c3da0174
--- /dev/null
+++ b/pages/main.py
@@ -0,0 +1,25 @@
+eraserVersionFileName = '../eraser.starter/src/main/resources/eraser.properties'
+
+
+def get_version():
+    with open(eraserVersionFileName) as eraserVersionFile:
+        versionFileContent = eraserVersionFile.read()
+    return versionFileContent[versionFileContent.rindex('version=') + 8:].strip()
+
+
+def define_env(env):
+    """
+    This is the hook for defining variables, macros and filters
+
+    - variables: the dictionary that contains the environment variables
+    - macro: a decorator function, to declare a macro.
+    """
+    env.conf['site_name'] = 'Documentation of Eraser ' + get_version()
+
+    @env.macro
+    def eraser_version():
+        return get_version()
+
+
+if __name__ == '__main__':
+    print(get_version())
diff --git a/pages/mkdocs.yml b/pages/mkdocs.yml
index e4410b59..e8b9ac7f 100644
--- a/pages/mkdocs.yml
+++ b/pages/mkdocs.yml
@@ -17,8 +17,11 @@ theme:
   custom_dir: custom_theme/
 plugins:
   - search
-  - git-revision-date:
-      as_datetime: True
+  - git-revision-date-localized:
+      type: datetime
+      timezone: Europe/Berlin
+      locale: en
+      fallback_to_build_date: True
   - macros
 repo_url: https://git-st.inf.tu-dresden.de/OpenLicht/eraser
 site_dir: ../public
-- 
GitLab