Zum Inhalt

sht31_th.tc

SHT31 Temp & Humidity — tc2plugin PoC test variant (T+H only)

Source on GitHub

// SHT31 Temp & Humidity — tc2plugin PoC test variant (T+H only)
// Trimmed copy of sht31.tc: dewpoint/abshumi REMOVED because they use
// log()/exp() (jt-routed transcendentals). On real HW the plugin's
// jt[] binding for logf/expf wild-jumps (MMU entry fault @0x428663cc,
// inside tc_sht_calc_dewpoint) — a separate known issue. Soft-float
// (+ - * / and (float) casts) is proven working live. Canonical
// sht31.tc is left intact.

#define SHT_ADDR1  0x44
#define SHT_ADDR2  0x45

float sht_temp = 0.0;
float sht_humi = 0.0;
int sht_ok = 0;
int sht_addr = 0;
int sht_bus = 0;
char sht_lbl[32];

// Shared buffer for I2C data
char sht_data[6];

// CRC-8 for SHT31 (polynomial 0x31)
int sht_crc8(int start, int len) {
    int crc = 0xFF;
    int i = 0;
    while (i < len) {
        crc = crc ^ sht_data[start + i];
        int bit = 0;
        while (bit < 8) {
            if (crc & 0x80) {
                crc = (crc << 1) ^ 0x31;
            } else {
                crc = crc << 1;
            }
            crc = crc & 0xFF;
            bit++;
        }
        i++;
    }
    return crc;
}

// Scan both buses and addresses using Tasmota's I2C claiming
int sht_scan() {
    int bus = 0;
    while (bus < 2) {
        if (i2cSetDevice(SHT_ADDR1, bus)) {
            sht_addr = SHT_ADDR1;
            sht_bus = bus;
            i2cSetActiveFound(sht_addr, "SHT3X", sht_bus);
            return 1;
        }
        if (i2cSetDevice(SHT_ADDR2, bus)) {
            sht_addr = SHT_ADDR2;
            sht_bus = bus;
            i2cSetActiveFound(sht_addr, "SHT3X", sht_bus);
            return 1;
        }
        bus++;
    }
    return 0;
}

void EverySecond() {
    if (!sht_addr) {
        if (!sht_scan()) {
            sht_ok = 0;
            return;
        }
    }

    // Send measurement command: clock stretching, high repeatability (0x2C06)
    if (!i2cWrite8(sht_addr, 0x2C, 0x06, sht_bus)) {
        sht_ok = 0;
        sht_addr = 0;  // force rescan next time
        return;
    }

    // SHT31 needs ~15ms for high repeatability measurement
    delay(30);

    // Read 6 bytes: [temp_msb, temp_lsb, temp_crc, humi_msb, humi_lsb, humi_crc]
    if (!i2cRead0(sht_addr, sht_data, 6, sht_bus)) {
        sht_ok = 0;
        sht_addr = 0;
        return;
    }

    // Verify CRC for temperature (bytes 0-1, CRC in byte 2)
    if (sht_crc8(0, 2) != sht_data[2]) {
        sht_ok = 0;
        return;
    }

    // Verify CRC for humidity (bytes 3-4, CRC in byte 5)
    if (sht_crc8(3, 2) != sht_data[5]) {
        sht_ok = 0;
        return;
    }

    // Temperature: -45 + 175 * raw / 65535
    int raw_t = (sht_data[0] << 8) | sht_data[1];
    sht_temp = -45.0 + 175.0 * (float)raw_t / 65535.0;

    // Humidity: 100 * raw / 65535
    int raw_h = (sht_data[3] << 8) | sht_data[4];
    sht_humi = 100.0 * (float)raw_h / 65535.0;

    sht_ok = 1;
}

void sht_web_label(int idx) {
    char vt[32];
    LGetString(idx, sht_lbl);
    sprintf(vt, "{s}SHT31 %s{m}", sht_lbl);
    webSend(vt);
}

void WebCall() {
    char buf[32];
    if (sht_ok) {
        sht_web_label(0);
        sprintf(buf, "%.1f &deg;C{e}", sht_temp);
        webSend(buf);
        sht_web_label(1);
        sprintf(buf, "%.1f %{e}", sht_humi);
        webSend(buf);
    } else {
        webSend("{s}SHT31{m}not found{e}");
    }
}

void JsonCall() {
    if (!sht_ok) return;
    char buf[96];
    sprintf(buf, ",\"SHT3X\":{\"Temperature\":%.1f", sht_temp);
    responseAppend(buf);
    sprintf(buf, ",\"Humidity\":%.1f}", sht_humi);
    responseAppend(buf);
}

// Called before VM stops — release I2C address so driver can restart
void OnExit() {
    if (sht_addr) {
        I2cResetActive(sht_addr, sht_bus);
        sht_addr = 0;
    }
}

// Init contract (tc2plugin -> pFUNC_INIT): return > 0 on success,
// 0 on failure. The translator wires this return value to the
// plugin `initialized` flag at every return path. Returning 0 when
// no sensor is found lets the loader retry init later instead of
// marking a missing sensor as up.
int main() {
    sht_ok = 0;
    sht_addr = 0;

    if (sht_scan()) {
        addLog("SHT3X found at 0x%x on bus %d", sht_addr, sht_bus);
        return 1;
    }
    addLog("SHT3X not found on any bus");
    return 0;
}