#ifndef CONFIG_TARGET_ESP01
#include <Arduino.h>
#endif
#include <homekit/logging.h>
#include "temphum.h"

namespace homekit::temphum {

void Sensor::setup() const {
#ifndef CONFIG_TARGET_ESP01
    pinMode(CONFIG_SDA_GPIO, OUTPUT);
    pinMode(CONFIG_SCL_GPIO, OUTPUT);

    Wire.begin(CONFIG_SDA_GPIO, CONFIG_SCL_GPIO);
#else
    Wire.begin();
#endif
}

void Sensor::writeCommand(int reg) const {
    Wire.beginTransmission(dev_addr);
    Wire.write(reg);
    Wire.endTransmission();
    delay(500); // wait for the measurement to be ready
}

SensorData Si7021::read() {
    uint8_t error = 0;
    writeCommand(0xf3); // command to measure temperature
    Wire.requestFrom(dev_addr, 2);
    if (Wire.available() < 2) {
        PRINTLN("Si7021: 0xf3: could not read 2 bytes");
        error = 1;
    }
    uint16_t temp_raw = Wire.read() << 8 | Wire.read();
    double temperature = ((175.72 * temp_raw) / 65536.0) - 46.85;

    writeCommand(0xf5); // command to measure humidity
    Wire.requestFrom(dev_addr, 2);
    if (Wire.available() < 2) {
        PRINTLN("Si7021: 0xf5: could not read 2 bytes");
        error = 1;
    }
    uint16_t hum_raw = Wire.read() << 8 | Wire.read();
    double humidity = ((125.0 * hum_raw) / 65536.0) - 6.0;

    return {
        .error = error,
        .temp = temperature,
        .rh = humidity
    };
}

SensorData DHT12::read() {
    SensorData sd;
    byte raw[5];
    sd.error = 1;

    writeCommand(0);
    Wire.requestFrom(dev_addr, 5);

    if (Wire.available() < 5) {
        PRINTLN("DHT12: could not read 5 bytes");
        goto end;
    }

    // Parse the received data
    for (uint8_t i = 0; i < 5; i++)
        raw[i] = Wire.read();

    if (((raw[0] + raw[1] + raw[2] + raw[3]) & 0xff) != raw[4]) {
        PRINTLN("DHT12: checksum error");
        goto end;
    }

    // Calculate temperature and humidity values
    sd.temp = raw[2] + (raw[3] & 0x7f) * 0.1;
    if (raw[3] & 0x80)
        sd.temp *= -1;

    sd.rh = raw[0] + raw[1] * 0.1;

    sd.error = 0;

end:
    return sd;
}

}
