diff --git a/CLC-qthing/SiliconTorch/Hardware/AS3935.cpp b/CLC-qthing/SiliconTorch/Hardware/AS3935.cpp
index de26a0de5372f69a11345c5aa38367162db4ef5f..8bcf7a8268d4479c704641c3be1f38a67892552a 100644
--- a/CLC-qthing/SiliconTorch/Hardware/AS3935.cpp
+++ b/CLC-qthing/SiliconTorch/Hardware/AS3935.cpp
@@ -8,6 +8,8 @@
 #include "esp_err.h"
 #include "driver/i2c.h"
 #include "driver/gpio.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
 
 // project specific
 #include <SpiderLib.hpp>
@@ -20,13 +22,14 @@
 
 
 
+
 static const char* TAG = "AS3935";
 
 
 namespace AS3935 {
 
 
-  AS3935::AS3935(u8 SDA, u8 SCL, u8 IRQ, u8 i2cAddr, u8 i2cChannel, u32 i2cFrequency) : i2cAddr(i2cAddr & I2C_ADDR_MASK), i2cChannel(i2cChannel) {
+  AS3935::AS3935(u8 SDA, u8 SCL, u8 IRQ, u8 i2cAddr, u8 i2cChannel, u32 i2cFrequency) : ioIRQ(IRQ), i2cAddr(i2cAddr & I2C_ADDR_MASK), i2cChannel(i2cChannel) {
 
     i2c_config_t cfg;
 
@@ -62,6 +65,15 @@ namespace AS3935 {
   }
 
 
+  void AS3935::mainLoop() {
+    while (true) {
+
+
+      vTaskDelay(100 / portTICK_PERIOD_MS);
+    }
+  }
+
+
   bool AS3935::clearStatistics() {
     return mutex.runReturn<bool> ([&]() {
       R0x02 reg;
@@ -200,4 +212,9 @@ namespace AS3935 {
     return i2cAddr << 1;
   }
 
+
+  bool AS3935::getIRQState() {
+    return gpio_get_level((gpio_num_t)ioIRQ);
+  }
+
 }
diff --git a/CLC-qthing/SiliconTorch/Hardware/AS3935.hpp b/CLC-qthing/SiliconTorch/Hardware/AS3935.hpp
index f922e0f15125dbf705d7c2e04c0a0d1406030503..ed4b63769c50cad1a9e45fa3b3cdda7bd3c5abbe 100644
--- a/CLC-qthing/SiliconTorch/Hardware/AS3935.hpp
+++ b/CLC-qthing/SiliconTorch/Hardware/AS3935.hpp
@@ -201,9 +201,13 @@ namespace AS3935 {
       bool i2cWriteByteMutex(u8 regAddr, u8  value);  // TMP public for debug
     protected:
 
+      const u8 ioIRQ;
       const u8 i2cAddr;
       const u8 i2cChannel;
 
+      bool getIRQState();
+
+      void mainLoop();
 
       //bool i2cReadByte      (u8 regAddr, u8* value);
       //bool i2cWriteByte     (u8 regAddr, u8  value);
@@ -213,6 +217,8 @@ namespace AS3935 {
       // Used to synchronize I²C calls (the IDF driver don't likes multithreading)
       SpiderLib::ManagedMutex mutex;
 
+      SpiderLib::Util::LambdaTask* loopTask = NULL;
+
   };
 
 }
diff --git a/CLC-qthing/SiliconTorch/Hardware/MAX31856.cpp b/CLC-qthing/SiliconTorch/Hardware/MAX31856.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e953230baa60e887a48be028ba4d69077af4212d
--- /dev/null
+++ b/CLC-qthing/SiliconTorch/Hardware/MAX31856.cpp
@@ -0,0 +1,268 @@
+#include "MAX31856.hpp"
+
+// C++ system level
+// #include <functional>
+
+// ESP32 specific
+#include "esp_log.h"
+#include "esp_err.h"
+#include "driver/gpio.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+
+// project specific
+#include <SpiderLib.hpp>
+
+// qthing stuff
+// #include <qthing>
+
+// misc
+// #include ""
+
+
+
+
+static const char* TAG = "MAX31856";
+
+
+namespace MAX31856 {
+
+
+  SoftSPI::SoftSPI(u8 miso, u8 mosi, u8 sclk, u8 cs) : miso(miso), mosi(mosi), sclk(sclk), cs(cs) {
+
+    // gpio init
+    mutex.run ([&]() {
+
+      gpio_config_t cfg;
+      u8 init_ios[] = {mosi, sclk, cs};
+
+      cfg.pin_bit_mask = 0;
+      for (u8 i = 0; i < 3; i++)
+        cfg.pin_bit_mask |= 1ULL << init_ios[i];
+
+      cfg.mode         = GPIO_MODE_OUTPUT;
+      cfg.intr_type    = GPIO_INTR_DISABLE;
+      cfg.pull_up_en   = GPIO_PULLUP_DISABLE;
+      cfg.pull_down_en = GPIO_PULLDOWN_DISABLE;
+
+      gpio_config(&cfg);
+
+      setCS(1);
+      setMOSI(0);
+      setSCLK(0);
+
+    });
+  }
+
+
+  void SoftSPI::writeU8(u8 addr, u8 value) {
+    mutex.run ([&]() {
+
+      addr     = (addr & 0x0F) | 0x80;
+      u16 data = (addr << 8) | value;
+
+      setCS(0);
+
+      for (i8 n = 15; n >= 0; n--) {
+        setSCLK(1);
+        setMOSI((data >> n) & 1);
+        setSCLK(0);
+      }
+
+      //setSCLK(0);
+      setMOSI(0);
+      setCS(1);
+    });
+  }
+
+
+  u8 SoftSPI::readU8(u8 addr) {
+    return mutex.runReturn<u8> ([&]() {
+
+      addr &= 0x0F;  // mask out write adresses
+      u8 value = 0x00;
+
+      setCS(0);
+
+      for (i8 n = 7; n >= 0; n--) {
+        setSCLK(1);
+        setMOSI((addr >> n) & 1);
+        setSCLK(0);
+      }
+
+      setMOSI(0);
+
+      for (i8 n = 7; n >= 0; n--) {
+        setSCLK(1);
+        value |= getMISO() << n;
+        setSCLK(0);
+      }
+
+      //setSCLK(0);
+      setCS(1);
+
+      return value;
+    });
+  }
+
+  void SoftSPI::setMOSI(bool value) {
+    gpio_set_level((gpio_num_t)mosi, value);
+  }
+
+  void SoftSPI::setSCLK(bool value) {
+    gpio_set_level((gpio_num_t)sclk, value);
+  }
+
+  void SoftSPI::setCS(bool value) {
+    gpio_set_level((gpio_num_t)cs, value);
+  }
+
+  bool SoftSPI::getMISO() {
+    return gpio_get_level((gpio_num_t)miso);
+  }
+
+
+
+  MAX31856::MAX31856(u8 miso, u8 mosi, u8 sclk, u8 cs) : miso(miso), mosi(mosi), sclk(sclk), cs(cs) {
+
+    spi = new SoftSPI(miso, mosi, sclk, cs);
+
+    setPwrLnRjFrq(F50Hz);
+
+    //return;
+
+    for (u8 addr = 0; addr < (0x0F+1); addr++) {
+
+      u8 data = spi->readU8(addr);
+
+      ESP_LOGI(TAG, "Addr[ 0x%02X ] ~~> Data[ 0x%02X ]", addr, data);
+    }
+
+    setPwrLnRjFrq(F60Hz);
+    ESP_LOGI(TAG, "----");
+
+
+    for (u8 addr = 0; addr < (0x0F+1); addr++) {
+
+      u8 data = spi->readU8(addr);
+
+      ESP_LOGI(TAG, "Addr[ 0x%02X ] ~~> Data[ 0x%02X ]", addr, data);
+    }
+
+  }
+
+
+
+
+
+/*
+
+  void MAX31856::setThermocoupleType(ThermocoupleType tc) {
+    return mutex.run ([&]() {
+
+      CR1 reg;
+      reg.value = spi->readU8(CR1::addr);
+
+
+      if (pfr == F60Hz) reg.PWRLNRJ = 0;
+      else              reg.PWRLNRJ = 1;
+
+      spi->writeU8(CR1::addr, reg.value);
+    });
+  }
+
+  ThermocoupleType MAX31856::getThermocoupleType() {
+    return mutex.runReturn<ThermocoupleType> ([&]() {
+
+      CR1 reg;
+      reg.value = spi->readU8(CR1::addr);
+
+      // TODO: Can this be done by casting?
+      if (reg.PWRLNRJ == 0) return F60Hz;
+      else                  return F50Hz;
+    });
+  }
+
+
+
+
+
+*/
+
+
+
+
+
+
+
+
+
+  void MAX31856::setPwrLnRjFrq(PowerlineFrequencyRejection pfr) {
+    return mutex.run ([&]() {
+
+      CR0 reg;
+      reg.value = spi->readU8(CR0::addr);
+
+      reg.PWRLNRJ = pfr;
+
+
+      //if (pfr == F60Hz) reg.PWRLNRJ = 0;
+      //else              reg.PWRLNRJ = 1;
+
+      spi->writeU8(CR0::addr, reg.value);
+    });
+  }
+
+  PowerlineFrequencyRejection MAX31856::getPwrLnRjFrq() {
+    return mutex.runReturn<PowerlineFrequencyRejection> ([&]() {
+
+      CR0 reg;
+      reg.value = spi->readU8(CR0::addr);
+
+      // TODO: Can this be done by casting?
+      //if (reg.PWRLNRJ == 0) return F60Hz;
+      //else                  return F50Hz;
+      return (PowerlineFrequencyRejection)reg.PWRLNRJ;
+    });
+  }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  void MAX31856::mainLoop() {
+    while (true) {
+
+
+
+
+
+      ESP_LOGI(TAG, "LoL");
+
+      vTaskDelay(100 / portTICK_PERIOD_MS);
+    }
+  }
+
+
+  // bool MAX31856::getIRQState() {
+  //   return gpio_get_level((gpio_num_t)ioIRQ);
+  // }
+
+}
diff --git a/CLC-qthing/SiliconTorch/Hardware/MAX31856.hpp b/CLC-qthing/SiliconTorch/Hardware/MAX31856.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..2112de9342883f310965aa3a5947cd1f13582f5f
--- /dev/null
+++ b/CLC-qthing/SiliconTorch/Hardware/MAX31856.hpp
@@ -0,0 +1,257 @@
+#pragma once
+
+// C++ system level
+// #include <functional>
+
+// ESP32 specific
+// #include "esp_log.h"
+
+// project specific
+#include <SpiderLib.hpp>
+
+// qthing stuff
+// #include <qthing>
+
+// misc
+// #include ""
+
+
+namespace MAX31856 {
+
+
+  enum PowerlineFrequencyRejection : u8 {
+    F60Hz = 0,
+    F50Hz = 1
+  };
+
+  enum ThermocoupleType : u8 {
+    B_Type = 0x00,
+    E_TYPE = 0x01,
+    J_TYPE = 0x02,
+    K_TYPE = 0x03,
+    N_TYPE = 0x04,
+    R_TYPE = 0x05,
+    S_TYPE = 0x06,
+    T_TYPE = 0x07
+  };
+
+
+  union CR0 {
+
+    struct __attribute__((packed)) {
+      u8 PWRLNRJ  : 1;  // Power Line Rejection Mode  (0 = 60Hz; 1 = 50Hz)
+      u8 FAULTCLR : 1;
+      u8 FAULT    : 1;
+      u8 CJ       : 1;
+      u8 OCFAULT  : 2;
+      u8 ONESHOT  : 1;
+      u8 CMODE    : 1;
+    };
+
+    u8 value = 0x00;
+
+    static constexpr u8 addr = 0x00;
+
+  };
+
+
+  union CR1 {
+
+    struct __attribute__((packed)) {
+      u8 TCTYPE     : 4;  // see enum: ThermocoupleType
+      u8 AVGSEL     : 3;
+      u8 _reserved_ : 1;
+    };
+
+    u8 value = 0x00;
+
+    static constexpr u8 addr = 0x01;
+
+  };
+
+
+  union MASK {
+
+    struct __attribute__((packed)) {
+    };
+
+    u8 value = 0x00;
+
+    static constexpr u8 addr = 0x02;
+
+  };
+
+
+  union CJHF {
+
+    struct __attribute__((packed)) {
+    };
+
+    u8 value = 0x00;
+
+    static constexpr u8 addr = 0x03;
+
+  };
+
+
+  union CJLF {
+
+    struct __attribute__((packed)) {
+    };
+
+    u8 value = 0x00;
+
+    static constexpr u8 addr = 0x04;
+
+  };
+
+
+  union LTHFTH {
+
+    struct __attribute__((packed)) {
+    };
+
+    u8 value = 0x00;
+
+    static constexpr u8 addr = 0x05;
+
+  };
+
+  union LTHFTL {
+
+    struct __attribute__((packed)) {
+    };
+
+    u8 value = 0x00;
+
+    static constexpr u8 addr = 0x06;
+
+  };
+
+  union LTLFTH {
+
+    struct __attribute__((packed)) {
+    };
+
+    u8 value = 0x00;
+
+    static constexpr u8 addr = 0x07;
+
+  };
+
+  union LTLFTL {
+
+    struct __attribute__((packed)) {
+    };
+
+    u8 value = 0x00;
+
+    static constexpr u8 addr = 0x08;
+
+  };
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/*
+
+  union _ {
+
+    struct __attribute__((packed)) {
+    };
+
+    u8 value = 0x00;
+
+    static constexpr u8 addr = 0x00;
+
+  };
+
+*/
+
+
+
+
+  class SoftSPI {
+    public:
+
+      SoftSPI(u8 miso, u8 mosi, u8 sclk, u8 cs);
+
+      void writeU8(u8 addr, u8 value);
+      u8 readU8(u8 addr);
+
+      const u8 cs;
+      const u8 mosi;
+      const u8 miso;
+      const u8 sclk;
+
+
+    protected:
+
+      void setMOSI(bool value);
+      void setSCLK(bool value);
+      void setCS(bool value);
+
+      bool getMISO();
+
+      SpiderLib::ManagedMutex mutex;
+
+  };
+
+
+
+  class MAX31856 {
+
+    public:
+
+      MAX31856(u8 miso, u8 mosi, u8 sclk, u8 cs);
+
+      // Methods below are semi-public: From a hidden-box model perspective they should be protected
+      // but from my POV they can be public as the user CANNOT misuse them in any way
+      // TODO: elaborate on this…
+
+      u8 readAddr ();
+      u8 writeAddr();
+
+
+      void                        setPwrLnRjFrq(PowerlineFrequencyRejection pfr);  // TODO: Better Name…?!
+      PowerlineFrequencyRejection getPwrLnRjFrq();                                 // TODO: Better Name…?!
+
+
+
+      void mainLoop();
+
+      const u8 cs;
+      const u8 mosi;
+      const u8 miso;
+      const u8 sclk;
+
+    protected:
+
+
+      SoftSPI* spi;
+
+
+
+      // bool getIRQState();
+
+      //void mainLoop();
+
+      SpiderLib::ManagedMutex mutex;
+
+      SpiderLib::Util::LambdaTask* loopTask = NULL;
+
+  };
+
+}