smart_meter 0.2.0

A library for reading smart meters.
Documentation
use std::error::Error;
use std::env;
use std::net::TcpStream;

use either::Either;
use hex::FromHex;
use serialport::{Parity, DataBits, StopBits};

use dlms_cosem::{ObisCode, Data, DateTime, Dlms, Unit};
use smart_meter::SmartMeter;

fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
  let url_or_path = env::args().nth(1).unwrap_or("/dev/serial0".into());
  let key = env::args().nth(2).expect("No key provided");
  let key = <[u8; 16]>::from_hex(key).expect("Invalid key format");

  let stream = if url_or_path.contains(":") {
    Either::Left(TcpStream::connect(url_or_path)?)
  } else {
    Either::Right(serialport::new(url_or_path, 2400)
      .parity(Parity::Even)
      .data_bits(DataBits::Eight)
      .stop_bits(StopBits::One)
      .open()?)
  };

  let dlms = Dlms::new(key);

  let mut smart_meter = SmartMeter::new(stream, dlms);

  loop {
    let mut obis = smart_meter.next().unwrap()?;

    let convert_date_time = |value| match value {
      Data::OctetString(value) => Data::DateTime(DateTime::parse(&value).unwrap().1),
      value => value,
    };
    obis.convert(&ObisCode::new(0, 0, 1, 0, 0, 255), convert_date_time);

    let convert_string = |value| match value {
      Data::OctetString(value) => Data::Utf8String(String::from_utf8(value).unwrap()),
      value => value,
    };
    obis.convert(&ObisCode::new(0, 0, 42, 0, 0, 255), convert_string);
    obis.convert(&ObisCode::new(0, 0, 96, 1, 0, 255), convert_string);

    for (key, reg) in obis.iter() {
      print!("{:<16} ", format!("{}:", key));

      fn format_value(value: &Data, unit: Option<&Unit>) -> String {
        let value = match value {
          Data::Utf8String(s) => format!("{}", s),
          Data::DateTime(date_time) => format!("{}", date_time),
          Data::Float32(n) => format!("{}", n),
          Data::Float64(n) => format!("{}", n),
          Data::LongUnsigned(n) => format!("{}", n),
          Data::DoubleLongUnsigned(n) => format!("{}", n),
          data => format!("{:?}", data),
        };

        if let Some(unit) = unit.and_then(|u| u.as_str()) {
          format!("{} {}", value, unit)
        } else {
          value
        }
      }

      println!("{}", format_value(reg.value(), reg.unit()));
    }

    println!();
  }
}