diff --git a/icbm.ino b/icbm.ino
index c43b3cf30726d99a9c137b62a6b96d70b63a1de3..cb83fd8509e4a18a140a06e539773f54c7535da9 100644
--- a/icbm.ino
+++ b/icbm.ino
@@ -15,11 +15,13 @@ void setup() {
     initializeRoutes();
     initializeSNMP();
 
-    start = millis();
-
+    // Poll port expander to initialize the PINS struct.
     poll_port_expander();
+    PINS.last_triggered = millis();
     PINS.stage = "";
     PINS.ramping = false;
+
+    start = millis();
 }
 
 enum {
@@ -28,7 +30,7 @@ enum {
     OFF,
 };
 
-void serial_loop() {
+void serialLoop() {
     if (millis() - start >= 1000) {
         start = millis();
         Serial.print(eth_connected ? "." : "-");
@@ -40,5 +42,8 @@ void loop() {
     snmp.loop();
     restServer.handleClient();
     toggle_status_led();
-    serial_loop();
+    serialLoop();
+    if (eth_connected) {  // We may be triggered, but disconnected from the network.
+        powerOffCheckLoop();
+    }
 }
diff --git a/mpod.cpp b/mpod.cpp
index 4ceb264867b8642de2ca540992e7a299ca29412f..d46fd3f791ea5cc1bf08b69b1ccc70412305dc56 100644
--- a/mpod.cpp
+++ b/mpod.cpp
@@ -5,6 +5,7 @@
 
 MPOD::MPOD() {
     bool _on = false;
+    bool _interlocked = false;
     bool _rampingUp = false;
     bool _rampingDown = false;
     float _measurementSenseVoltage = 0;
@@ -85,6 +86,7 @@ bool MPOD::message(const SNMP::Message *message) {
                     break;
                 }
                 _on = status->getBit(0);
+                _interlocked = status->getBit(1);
                 _rampingUp = status->getBit(11);
                 _rampingDown = status->getBit(12);
             }
@@ -105,9 +107,6 @@ bool MPOD::message(const SNMP::Message *message) {
                 found++;
                 break;
             case OID::OUTPUTSWITCH:
-                // Use private helper function to extract integer value
-                Serial.print("Output Switch Length: ");
-                Serial.println(varbind->getLength());
                 _on = getIntegerFromVarBind(varbind);
                 found++;
                 break;
@@ -154,6 +153,8 @@ bool MPOD::message(const SNMP::Message *message) {
 
 bool MPOD::isOn() const { return _on; }
 
+bool MPOD::isInterlocked() const { return _interlocked; }
+
 bool MPOD::isRampingUp() const { return _rampingUp; }
 
 bool MPOD::isRampingDown() const { return _rampingDown; }
@@ -185,6 +186,7 @@ String MPOD::toJSON() {
     String json = "{\n";
     json += "\"channel\":" + String(getChannel()) + ",";
     json += "\"is_on\":" + String(isOn()) + ",";
+    json += "\"is_interlocked\":" + String(isInterlocked()) + ",";
     json += "\"ramping_up\":" + String(isRampingUp()) + ",";
     json += "\"ramping_down\":" + String(isRampingDown()) + ",";
     json += "\"sense_voltage\":" + String(getMeasurementSenseVoltage()) + ",";
@@ -261,7 +263,7 @@ void setChannelStateAndWait(const IPAddress *ipAddr, const uint16_t channel, con
         loopCount += 1;
         ramping = (mpod.isRampingUp() || mpod.isRampingDown());
         if (!ramping) {
-            if (mpod.isOn() == (bool)output) {
+            if ((mpod.isOn() == (bool)output || mpod.isInterlocked())) {
                 settingChannelState = false;
             } else if (loopCount >= 5) {
                 // Resend set command
diff --git a/mpod.hpp b/mpod.hpp
index 8ecd78f17ddca1c1f65409a0f27da26575fd3e2b..ac64d040e8be88facffe66a2e3f8cee49e52d7e1 100644
--- a/mpod.hpp
+++ b/mpod.hpp
@@ -34,7 +34,7 @@ class MPOD {
                 UNKNOWN,
                 COUNT = UNKNOWN,
             };
-    
+
             static inline const char *NAMES[] = {
                     // These are incomplete SNMP commands needing to be
                     // formatted with the channel id after the final dot
@@ -46,7 +46,7 @@ class MPOD {
                     "1.3.6.1.4.1.19947.1.3.2.1.12.",
                     "1.3.6.1.4.1.19947.1.3.2.1.13.",
             };
-    
+
             // Returns index of OID equals to name
             // Returns UNKNOWN if none
             static unsigned int match(const char *name) {
@@ -58,13 +58,14 @@ class MPOD {
                 return UNKNOWN;
             }
         };
-    
-        MPOD();  
+
+        MPOD();
         SNMP::Message* read(const uint16_t);
         SNMP::Message* setChannelState(const uint16_t, const bool);
         SNMP::Message* setTargetVoltage(const uint16_t, const float);
         bool message(const SNMP::Message*);
         bool isOn() const;
+        bool isInterlocked() const;
         bool isRampingUp() const;
         bool isRampingDown() const;
         float getMeasurementSenseVoltage() const;
@@ -74,12 +75,13 @@ class MPOD {
         float getVoltageRiseRate() const;
         uint16_t getChannel() const;
         String toJSON();
-    
+
     private:
         unsigned int getIntegerFromVarBind(const VarBind*);
         float getFloatFromVarBind(const VarBind*);
         uint16_t _channel;
         bool _on;
+        bool _interlocked;
         bool _rampingUp;
         bool _rampingDown;
         float _measurementSenseVoltage;
diff --git a/pins.cpp b/pins.cpp
index c64146c4b3562c038a48d1fa582a581abb837675..03a94ccebd9cbf5ef6bff9fca4021c4694b8c2d9 100644
--- a/pins.cpp
+++ b/pins.cpp
@@ -1,10 +1,16 @@
 #include "pins.hpp"
 
+#include "powerproc.hpp"
+
 MCP23S08 MCP(SS, MISO, MOSI, SCK);
-volatile byte ISR_FLAG = 0;
+
+// Semaphores for handling interrupts and power down events.
+volatile byte MCP_ISR_FLAG = 0;
+volatile byte PERFORM_PROCEDURE_FROM_INTERRUPT = 0;
+
 struct pins PINS;
 
-void IRAM_ATTR isr() { ISR_FLAG = 1; }
+void IRAM_ATTR isr() { MCP_ISR_FLAG = 1; }
 
 void initializeMCP() {
     pinMode(ISR_PIN, INPUT_PULLUP);
@@ -18,40 +24,54 @@ void initializeMCP() {
     MCP.enableInterrupt(0, CHANGE);
     MCP.enableInterrupt(1, CHANGE);
     MCP.enableInterrupt(2, CHANGE);
+
+    // Inform SIB we're ready
+    MCP.write1(ALERT_SIB_PIN, HIGH);
+
     Serial.println("MCP23S08 Started");
 }
 
 void isr_check_loop() {
-    if (ISR_FLAG == 1) {
-        PINS.sib = false;
-        PINS.plc = false;
-        PINS.ups = false;
-        PINS.last_triggered = millis();
-
-        Serial.print("Interrupt: ");
-        uint8_t regval = MCP.getInterruptCaptureRegister();  // INTCAP
-        Serial.print(regval, BIN);
-
-        uint8_t mask = 1 << 0;
-        if (!(regval & mask)) {
-            Serial.print(" UPS");
-            PINS.ups = true;
-        }
-
-        mask = 1 << 1;
-        if (!(regval & mask)) {
-            Serial.print(" PLC");
-            PINS.plc = true;
-        }
-
-        mask = 1 << 2;
-        if (!(regval & mask)) {
-            Serial.print(" SIB");
-            PINS.sib = true;
-        }
-
-        Serial.println();
-        ISR_FLAG = 0;
+    if (MCP_ISR_FLAG == 0) {
+        return;
+    }
+    // False means triggered (not ok).
+    PINS.sib = false;
+    PINS.plc = false;
+    PINS.ups = false;
+    PINS.last_triggered = millis();
+
+    // Get the pins status at the time of the interrupt, and check their statuses.
+    Serial.print("Interrupt: ");
+    uint8_t regval = MCP.getInterruptCaptureRegister();  // INTCAP
+    Serial.print(regval, BIN);
+
+    uint8_t mask = 1 << 0;
+    if (!(regval & mask)) {
+        Serial.print(" UPS");
+        PINS.ups = true;
+    }
+
+    mask = 1 << 1;
+    if (!(regval & mask)) {
+        Serial.print(" PLC");
+        PINS.plc = true;
+    }
+
+    mask = 1 << 2;
+    if (!(regval & mask)) {
+        Serial.print(" SIB");
+        PINS.sib = true;
+    }
+
+    Serial.println();
+
+    // This interrupt was handled
+    MCP_ISR_FLAG = 0;
+
+    // If not all ok, set the power down flag, later handled.
+    if (!(PINS.sib && PINS.plc && PINS.ups)) {
+        PERFORM_PROCEDURE_FROM_INTERRUPT = 1;
     }
 }
 
@@ -59,7 +79,6 @@ void poll_port_expander() {
     PINS.sib = false;
     PINS.plc = false;
     PINS.ups = false;
-    PINS.last_triggered = millis();
     int regval = MCP.read8();
 
     uint8_t mask = 1 << 0;
@@ -92,3 +111,56 @@ void toggle_status_led() {
         MCP.write1(STATUS_LED_PIN, on);
     }
 }
+
+void powerOffCheckLoop() {
+    if (!PERFORM_PROCEDURE_FROM_INTERRUPT) {
+        return;
+    }
+    // Disable interrupts while performing power procedure.
+    // Once we've been triggered, we perform the power down procedure, uninterrupted,
+    // regardless of changes in the environment.
+    detachInterrupt(digitalPinToInterrupt(ISR_PIN));
+
+    // Update status on serial interface and status webpage.
+    PINS.ramping = true;
+    Serial.println("POWERING DOWN DUE TO TRIGGER.");
+
+    // Inform SIB that we're about to perform a procedure.
+    MCP.write1(ALERT_SIB_PIN, LOW);
+    Serial.println("asked sib down");
+
+    // Wait for SIB to acknowledge by checking its input (should go to triggered).
+    /* This require hardware changes, not implemented yet.
+    // TODO: apply a timeout and go ahead anyway?
+    do {
+        delay(200);
+        poll_port_expander();
+    } while(!(PINS.sib));
+    Serial.println("SIB ACK");
+     */
+
+    // Iterate through each group and power down.
+    String group;
+    String groups;
+    for (int8_t groupIdx = pproc.stagesCount - 1; groupIdx >= 0; groupIdx--) {
+        group = pproc.stages[groupIdx].name;
+        groups += group;
+        groups += ",";
+        PINS.stage = group;
+        pproc.powerOff(group);
+        delay(1000);
+    }
+
+    // Clear statuses on webpage and serial interfaces.
+    PINS.ramping = false;
+    Serial.print("Finished powering down from interrupt: ");
+    Serial.println(groups);
+    PINS.stage = "Ramped down";
+
+    // This event has been handled.
+    PERFORM_PROCEDURE_FROM_INTERRUPT = 0;
+    // Inform SIB that we're done and it can take data again.
+    MCP.write1(ALERT_SIB_PIN, HIGH);
+    // Re-enable interrupts before exiting.
+    attachInterrupt(digitalPinToInterrupt(ISR_PIN), isr, CHANGE);
+}
diff --git a/pins.hpp b/pins.hpp
index 0cd10be8355680ed00f69e82155f5bf4df5fe46f..e1efb053f3824ff5eeb9d3b30c7312e44c2caec9 100644
--- a/pins.hpp
+++ b/pins.hpp
@@ -13,9 +13,12 @@
 //AlCon Logic Board interrupt
 #define TRIGGER_SIGNAL 14
 
-// LED pin on MCP23S08 extender
+// LED pin on MCP23S08 expander
 #define STATUS_LED_PIN 6
 
+// Pin to inform SIB that a power down is about to happen, on MCP23S08 expander
+#define ALERT_SIB_PIN 7
+
 struct pins {
    bool sib;
    bool plc;
@@ -32,3 +35,4 @@ void initializeMCP();
 void isr_check_loop();
 void poll_port_expander();
 void toggle_status_led();
+void powerOffCheckLoop();
diff --git a/powerproc.hpp b/powerproc.hpp
index 979df469bee14954ac6bd1b95ccbbee18c5e62a6..8e91b8810d72d700e23d62f628a8db8e387ec948 100644
--- a/powerproc.hpp
+++ b/powerproc.hpp
@@ -34,4 +34,6 @@ public:
     String toJSON();
 };
 
+void powerOffCheckLoop();
+
 extern PowerProcedure pproc;
diff --git a/rest.cpp b/rest.cpp
index e4bbea1f025e0beae09f5fd353127b3718a6f917..e71b0837da9a35ae53a3aa3b931ba765fa5b8cc2 100644
--- a/rest.cpp
+++ b/rest.cpp
@@ -274,10 +274,9 @@ void pollMPODChannel() {
         }
     }
 
-    String ret;
-    if (!channel) {
-        ret = "\"reason\": \"Invalid channel\"";
-    } else {
+    String ret = "\"Invalid channel\"";
+
+    if (channel) {
         SNMP::Message *snmp_msg = mpod.read(channel);
         snmp.send(snmp_msg, pproc.ipAddr, SNMP::Port::SNMP);
         delete snmp_msg;
@@ -285,20 +284,22 @@ void pollMPODChannel() {
         delay(MPOD_UPDATE_LATENCY);
         snmp.loop();  // Force loop to update now
 
-        if (mpod.getChannel()) {
+        if (mpod.getChannel()) {  // Valid channel requested
             ret = mpod.toJSON();
-        } else {
-            ret = "\"reason\": \"Invalid channel\"";
-            channel = 0;
         }
     }
 
     String http_msg = "{\n";
+    http_msg += "\"success\": ";
+    http_msg += channel ? 1 : 0;
+    http_msg += ",\n";
+    http_msg += "\"arguments\": {";
+    http_msg += "\"channel\": ";
+    http_msg += channel;
+    http_msg += "},\n";  // arguments
     http_msg += "\"status\": ";
     http_msg += ret;
-    http_msg += ",\"success\": ";
-    http_msg += channel ? 1 : 0;
-    http_msg += "\n}";
+    http_msg += "}";
 
     restServer.send(channel ? 200 : 406, "text/json", http_msg);
 }