-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
015b57d
commit dbbb03c
Showing
14 changed files
with
602 additions
and
68 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,5 +4,5 @@ members = [ | |
"sml-parser", | ||
"app", | ||
"server_shared" | ||
] | ||
, "mqtt_client"] | ||
resolver="2" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
/profiles |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters