//
// pushlogic version 0
// Heating Controller
inout Heating#Control#Furnace : {0: 1};
inout Heating#Control#Pump : {0: 1};
input Heating#Sense#TankThermostat : {0: 1};
input Heating#Sense#RoomThermostat : {0: 1};
output HVAC#Control#Light1 : {0: 1};
// This constraint is physically implemented by the hardware interlock, but
// it is a good idea to state it in the PushLogic as well.
// The hardware interlock is mirrored as a software interlock that pushes
// back on the Furnace and Pump control fields.
always (Heating#Sense#RoomThermostat==0 && Heating#Sense#TankThermostat==0) =>
Heating#Control#Furnace==0 && Heating#Control#Pump== 0;
// Annunciator leds:
output Display#leds#HotWater : {0: 1};
output Display#leds#CentralHeating : {0: 1};
output Display#leds#Hour : {off: 0-23};
output Display#leds#Minute : {off: 0-59};
input Keypad#Keys#index : {0: up down fast_up fast_down};
input Keypad#Keys#override : {0: 1};
input Keypad#Keys#ModeSelect : { 0: CurrentTime Heating_On1_Time Heating_On0_Time Heating_Off1_Time Heating_Off0_Time Water_On1_Time Water_On0_Time Water_Off1_Time Water_Off0_Time };
// Communication with the timer Pebble:
input Timer#Timenow#hour : {0-23}, Timer#Timenow#minute : {0-59};
// Local state variables
local Times#Heating_On0#Hour : {0-23}, Times#Heating_On0#Minute : {0-59};
local Times#Heating_Off0#Hour: {0-23}, Times#Heating_Off0#Minute: {0-59};
local Times#Heating_On1#Hour : {0-23}, Times#Heating_On1#Minute : {0-59};
local Times#Heating_Off1#Hour: {0-23}, Times#Heating_Off1#Minute: {0-59};
local Times#Water_On0#Hour : {0-23}, Times#Water_On0#Minute : {0-59};
local Times#Water_Off0#Hour : {0-23}, Times#Water_Off0#Minute : {0-59};
local Times#Water_On1#Hour : {0-23}, Times#Water_On1#Minute : {0-59};
local Times#Water_Off1#Hour : {0-23}, Times#Water_Off1#Minute : {0-59};
local HEATING : {0:1}, WATER : {0:1};
with Timer#Timenow
{
macro heating_on =
(Times#Heating_On0#(Hour, Minute) == #(hour, minute)) ||
(Times#Heating_On1#(Hour, Minute) == #(hour, minute));
macro water_on =
(Times#Water_On0#(Hour, Minute) == #(hour, minute)) ||
(Times#Water_On1#(Hour, Minute) == #(hour, minute));
macro heating_off =
(Times#Heating_Off0#(Hour, Minute) == #(hour, minute)) ||
(Times#Heating_Off1#(Hour, Minute) == #(hour, minute));
macro water_off =
(Times#Water_Off0#(Hour, Minute) == #(hour, minute)) ||
(Times#Water_Off1#(Hour, Minute) == #(hour, minute));
}
// Front panel override button
if (^Keypad#Keys#override && Keypad#Keys#override=="1")
HEATING := ! (HEATING);
else
// Give priority to off if off and on times are the same.
if (heating_off) HEATING:=0; else if (heating_on) HEATING:=1;
if (water_off) WATER:=0; else if (water_on) WATER:=1;
// Annunciators
with Display#leds
{
#HotWater := WATER;
#CentralHeating := HEATING;
}
// Up/Down Buttons
macro key_up = (Keypad#Keys#index == up) || (Keypad#Keys#index == fast_up);
macro key_down = (Keypad#Keys#index == down) || (Keypad#Keys#index == fast_down);
macro key_fast = (Keypad#Keys#index == fast_up) || (Keypad#Keys#index == fast_down);
if (^Timer#Timenow#second || (key_fast && ^Timer#Timenow#fast_clock) || ^key_up || ^key_down)
switch (Keypad#Keys#ModeSelect)
{
case Heating_On0_Time:
with (Times#Heating_On0)
{
#Minute := (key_up) ? (#Minute == 59) ? 0 : #Minute + 1 :
(key_down) ? (#Minute == 0) ? 59 : #Minute - 1 : #Minute;
#Hour := (key_up) ? ((#Minute == 59) ? ((#Hour == 23) ? 0 : #Hour + 1) : #Hour) :
(key_down) ? ((#Minute == 0) ? ((#Hour == 0) ? 23 : #Hour - 1) : #Hour) : #Hour;
}
case Heating_Off0_Time:
with (Times#Heating_Off0)
{
#Minute := (key_up) ? (#Minute == 59) ? 0 : #Minute + 1 :
(key_down) ? (#Minute == 0) ? 59 : #Minute - 1 : #Minute;
#Hour := (key_up) ? ((#Minute == 59) ? ((#Hour == 23) ? 0 : #Hour + 1) : #Hour) :
(key_down) ? ((#Minute == 0) ? ((#Hour == 0) ? 23 : #Hour - 1) : #Hour) : #Hour;
}
case Heating_On1_Time:
with (Times#Heating_On1)
{
#Minute := (key_up) ? (#Minute == 59) ? 0 : #Minute + 1 :
(key_down) ? (#Minute == 0) ? 59 : #Minute - 1 : #Minute;
#Hour := (key_up) ? ((#Minute == 59) ? ((#Hour == 23) ? 0 : #Hour + 1) : #Hour) :
(key_down) ? ((#Minute == 0) ? ((#Hour == 0) ? 23 : #Hour - 1) : #Hour) : #Hour;
}
case Heating_Off1_Time:
with (Times#Heating_Off1)
{
#Minute := (key_up) ? (#Minute == 59) ? 0 : #Minute + 1 :
(key_down) ? (#Minute == 0) ? 59 : #Minute - 1 : #Minute;
#Hour := (key_up) ? ((#Minute == 59) ? ((#Hour == 23) ? 0 : #Hour + 1) : #Hour) :
(key_down) ? ((#Minute == 0) ? ((#Hour == 0) ? 23 : #Hour - 1) : #Hour) : #Hour;
}
case Water_On0_Time:
with (Times#Water_On0)
{
#Minute := (key_up) ? (#Minute == 59) ? 0 : #Minute + 1 :
(key_down) ? (#Minute == 0) ? 59 : #Minute - 1 : #Minute;
#Hour := (key_up) ? ((#Minute == 59) ? ((#Hour == 23) ? 0 : #Hour + 1) : #Hour) :
(key_down) ? ((#Minute == 0) ? ((#Hour == 0) ? 23 : #Hour - 1) : #Hour) : #Hour;
}
case Water_Off0_Time:
with (Times#Water_Off0)
{
#Minute := (key_up) ? (#Minute == 59) ? 0 : #Minute + 1 :
(key_down) ? (#Minute == 0) ? 59 : #Minute - 1 : #Minute;
#Hour := (key_up) ? ((#Minute == 59) ? ((#Hour == 23) ? 0 : #Hour + 1) : #Hour) :
(key_down) ? ((#Minute == 0) ? ((#Hour == 0) ? 23 : #Hour - 1) : #Hour) : #Hour;
}
case Water_On1_Time:
with (Times#Water_On1)
{
#Minute := (key_up) ? (#Minute == 59) ? 0 : #Minute + 1 :
(key_down) ? (#Minute == 0) ? 59 : #Minute - 1 : #Minute;
#Hour := (key_up) ? ((#Minute == 59) ? ((#Hour == 23) ? 0 : #Hour + 1) : #Hour) :
(key_down) ? ((#Minute == 0) ? ((#Hour == 0) ? 23 : #Hour - 1) : #Hour) : #Hour;
}
case Water_Off1_Time:
with (Times#Water_Off1)
{
#Minute := (key_up) ? (#Minute == 59) ? 0 : #Minute + 1 :
(key_down) ? (#Minute == 0) ? 59 : #Minute - 1 : #Minute;
#Hour := (key_up) ? ((#Minute == 59) ? ((#Hour == 23) ? 0 : #Hour + 1) : #Hour) :
(key_down) ? ((#Minute == 0) ? ((#Hour == 0) ? 23 : #Hour - 1) : #Hour) : #Hour;
}
}
// LED display
with (Times) switch (Keypad#Keys#ModeSelect)
{
case CurrentTime:
Display#leds#(Hour,Minute) := Timer#Timenow#(hour,minute);
case Heating_Off0_Time:
Display#leds#(Hour,Minute) := Times#Heating_Off0#(Hour,Minute);
case Heating_Off1_Time:
Display#leds#(Hour,Minute) := Times#Heating_Off1#(Hour,Minute);
case Heating_On0_Time:
Display#leds#(Hour,Minute) := Times#Heating_On0#(Hour,Minute);
case Heating_On1_Time:
Display#leds#(Hour,Minute) := Times#Heating_On1#(Hour,Minute);
case Water_Off0_Time:
Display#leds#(Hour,Minute) := Times#Water_Off0#(Hour,Minute);
case Water_Off1_Time:
Display#leds#(Hour,Minute) := Times#Water_Off1#(Hour,Minute);
case Water_On0_Time:
Display#leds#(Hour,Minute) := Times#Water_On0#(Hour,Minute);
case Water_On1_Time:
Display#leds#(Hour,Minute) := Times#Water_On1#(Hour,Minute);
default:
// Better would be a five second delay before going blank.
Display#leds#(Hour,Minute) := (off, off);
}
// Main output controls
with (Heating)
{
#Control#Furnace := (HEATING && !(#Sense#RoomThermostat)) || (WATER && !(#Sense#TankThermostat));
#Control#Pump := (HEATING && !(#Sense#RoomThermostat));
}
// EOF
|
As you can see, this code will become a bit shorter when we have implemented arrays in the pushlogic! The pebble statement can be used at the start of the script (or in a separate file) to redirect field references. Therefore, with the following addition, the Pushlogic program can be hosted on a remote platform, yet still interact with the heating unit's physical I/O devices. pebble Heating = "tup:/12.323.44.23/devices/Heating"; pebble Display = "tup:/12.323.44.23/devices/Display"; pebble Keypad = "tup:/12.323.44.23/devices/Keypad"; pebble Timer = $$/Timer; This all works today and can be demonstrated in FN12. Security Light FunctionThe device serves another separate function. It has an additional fused 240V AC switched output that is intended to control a security light. This can be controlled by a separate program, either loaded over the network and hosted on the local Pushlogic execution platform or executed remotely. |