From 8564a6b56fdaceae85b91e5ba6a6430a72deee34 Mon Sep 17 00:00:00 2001
From: Alexander Entinger <cto@lxrobotics.com>
Date: Tue, 19 Jul 2022 10:25:34 +0200
Subject: [PATCH 1/2] Thermostat example demonstrate advantages of source/sink
 vs shared in certain applications.

---
 .../Thermostat/SharedVariables.h              |  0
 .../TemperatureControl_LivingRoom.inot        | 59 +++++++++++++++++++
 .../TemperatureControl_SleepingRoom.inot      | 59 +++++++++++++++++++
 .../Thermostat/TemperatureSensor.inot         | 19 ++++++
 .../Thermostat/TemperatureSensorReporter.inot | 19 ++++++
 .../Thermostat/Thermostat.ino                 | 37 ++++++++++++
 6 files changed, 193 insertions(+)
 create mode 100644 examples/Threading_Basics/Thermostat/SharedVariables.h
 create mode 100644 examples/Threading_Basics/Thermostat/TemperatureControl_LivingRoom.inot
 create mode 100644 examples/Threading_Basics/Thermostat/TemperatureControl_SleepingRoom.inot
 create mode 100644 examples/Threading_Basics/Thermostat/TemperatureSensor.inot
 create mode 100644 examples/Threading_Basics/Thermostat/TemperatureSensorReporter.inot
 create mode 100644 examples/Threading_Basics/Thermostat/Thermostat.ino

diff --git a/examples/Threading_Basics/Thermostat/SharedVariables.h b/examples/Threading_Basics/Thermostat/SharedVariables.h
new file mode 100644
index 0000000..e69de29
diff --git a/examples/Threading_Basics/Thermostat/TemperatureControl_LivingRoom.inot b/examples/Threading_Basics/Thermostat/TemperatureControl_LivingRoom.inot
new file mode 100644
index 0000000..f771ce9
--- /dev/null
+++ b/examples/Threading_Basics/Thermostat/TemperatureControl_LivingRoom.inot
@@ -0,0 +1,59 @@
+/* Define a data sink named 'temperature' of type 'float'. */
+SINK(temperature, float, 10);
+
+static String living_room_message_prefix(String const & /* msg */)
+{
+  return String("[Living Room] ");
+}
+
+void setup()
+{
+  Serial.begin(9600);
+  Serial.prefix(living_room_message_prefix);
+  while (!Serial) { }
+}
+
+bool is_heating_on = false;
+
+void loop()
+{
+  float current_temperature_deg = temperature.pop();
+
+  /* Check if the temperature reported by the thermostat is above
+   * or below 22.0 °C. If the temperature is below 22.0 °C, turn
+   * on the heating.
+   */
+  bool turn_heating_on  = false,
+       turn_heating_off = false;
+
+  if (current_temperature_deg < 22.0f)
+    turn_heating_on = true;
+  else
+    turn_heating_off = true;
+
+  /* Only perform a simulated turning on of
+   * the heating if the heating is currently
+   * turned off.
+   */
+  if (is_heating_on && turn_heating_off)
+  {
+    is_heating_on = false;
+  
+    Serial.block();
+    Serial.print("Heating OFF (");
+    Serial.print(current_temperature_deg);
+    Serial.println(" °C)");
+    Serial.unblock();
+  }
+
+  if (!is_heating_on && turn_heating_on)
+  {
+    is_heating_on = true;
+    
+    Serial.block();
+    Serial.print("Heating ON (");
+    Serial.print(current_temperature_deg);
+    Serial.println(" °C)");
+    Serial.unblock();
+  }
+}
diff --git a/examples/Threading_Basics/Thermostat/TemperatureControl_SleepingRoom.inot b/examples/Threading_Basics/Thermostat/TemperatureControl_SleepingRoom.inot
new file mode 100644
index 0000000..cf86f23
--- /dev/null
+++ b/examples/Threading_Basics/Thermostat/TemperatureControl_SleepingRoom.inot
@@ -0,0 +1,59 @@
+/* Define a data sink named 'temperature' of type 'float'. */
+SINK(temperature, float, 10);
+
+static String sleeping_room_message_prefix(String const & /* msg */)
+{
+  return String("[Sleeping Room] ");
+}
+
+void setup()
+{
+  Serial.begin(9600);
+  Serial.prefix(sleeping_room_message_prefix);
+  while (!Serial) { }
+}
+
+bool is_ac_on = false;
+
+void loop()
+{
+  float current_temperature_deg = temperature.pop();
+
+  /* Check if the temperature reported by the thermostat is above
+   * or below 20.0 °C. If the temperature is above 20.0 °C, turn
+   * on the AC.
+   */
+  bool turn_ac_on  = false,
+       turn_ac_off = false;
+
+  if (current_temperature_deg > 20.0f)
+    turn_ac_on = true;
+  else
+    turn_ac_off = true;
+
+  /* Only perform a simulated turning on of
+   * the air conditioner if the heating is
+   * air conditioner is currently turned off.
+   */
+  if (is_ac_on && turn_ac_off)
+  {
+    is_ac_on = false;
+  
+    Serial.block();
+    Serial.print("AC OFF (");
+    Serial.print(current_temperature_deg);
+    Serial.println(" °C)");
+    Serial.unblock();
+  }
+
+  if (!is_ac_on && turn_ac_on)
+  {
+    is_ac_on = true;
+    
+    Serial.block();
+    Serial.print("AC ON  (");
+    Serial.print(current_temperature_deg);
+    Serial.println(" °C)");
+    Serial.unblock();
+  }
+}
diff --git a/examples/Threading_Basics/Thermostat/TemperatureSensor.inot b/examples/Threading_Basics/Thermostat/TemperatureSensor.inot
new file mode 100644
index 0000000..8d7c3b1
--- /dev/null
+++ b/examples/Threading_Basics/Thermostat/TemperatureSensor.inot
@@ -0,0 +1,19 @@
+/* Define a data source named 'temperature' of type 'float'. */
+SOURCE(temperature, float);
+
+void setup()
+{
+
+}
+
+void loop()
+{
+  /* Read temperature - since this is just a simulation
+   * so we take a random value between 15 and 25 °C.
+   */
+  float const temperature_deg = (rand() % 16) + 10;
+  /* Store in temperature source variable. */
+  temperature.push(temperature_deg);
+  /* Do only one temperature sensore measurement per second. */
+  delay(5000);
+}
diff --git a/examples/Threading_Basics/Thermostat/TemperatureSensorReporter.inot b/examples/Threading_Basics/Thermostat/TemperatureSensorReporter.inot
new file mode 100644
index 0000000..c6ceb10
--- /dev/null
+++ b/examples/Threading_Basics/Thermostat/TemperatureSensorReporter.inot
@@ -0,0 +1,19 @@
+/* Define a data sink named 'temperature' of type 'float'. */
+SINK(temperature, float);
+
+void setup()
+{
+  Serial.begin(9600);
+  while (!Serial) { }
+}
+
+void loop()
+{
+  float const current_temperature_deg = temperature.pop();
+
+  Serial.block();
+  Serial.print("Temperature = ");
+  Serial.print(current_temperature_deg);
+  Serial.println(" °C");
+  Serial.unblock();
+}
diff --git a/examples/Threading_Basics/Thermostat/Thermostat.ino b/examples/Threading_Basics/Thermostat/Thermostat.ino
new file mode 100644
index 0000000..a655e96
--- /dev/null
+++ b/examples/Threading_Basics/Thermostat/Thermostat.ino
@@ -0,0 +1,37 @@
+/* This example emulates a thermostat system which consists of
+ * a single temperature sensore and multiple heating devices
+ * or air-conditioners. The temperature sensor provides periodic
+ * temperature sensor measurements and acts as a temperature source.
+ * This temperature is consumed by various TemperatureControl_ threads
+ * which perform the act of actual room temperature control.
+ * 
+ * Note: While there is only a single temperature "source" there are
+ * multiple temperature "sinks". The source/sink paradigm is constructed
+ * in such a way, that each sink is guaranteed to see every value provided
+ * by a source. This is something that can not be modeled using the shared
+ * variable abstraction.
+ */
+
+void setup()
+{
+  /* Connect the TemperatureSensor thread providing temperature readings
+   * with the various TemperatureControl_* threads.
+   */
+  TemperatureSensor.temperature.connectTo(TemperatureControl_LivingRoom.temperature);
+  TemperatureSensor.temperature.connectTo(TemperatureControl_SleepingRoom.temperature);
+  TemperatureSensor.temperature.connectTo(TemperatureSensorReporter.temperature);
+
+  /* Start the individual threads for sensing the temperature
+   * and controlling heating/air-conditioning based on the sensed
+   * temperature on a per-room basis.
+   */
+  TemperatureSensor.start();
+  TemperatureControl_LivingRoom.start();
+  TemperatureControl_SleepingRoom.start();
+  TemperatureSensorReporter.start();
+}
+
+void loop()
+{
+
+}

From 1e5a95a9ecb40d2a2b36c6ce00bd2c0be252c6d5 Mon Sep 17 00:00:00 2001
From: Alexander Entinger <cto@lxrobotics.com>
Date: Fri, 22 Jul 2022 08:26:45 +0200
Subject: [PATCH 2/2] Simplify example.

---
 ..._SleepingRoom.inot => AirConditionerControl.inot} | 10 ++--------
 ...reControl_LivingRoom.inot => HeatingControl.inot} |  6 ------
 .../Thermostat/TemperatureSensor.inot                |  4 ++--
 examples/Threading_Basics/Thermostat/Thermostat.ino  | 12 ++++++------
 4 files changed, 10 insertions(+), 22 deletions(-)
 rename examples/Threading_Basics/Thermostat/{TemperatureControl_SleepingRoom.inot => AirConditionerControl.inot} (79%)
 rename examples/Threading_Basics/Thermostat/{TemperatureControl_LivingRoom.inot => HeatingControl.inot} (88%)

diff --git a/examples/Threading_Basics/Thermostat/TemperatureControl_SleepingRoom.inot b/examples/Threading_Basics/Thermostat/AirConditionerControl.inot
similarity index 79%
rename from examples/Threading_Basics/Thermostat/TemperatureControl_SleepingRoom.inot
rename to examples/Threading_Basics/Thermostat/AirConditionerControl.inot
index cf86f23..59dc16e 100644
--- a/examples/Threading_Basics/Thermostat/TemperatureControl_SleepingRoom.inot
+++ b/examples/Threading_Basics/Thermostat/AirConditionerControl.inot
@@ -1,15 +1,9 @@
 /* Define a data sink named 'temperature' of type 'float'. */
 SINK(temperature, float, 10);
 
-static String sleeping_room_message_prefix(String const & /* msg */)
-{
-  return String("[Sleeping Room] ");
-}
-
 void setup()
 {
   Serial.begin(9600);
-  Serial.prefix(sleeping_room_message_prefix);
   while (!Serial) { }
 }
 
@@ -20,13 +14,13 @@ void loop()
   float current_temperature_deg = temperature.pop();
 
   /* Check if the temperature reported by the thermostat is above
-   * or below 20.0 °C. If the temperature is above 20.0 °C, turn
+   * or below 26.0 °C. If the temperature is above 26.0 °C, turn
    * on the AC.
    */
   bool turn_ac_on  = false,
        turn_ac_off = false;
 
-  if (current_temperature_deg > 20.0f)
+  if (current_temperature_deg > 26.0f)
     turn_ac_on = true;
   else
     turn_ac_off = true;
diff --git a/examples/Threading_Basics/Thermostat/TemperatureControl_LivingRoom.inot b/examples/Threading_Basics/Thermostat/HeatingControl.inot
similarity index 88%
rename from examples/Threading_Basics/Thermostat/TemperatureControl_LivingRoom.inot
rename to examples/Threading_Basics/Thermostat/HeatingControl.inot
index f771ce9..5fcaf82 100644
--- a/examples/Threading_Basics/Thermostat/TemperatureControl_LivingRoom.inot
+++ b/examples/Threading_Basics/Thermostat/HeatingControl.inot
@@ -1,15 +1,9 @@
 /* Define a data sink named 'temperature' of type 'float'. */
 SINK(temperature, float, 10);
 
-static String living_room_message_prefix(String const & /* msg */)
-{
-  return String("[Living Room] ");
-}
-
 void setup()
 {
   Serial.begin(9600);
-  Serial.prefix(living_room_message_prefix);
   while (!Serial) { }
 }
 
diff --git a/examples/Threading_Basics/Thermostat/TemperatureSensor.inot b/examples/Threading_Basics/Thermostat/TemperatureSensor.inot
index 8d7c3b1..d763ca4 100644
--- a/examples/Threading_Basics/Thermostat/TemperatureSensor.inot
+++ b/examples/Threading_Basics/Thermostat/TemperatureSensor.inot
@@ -9,9 +9,9 @@ void setup()
 void loop()
 {
   /* Read temperature - since this is just a simulation
-   * so we take a random value between 15 and 25 °C.
+   * so we take a random value between 15 and 30 °C.
    */
-  float const temperature_deg = (rand() % 16) + 10;
+  float const temperature_deg = (rand() % 16) + 15;
   /* Store in temperature source variable. */
   temperature.push(temperature_deg);
   /* Do only one temperature sensore measurement per second. */
diff --git a/examples/Threading_Basics/Thermostat/Thermostat.ino b/examples/Threading_Basics/Thermostat/Thermostat.ino
index a655e96..7fdfd17 100644
--- a/examples/Threading_Basics/Thermostat/Thermostat.ino
+++ b/examples/Threading_Basics/Thermostat/Thermostat.ino
@@ -14,11 +14,11 @@
 
 void setup()
 {
-  /* Connect the TemperatureSensor thread providing temperature readings
-   * with the various TemperatureControl_* threads.
+  /* Connect the temperature sensor thread providing temperature readings
+   * with the various temperature control unit threads.
    */
-  TemperatureSensor.temperature.connectTo(TemperatureControl_LivingRoom.temperature);
-  TemperatureSensor.temperature.connectTo(TemperatureControl_SleepingRoom.temperature);
+  TemperatureSensor.temperature.connectTo(HeatingControl.temperature);
+  TemperatureSensor.temperature.connectTo(AirConditionerControl.temperature);
   TemperatureSensor.temperature.connectTo(TemperatureSensorReporter.temperature);
 
   /* Start the individual threads for sensing the temperature
@@ -26,8 +26,8 @@ void setup()
    * temperature on a per-room basis.
    */
   TemperatureSensor.start();
-  TemperatureControl_LivingRoom.start();
-  TemperatureControl_SleepingRoom.start();
+  HeatingControl.start();
+  AirConditionerControl.start();
   TemperatureSensorReporter.start();
 }