Skip to content

Commit

Permalink
first draft
Browse files Browse the repository at this point in the history
  • Loading branch information
torfmaster committed Aug 27, 2024
1 parent 015b57d commit dbbb03c
Show file tree
Hide file tree
Showing 14 changed files with 602 additions and 68 deletions.
350 changes: 287 additions & 63 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ members = [
"sml-parser",
"app",
"server_shared"
]
, "mqtt_client"]
resolver="2"
1 change: 1 addition & 0 deletions mqtt_client/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/profiles
14 changes: 14 additions & 0 deletions mqtt_client/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[package]
name = "hackdose_mqtt_client"
version = "0.1.0"
edition = "2021"

[dependencies]
hackdose-sml-parser = { version = "0.10.0", path="../sml-parser" }
rumqttc = "0.24.0"
tokio-serial = "5.4.3"
tokio = { version="1.23.0", features=["macros", "rt-multi-thread", "fs"] }
tokio-stream = { version="0.1.11", features=["sync"] }
clap = { version="4.5.16", features=["derive"] }
serde = { version = "1.0.209", features = ["derive"] }
serde_yaml = "0.9.34"
15 changes: 15 additions & 0 deletions mqtt_client/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Hackdose mqtt Client

This little piece of Software lets you publish the data from your Smart Meter to arbtitrary
mqtt brokers (i.e. home assistant).

## Quick Start

- install the cross-compilation target for your architecture
`armv7-unknown-linux-musleabihf`
- compile the binary using `cargo build --target=armv7-unknown-linux-musleabihf --release`
- create a configuration file (see sample) and move it to `/home/pi/hackdose_mqtt_client_config.yaml`
- enable the client in systemd
- copy `hackdose_mqtt.service` to `/etc/systemd/system`
- `systemctl enable hackdose_mqtt.service`
- `systemctl start hackdose_mqtt.service`
10 changes: 10 additions & 0 deletions mqtt_client/hackdose_mqtt.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[Unit]
Description=Hackdose

[Service]
ExecStart=/home/pi/hackdose_mqtt_client --config /home/pi/hackdose_mqtt_client_config.yaml
Restart=on-failure
EnvironmentFile=/etc/environment

[Install]
WantedBy=multi-user.target
13 changes: 13 additions & 0 deletions mqtt_client/hackdose_mqtt_client_config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
ttys_location: /dev/ttyUSB0
mqtt_broker:
host: "192.168.1.1"
port: 1883
username: username
password: password
publications:
- topic: homeassistant/energy_meter/power_in
obis: SumActiveInstantaneousPower
- topic: homeassistant/energy_meter/energy_in
obis: PositiveActiveEnergyTotal
- topic: homeassistant/energy_meter/energy_out
obis: NegativeActiveEnergyTotal
100 changes: 100 additions & 0 deletions mqtt_client/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
use clap::Parser;
use hackdose_sml_parser::application::domain::Scale;
use hackdose_sml_parser::application::obis;
use hackdose_sml_parser::{
application::{
domain::{AnyValue, SmlMessageEnvelope, SmlMessages},
obis::Obis,
},
message_stream::sml_message_stream,
};
use options::Args;
use rumqttc::{v5::mqttbytes::QoS, v5::AsyncClient, v5::MqttOptions};
use std::time::Duration;
use tokio::io::AsyncRead;
use tokio_serial::SerialStream;
use tokio_stream::StreamExt;

mod options;

pub(crate) fn uart_ir_sensor_data_stream(ttys_location: String) -> impl AsyncRead {
let serial = tokio_serial::new(ttys_location, 9600);
let stream = SerialStream::open(&serial).unwrap();
stream
}

#[tokio::main(worker_threads = 2)]
async fn main() {
let args = Args::parse();
let config = args.get_config_file().await;

let uart = uart_ir_sensor_data_stream(config.ttys_location);
let mut stream = sml_message_stream(uart);

let mut mqttoptions = MqttOptions::new(
"rumqtt-async",
config.mqtt_broker.host,
config.mqtt_broker.port,
);
mqttoptions.set_credentials(config.mqtt_broker.username, config.mqtt_broker.password);
mqttoptions.set_keep_alive(Duration::from_secs(5));

let (client, mut eventloop) = AsyncClient::new(mqttoptions, 10);

tokio::spawn(async move {
loop {
let _ = eventloop.poll().await;
}
});

while let Some(event) = stream.next().await {
for publication in &config.publications {
let v = find_value(&event, &publication.obis);
if let Some(v) = v {
let formatted = format!("{:?}", v);
let res = client
.publish(publication.topic.clone(), QoS::AtLeastOnce, false, formatted)
.await;
}
}
}
}

pub fn find_value(messages: &SmlMessages, obis_value: &Obis) -> Option<i32> {
for list in &messages.messages {
match list {
SmlMessageEnvelope::GetOpenResponse(_) => continue,
SmlMessageEnvelope::GetListResponse(body) => {
let values = &body.value_list;
let identified = values
.iter()
.flat_map(|value| {
Obis::from_number(&value.object_name)
.map(|x| (x, value.value.clone(), value.scaler.clone()))
})
.collect::<Vec<_>>();

let usage = identified
.iter()
.find(|(o, _, _)| o == obis_value)
.map(|(_, v, scaler)| v.scale(scaler.unwrap_or(0)));

if let Some(usage) = usage {
if let AnyValue::Signed(value) = usage {
return Some(value as i32);
}
if let AnyValue::Unsigned(value) = usage {
return Some(value as i32);
}
}
}
SmlMessageEnvelope::GetCloseResponse => continue,
}
}
return None;
}

// Todo:
// - cli
// - compile on github
// issue: create configuration file as an alternative for cli options
49 changes: 49 additions & 0 deletions mqtt_client/src/options.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
use hackdose_sml_parser::application::obis::Obis;
use serde::Deserialize;
use serde::Serialize;
use tokio::io::BufReader;
use tokio::fs::File;
use std::collections::HashMap;
use std::path::PathBuf;
use clap::Parser;
use tokio::io::AsyncReadExt;

#[derive(Serialize, Deserialize, Clone)]
pub(crate) struct Configuration {
pub (crate) ttys_location: String,
pub (crate) mqtt_broker: MqttBroker,
pub (crate) publications: Vec<Publication>,
}

#[derive(Serialize, Deserialize, Clone)]
pub(crate) struct MqttBroker {
pub (crate) host: String,
pub (crate) port: u16,
pub (crate) username: String,
pub (crate) password: String,
}

#[derive(Serialize, Deserialize, Clone)]
pub(crate) struct Publication {
pub (crate) topic: String,
pub (crate)obis: Obis,
}

#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
pub (crate) struct Args {
#[arg(short, long, value_name = "FILE")]
config: PathBuf,
}

impl Args {
pub (crate) async fn get_config_file(&self) -> Configuration {
let config = File::open(&self.config).await.unwrap();
let mut config_file = String::new();
BufReader::new(config)
.read_to_string(&mut config_file)
.await
.unwrap();
serde_yaml::from_str::<Configuration>(&config_file).unwrap()
}
}
1 change: 1 addition & 0 deletions sml-parser/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ byteorder = "1.4.3"
enum-iterator = "1.2.0"
lazy_static = "1.4.0"
peg = { version = "0.8.1" }
# peg = { version = "0.8.1", features=["trace"] }
serde = { version="1.0.149", features=["derive"] }
tokio = { version="1.23.0", features=["sync", "io-util", "rt"] }
tokio-stream = { version="0.1.11", features=["sync"] }
Expand Down
12 changes: 12 additions & 0 deletions sml-parser/christian.txt

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion sml-parser/examples/serial-stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use tokio_serial::SerialStream;
use tokio_stream::StreamExt;

pub(crate) fn uart_ir_sensor_data_stream() -> impl AsyncRead {
let ttys_location = "/dev/ttyS0";
let ttys_location = "/dev/ttyUSB0";
let serial = tokio_serial::new(ttys_location, 9600);
let stream = SerialStream::open(&serial).unwrap();
stream
Expand Down
2 changes: 1 addition & 1 deletion sml-parser/src/application/obis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ lazy_static! {
macro_rules! generate_obis {

($( ($x:ident, $y:expr, $l:literal) ),*) => {
#[derive(serde::Serialize, serde::Deserialize, enum_iterator::Sequence, Eq, PartialEq, Hash, Clone)]
#[derive(serde::Serialize, serde::Deserialize, enum_iterator::Sequence, Eq, PartialEq, Hash, Clone, Debug)]
#[non_exhaustive]
pub enum Obis {
$(
Expand Down
99 changes: 97 additions & 2 deletions sml-parser/src/application/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,13 +158,13 @@ peg::parser! {
[0x77]
object_name: string()
status: optional_unsigned()
value_time: string()
(optional_sml_time())
unit: optional_unsigned()
scaler: scaler()
value: value() sml_value_signature()
{
SmlListEntry {
object_name, status, value_time, unit, scaler, value
object_name, status, value_time: vec![], unit, scaler, value
}
}

Expand Down Expand Up @@ -438,6 +438,101 @@ mod test {
assert_eq!(result.is_ok(), true)
}

#[test]
pub fn christian() {
let bytes = vec![
0x1b, 0x1b, 0x1b, 0x1b, 0x01, 0x01, 0x01, 0x01, // header
/* list of 6 */
0x76,
/* tranaction id */ 0x05, 0x03, 0x19, 0xe9, 0x07, 0x62, 0x00, /* */
/* group no */ 0x62, 0x00,
/* list of 2 */ 0x72,
/* */ 0x63, 0x01, 0x01,
/* list of 6 */ 0x76,
/* */ 0x01,
/* */ 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
/* */ 0x05, 0x01, 0x08, 0xa3, 0x03,
/* */ 0x0b, 0x0a, 0x01, 0x45, 0x4d, 0x48, 0x00, 0x00, 0x92, 0xad, 0xeb,
/* */ 0x72,
/* */ 0x62, 0x01,
/* */ 0x65, 0x06, 0x95, 0x89, 0x1d,
/* */ 0x62, 0x01,
/* */ 0x63, 0x32, 0x0c,
/* */ 0x00,
/* */ 0x76,
/* */ 0x05, 0x03, 0x19, 0xe9, 0x08,
/* */ 0x62, 0x00,
/* */ 0x62, 0x00,
/* */ 0x72,
/* */ 0x63, 0x07, 0x01,
/* */ 0x77,
/* */ 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
/* */ 0x0b, 0x0a, 0x01, 0x45, 0x4d, 0x48, 0x00, 0x00, 0x92, 0xad, 0xeb,
/* */ 0x07, 0x01, 0x00, 0x62, 0x0a, 0xff, 0xff,
/* */ 0x72,
/* */0x62, 0x01,
/* */0x65, 0x06, 0x95, 0x89, 0x1d,
/* */ 0x78,
/* */ 0x77,
/* */ 0x07, 0x01, 0x00, 0x60, 0x32, 0x01,
/* */ 0x01,
/* */ 0x01,
/* */ 0x01,
/* */ 0x01,
/* */ 0x01,
/* */ 0x04, 0x45, 0x4d, 0x48,
/* */ 0x01,
/* */ 0x77,
/* */ 0x07, 0x01, 0x00, 0x60, 0x01, 0x00, 0xff,
/* */ 0x01,
/* */ 0x01,
/* */ 0x01,
/* */ 0x01,
/* */ 0x0b, 0x0a, 0x01, 0x45, 0x4d, 0x48, 0x00, 0x00, 0x92, 0xad, 0xeb,
/* */ 0x01,
/* */ 0x77,
/* */ 0x07, 0x01, 0x00, 0x01, 0x08, 0x00, 0xff,
/* */ 0x64, 0x1c, 0xc9, 0x04,
/* */ 0x72,
/* */ 0x62, 0x01,
/* */ 0x65, 0x06, 0x95, 0x89, 0x1d,
/* */ 0x62, 0x1e,
/* */ 0x52, 0xff,
/* */ 0x69, 0x00, 0x00, 0x00,
/* */ 0x00,
/* */ 0x01, 0xb1, 0xe8, 0x7b, 0x01, 0x77, 0x07, 0x01, 0x00, 0x02, 0x08, 0x00, 0xff,
0x01, 0x72, 0x62, 0x01, 0x65, 0x06, 0x95, 0x89, 0x1d, 0x62, 0x1e, 0x52, 0xff, 0x69,
0x00, 0x00, 0x00, 0x00, 0x03, 0xaf, 0xec, 0xc2, 0x01, 0x77, 0x07, 0x01, 0x00, 0x24,
0x07, 0x00, 0xff, 0x01, 0x72, 0x62, 0x01, 0x65, 0x06, 0x95, 0x89, 0x1d, 0x62, 0x1b,
0x52, 0x00, 0x55, 0x00, 0x00, 0x00, 0x7e, 0x01, 0x77, 0x07, 0x01, 0x00, 0x38, 0x07,
0x00, 0xff, 0x01, 0x72, 0x62, 0x01, 0x65, 0x06, 0x95, 0x89, 0x1d, 0x62, 0x1b, 0x52,
0x00, 0x55, 0x00, 0x00, 0x00, 0x3c, 0x01, 0x77, 0x07, 0x01, 0x00, 0x4c, 0x07, 0x00,
0xff, 0x01, 0x72, 0x62, 0x01, 0x65, 0x06, 0x95, 0x89, 0x1d, 0x62, 0x1b, 0x52, 0x00,
0x55, 0xff, 0xff, 0xfd, 0x45, 0x01, 0x77, 0x07, 0x01, 0x00, 0x10, 0x07, 0x00, 0xff,
0x01, 0x72, 0x62, 0x01, 0x65, 0x06, 0x95, 0x89, 0x1d, 0x62, 0x1b, 0x52, 0x00, 0x55,
0xff, 0xff, 0xfe, 0x00, 0x01, 0x01, 0x01, 0x63, 0xd7, 0xa3, 0x00, 0x76, 0x05, 0x03,
0x19, 0xe9, 0x09, 0x62, 0x00, 0x62, 0x00, 0x72, 0x63, 0x02, 0x01, 0x71, 0x01, 0x63,
0xa2, 0x5d, 0x00, 0x00, 0x00, 0x1b, 0x1b, 0x1b, 0x1b, 0x1a, 0x02, 0x6b, 0xb6,
];
let result = dbg!(sml_parser::sml_messages(&bytes));

assert_eq!(result.is_ok(), true)
}

// 0x1b, 0x1b, 0x1b, 0x1b, 0x01, 0x01, 0x01, 0x01, 0x76, 0x05, 0x03, 0x19, 0xe9, 0x0a, 0x62, 0x00, 0x62, 0x00, 0x72, 0x63, 0x01, 0x01, 0x76, 0x01, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x05, 0x01, 0x08, 0xa3, 0x04, 0x0b, 0x0a, 0x01, 0x45, 0x4d, 0x48, 0x00, 0x00, 0x92, 0xad, 0xeb, 0x72, 0x62, 0x01, 0x65, 0x06, 0x95, 0x89, 0x1e, 0x62, 0x01, 0x63, 0xf3, 0x16, 0x00, 0x76, 0x05, 0x03, 0x19, 0xe9, 0x0b, 0x62, 0x00, 0x62, 0x00, 0x72, 0x63, 0x07, 0x01, 0x77, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0b, 0x0a, 0x01, 0x45, 0x4d, 0x48, 0x00, 0x00, 0x92, 0xad, 0xeb, 0x07, 0x01, 0x00, 0x62, 0x0a, 0xff, 0xff, 0x72, 0x62, 0x01, 0x65, 0x06, 0x95, 0x89, 0x1e, 0x78, 0x77, 0x07, 0x01, 0x00, 0x60, 0x32, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x45, 0x4d, 0x48, 0x01, 0x77, 0x07, 0x01, 0x00, 0x60, 0x01, 0x00, 0xff, 0x01, 0x01, 0x01, 0x01, 0x0b, 0x0a, 0x01, 0x45, 0x4d, 0x48, 0x00, 0x00, 0x92, 0xad, 0xeb, 0x01, 0x77, 0x07, 0x01, 0x00, 0x01, 0x08, 0x00, 0xff, 0x64, 0x1c, 0xc9, 0x04, 0x72, 0x62, 0x01, 0x65, 0x06, 0x95, 0x89, 0x1e, 0x62, 0x1e, 0x52, 0xff, 0x69, 0x00, 0x00, 0x00, 0x00, 0x01, 0xb1, 0xe8, 0x7b, 0x01, 0x77, 0x07, 0x01, 0x00, 0x02, 0x08, 0x00, 0xff, 0x01, 0x72, 0x62, 0x01, 0x65, 0x06, 0x95, 0x89, 0x1e, 0x62, 0x1e, 0x52, 0xff, 0x69, 0x00, 0x00, 0x00, 0x00, 0x03, 0xaf, 0xec, 0xc3, 0x01, 0x77, 0x07, 0x01, 0x00, 0x24, 0x07, 0x00, 0xff, 0x01, 0x72, 0x62, 0x01, 0x65, 0x06, 0x95, 0x89, 0x1e, 0x62, 0x1b, 0x52, 0x00, 0x55, 0x00, 0x00, 0x00, 0x7e, 0x01, 0x77, 0x07, 0x01, 0x00, 0x38, 0x07, 0x00, 0xff, 0x01, 0x72, 0x62, 0x01, 0x65, 0x06, 0x95, 0x89, 0x1e, 0x62, 0x1b, 0x52, 0x00, 0x55, 0x00, 0x00, 0x00, 0x3c, 0x01, 0x77, 0x07, 0x01, 0x00, 0x4c, 0x07, 0x00, 0xff, 0x01, 0x72, 0x62, 0x01, 0x65, 0x06, 0x95, 0x89, 0x1e, 0x62, 0x1b, 0x52, 0x00, 0x55, 0xff, 0xff, 0xfd, 0x0c, 0x01, 0x77, 0x07, 0x01, 0x00, 0x10, 0x07, 0x00, 0xff, 0x01, 0x72, 0x62, 0x01, 0x65, 0x06, 0x95, 0x89, 0x1e, 0x62, 0x1b, 0x52, 0x00, 0x55, 0xff, 0xff, 0xfd, 0xc8, 0x01, 0x01, 0x01, 0x63, 0xb0, 0x4d, 0x00, 0x76, 0x05, 0x03, 0x19, 0xe9, 0x0c, 0x62, 0x00, 0x62, 0x00, 0x72, 0x63, 0x02, 0x01, 0x71, 0x01, 0x63, 0x66, 0x56, 0x00, 0x00, 0x00, 0x1b, 0x1b, 0x1b, 0x1b, 0x1a, 0x02, 0x95, 0x36, 0x

#[test]
pub fn christian2() {
let bytes = vec![
0x1b, 0x1b, 0x1b, 0x1b, 0x01, 0x01, 0x01, 0x01, 0x76, 0x05, 0x03, 0x19, 0xe9, 0x0a, 0x62, 0x00, 0x62, 0x00, 0x72, 0x63, 0x01, 0x01, 0x76, 0x01, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x05, 0x01, 0x08, 0xa3, 0x04, 0x0b, 0x0a, 0x01, 0x45, 0x4d, 0x48, 0x00, 0x00, 0x92, 0xad, 0xeb, 0x72, 0x62, 0x01, 0x65, 0x06, 0x95, 0x89, 0x1e, 0x62, 0x01, 0x63, 0xf3, 0x16, 0x00, 0x76, 0x05, 0x03, 0x19, 0xe9, 0x0b, 0x62, 0x00, 0x62, 0x00, 0x72, 0x63, 0x07, 0x01, 0x77, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0b, 0x0a, 0x01, 0x45, 0x4d, 0x48, 0x00, 0x00, 0x92, 0xad, 0xeb, 0x07, 0x01, 0x00, 0x62, 0x0a, 0xff, 0xff, 0x72, 0x62, 0x01, 0x65, 0x06, 0x95, 0x89, 0x1e, 0x78, 0x77, 0x07, 0x01, 0x00, 0x60, 0x32, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x45, 0x4d, 0x48, 0x01, 0x77, 0x07, 0x01, 0x00, 0x60, 0x01, 0x00, 0xff, 0x01, 0x01, 0x01, 0x01, 0x0b, 0x0a, 0x01, 0x45, 0x4d, 0x48, 0x00, 0x00, 0x92, 0xad, 0xeb, 0x01, 0x77, 0x07, 0x01, 0x00, 0x01, 0x08, 0x00, 0xff, 0x64, 0x1c, 0xc9, 0x04, 0x72, 0x62, 0x01, 0x65, 0x06, 0x95, 0x89, 0x1e, 0x62, 0x1e, 0x52, 0xff, 0x69, 0x00, 0x00, 0x00, 0x00, 0x01, 0xb1, 0xe8, 0x7b, 0x01, 0x77, 0x07, 0x01, 0x00, 0x02, 0x08, 0x00, 0xff, 0x01, 0x72, 0x62, 0x01, 0x65, 0x06, 0x95, 0x89, 0x1e, 0x62, 0x1e, 0x52, 0xff, 0x69, 0x00, 0x00, 0x00, 0x00, 0x03, 0xaf, 0xec, 0xc3, 0x01, 0x77, 0x07, 0x01, 0x00, 0x24, 0x07, 0x00, 0xff, 0x01, 0x72, 0x62, 0x01, 0x65, 0x06, 0x95, 0x89, 0x1e, 0x62, 0x1b, 0x52, 0x00, 0x55, 0x00, 0x00, 0x00, 0x7e, 0x01, 0x77, 0x07, 0x01, 0x00, 0x38, 0x07, 0x00, 0xff, 0x01, 0x72, 0x62, 0x01, 0x65, 0x06, 0x95, 0x89, 0x1e, 0x62, 0x1b, 0x52, 0x00, 0x55, 0x00, 0x00, 0x00, 0x3c, 0x01, 0x77, 0x07, 0x01, 0x00, 0x4c, 0x07, 0x00, 0xff, 0x01, 0x72, 0x62, 0x01, 0x65, 0x06, 0x95, 0x89, 0x1e, 0x62, 0x1b, 0x52, 0x00, 0x55, 0xff, 0xff, 0xfd, 0x0c, 0x01, 0x77, 0x07, 0x01, 0x00, 0x10, 0x07, 0x00, 0xff, 0x01, 0x72, 0x62, 0x01, 0x65, 0x06, 0x95, 0x89, 0x1e, 0x62, 0x1b, 0x52, 0x00, 0x55, 0xff, 0xff, 0xfd, 0xc8, 0x01, 0x01, 0x01, 0x63, 0xb0, 0x4d, 0x00, 0x76, 0x05, 0x03, 0x19, 0xe9, 0x0c, 0x62, 0x00, 0x62, 0x00, 0x72, 0x63, 0x02, 0x01, 0x71, 0x01, 0x63, 0x66, 0x56, 0x00, 0x00, 0x00, 0x1b, 0x1b, 0x1b, 0x1b, 0x1a, 0x02, 0x95, 0x36

];
let result = dbg!(sml_parser::sml_messages(&bytes));

assert_eq!(result.is_ok(), true)
}


#[test]
pub fn reads_8_bit_signed() {
let bytes = vec![0x52, 0x02];
Expand Down

0 comments on commit dbbb03c

Please sign in to comment.