tanuki-bthome 0.0.1

BTHome adapter for Tanuki
Documentation
use bytes::Buf;
use tanuki_common::capabilities::sensor::SensorValue;

#[derive(Debug, PartialEq)]
pub enum Object {
    Battery(f32),
    Temperature(f32),
    Humidity(f32),
    Voltage(f32),
    Power(bool),
    Rssi(i16),
}

impl Object {
    pub fn topic(&self) -> &'static str {
        match self {
            Object::Battery(_) => "battery",
            Object::Temperature(_) => "temperature",
            Object::Humidity(_) => "humidity",
            Object::Voltage(_) => "voltage",
            Object::Power(_) => "power",
            Object::Rssi(_) => "rssi",
        }
    }

    pub fn unit(&self) -> &'static str {
        match self {
            Object::Battery(_) => "%",
            Object::Temperature(_) => "°C",
            Object::Humidity(_) => "%",
            Object::Voltage(_) => "V",
            Object::Power(_) => "",
            Object::Rssi(_) => "dBm",
        }
    }

    pub fn value(&self) -> SensorValue {
        match self {
            Object::Battery(v) => SensorValue::Number(*v),
            Object::Temperature(v) => SensorValue::Number(*v),
            Object::Humidity(v) => SensorValue::Number(*v),
            Object::Voltage(v) => SensorValue::Number(*v),
            Object::Power(v) => SensorValue::Boolean(*v),
            Object::Rssi(v) => SensorValue::Number(*v as f32),
        }
    }
}

impl Object {
    pub fn decode(mut data: impl Buf) -> Vec<Object> {
        data.copy_to_bytes(3);

        let mut out = vec![];

        while data.has_remaining() {
            let header = data.get_u8();
            let len = header & 0b11111;
            let ty = header >> 5;
            tracing::trace!("len: {}, ty: {}", len, ty);

            let mut data = data.copy_to_bytes(len as usize);
            tracing::trace!("{:#02x?}", &data[..]);

            let object_id = data.get_u8();
            let value = match (len, ty) {
                (2, 0) => data.get_u8() as f32,
                (3, 0) => data.get_u16_le() as f32,
                (2, 1) => data.get_i8() as f32,
                (3, 1) => data.get_i16_le() as f32,
                (5, 2) => data.get_f32_le(),
                _ => {
                    tracing::warn!("unimplemented length/type combo: len={}, type={}", len, ty);
                    continue;
                }
            };

            let obj = match object_id {
                0x01 => Object::Battery(value),
                0x02 => Object::Temperature(value * 0.01),
                0x03 => Object::Humidity(value * 0.01),
                0x0c => Object::Voltage(value * 0.001),
                0x10 => Object::Power(value > 0.),
                _ => {
                    tracing::warn!("unknown object id: {:#02x}", object_id);
                    continue;
                }
            };

            out.push(obj);
        }

        out
    }
}