Initial commit: CODESYS tree, integration docs, Node-RED scripts.
PLC application sources (NVL, rooms, boiler), HA/Node-RED integration guide, and NVL patch utilities. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,151 @@
|
||||
(* === DECLARATION === *)
|
||||
FUNCTION_BLOCK fb_boiler
|
||||
VAR_INPUT
|
||||
// Control Commands
|
||||
ha_on: BOOL; // Home Assistant ON command
|
||||
ha_off: BOOL; // Home Assistant OFF command
|
||||
schedule_on: BOOL; // Scheduled ON
|
||||
schedule_off: BOOL; // Scheduled OFF
|
||||
|
||||
// Safety
|
||||
emergency_stop: BOOL; // Emergency stop input
|
||||
|
||||
// Configuration
|
||||
max_on_time: TIME := T#8H; // Maximum ON time (default 8 hours)
|
||||
END_VAR
|
||||
VAR_OUTPUT
|
||||
// Outputs
|
||||
relay_control: BOOL; // Control output to relay
|
||||
|
||||
// Status
|
||||
state: BOOL; // Current state
|
||||
on_time_seconds: DINT; // Current ON time in seconds
|
||||
remaining_seconds: DINT; // Remaining time in seconds
|
||||
|
||||
// Safety Status
|
||||
emergency_active: BOOL; // Emergency stop active
|
||||
time_limit_reached: BOOL; // Time limit was reached
|
||||
error_state: BOOL; // Error flag
|
||||
error_code: INT; // Error code
|
||||
END_VAR
|
||||
VAR
|
||||
// Internal State
|
||||
internal_state: BOOL := FALSE;
|
||||
last_state: BOOL := FALSE;
|
||||
|
||||
// Edge Detection
|
||||
r_trig_ha_on: R_TRIG;
|
||||
r_trig_ha_off: R_TRIG;
|
||||
r_trig_schedule_on: R_TRIG;
|
||||
r_trig_schedule_off: R_TRIG;
|
||||
r_trig_emergency: R_TRIG;
|
||||
f_trig_emergency: F_TRIG;
|
||||
|
||||
// Timers
|
||||
on_timer: TON; // Counts ON time
|
||||
|
||||
// Time tracking
|
||||
max_on_seconds: DINT;
|
||||
END_VAR
|
||||
|
||||
(* === IMPLEMENTATION === *)
|
||||
// =====================================================
|
||||
// fb_boiler - Implementation
|
||||
// =====================================================
|
||||
// Priority (highest to lowest):
|
||||
// 1. Emergency Stop - Immediate shutdown
|
||||
// 2. Time Limit Exceeded - Auto shutdown
|
||||
// 3. OFF Commands - Turn off
|
||||
// 4. ON Commands - Turn on (if safe)
|
||||
// =====================================================
|
||||
|
||||
// Calculate max time in seconds
|
||||
max_on_seconds := TIME_TO_DINT(max_on_time) / 1000;
|
||||
|
||||
// Edge detection for commands
|
||||
r_trig_ha_on(CLK := ha_on);
|
||||
r_trig_ha_off(CLK := ha_off);
|
||||
r_trig_schedule_on(CLK := schedule_on);
|
||||
r_trig_schedule_off(CLK := schedule_off);
|
||||
r_trig_emergency(CLK := emergency_stop);
|
||||
f_trig_emergency(CLK := emergency_stop);
|
||||
|
||||
// =====================================================
|
||||
// SAFETY CHECKS (highest priority)
|
||||
// =====================================================
|
||||
|
||||
// Priority 1: Emergency Stop
|
||||
IF emergency_stop THEN
|
||||
internal_state := FALSE;
|
||||
emergency_active := TRUE;
|
||||
error_state := TRUE;
|
||||
error_code := 1; // Emergency stop active
|
||||
|
||||
// Priority 2: Time Limit Check
|
||||
ELSIF on_timer.Q THEN
|
||||
internal_state := FALSE;
|
||||
time_limit_reached := TRUE;
|
||||
error_state := TRUE;
|
||||
error_code := 2; // Time limit exceeded
|
||||
|
||||
// =====================================================
|
||||
// CONTROL LOGIC (only when safe)
|
||||
// =====================================================
|
||||
ELSE
|
||||
// Clear safety flags when emergency released
|
||||
IF f_trig_emergency.Q THEN
|
||||
emergency_active := FALSE;
|
||||
error_state := FALSE;
|
||||
error_code := 0;
|
||||
END_IF;
|
||||
|
||||
// Clear time limit flag when boiler turned off
|
||||
IF NOT internal_state THEN
|
||||
time_limit_reached := FALSE;
|
||||
IF error_code = 2 THEN
|
||||
error_state := FALSE;
|
||||
error_code := 0;
|
||||
END_IF;
|
||||
END_IF;
|
||||
|
||||
// Priority 3: OFF Commands (HA OFF or Schedule OFF)
|
||||
IF r_trig_ha_off.Q OR r_trig_schedule_off.Q THEN
|
||||
internal_state := FALSE;
|
||||
|
||||
// Priority 4: ON Commands (HA ON or Schedule ON)
|
||||
ELSIF (r_trig_ha_on.Q OR r_trig_schedule_on.Q) AND NOT time_limit_reached THEN
|
||||
internal_state := TRUE;
|
||||
END_IF;
|
||||
END_IF;
|
||||
|
||||
// =====================================================
|
||||
// TIMER MANAGEMENT
|
||||
// =====================================================
|
||||
|
||||
// ON timer - counts total ON time
|
||||
on_timer(
|
||||
IN := internal_state AND NOT emergency_active,
|
||||
PT := max_on_time
|
||||
);
|
||||
|
||||
// Calculate current ON time in seconds
|
||||
IF internal_state THEN
|
||||
on_time_seconds := TIME_TO_DINT(on_timer.ET) / 1000;
|
||||
remaining_seconds := max_on_seconds - on_time_seconds;
|
||||
IF remaining_seconds < 0 THEN
|
||||
remaining_seconds := 0;
|
||||
END_IF;
|
||||
ELSE
|
||||
on_time_seconds := 0;
|
||||
remaining_seconds := max_on_seconds;
|
||||
END_IF;
|
||||
|
||||
// =====================================================
|
||||
// OUTPUT ASSIGNMENT
|
||||
// =====================================================
|
||||
|
||||
// Relay control - only ON when state is ON and no emergency
|
||||
relay_control := internal_state AND NOT emergency_active;
|
||||
|
||||
// State output
|
||||
state := internal_state;
|
||||
Reference in New Issue
Block a user