Initial commit
This commit is contained in:
commit
46dc6ffb71
|
@ -0,0 +1,4 @@
|
||||||
|
[build]
|
||||||
|
|
||||||
|
[target.armv7-unknown-linux-gnueabihf]
|
||||||
|
linker = "arm-linux-gnueabihf-gcc"
|
|
@ -0,0 +1 @@
|
||||||
|
/target
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,17 @@
|
||||||
|
[package]
|
||||||
|
name = "rusty_home"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
serde_json = { version = "1.0" }
|
||||||
|
reqwest = { version = "0.11", features = ["json", "native-tls-vendored"] }
|
||||||
|
influxdb = { version = "0.7.1", features = ["derive"] }
|
||||||
|
futures = { version = "0.3.30" }
|
||||||
|
tokio = { version = "1.36.0", features = ["full"] }
|
||||||
|
chrono = { version = "0.4.33" }
|
||||||
|
clap = { version = "4.4.11", features = ["derive"] }
|
||||||
|
handlebars = { version = "5.1.0" }
|
|
@ -0,0 +1,255 @@
|
||||||
|
{
|
||||||
|
"influx": {
|
||||||
|
"url": "http://localhost:8086",
|
||||||
|
"database": "rust",
|
||||||
|
"username": "8< snip >8",
|
||||||
|
"password": "8< snip >8"
|
||||||
|
},
|
||||||
|
"vars": {
|
||||||
|
"site_id": "8< snip >8",
|
||||||
|
"api_key": "8< snip >8"
|
||||||
|
},
|
||||||
|
"configs": [
|
||||||
|
{
|
||||||
|
"url": "https://pass.telekom.de/api/service/generic/v1/status",
|
||||||
|
"values": [
|
||||||
|
{
|
||||||
|
"path": [
|
||||||
|
"usedVolume"
|
||||||
|
],
|
||||||
|
"tags": {
|
||||||
|
"system": "internet_fraenk",
|
||||||
|
"metric": "used_volume",
|
||||||
|
"unit": "B"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://monitoringapi.solaredge.com/site/{{site_id}}/overview?api_key={{api_key}}",
|
||||||
|
"values": [
|
||||||
|
{
|
||||||
|
"path": [
|
||||||
|
"overview",
|
||||||
|
"lifeTimeData",
|
||||||
|
"energy"
|
||||||
|
],
|
||||||
|
"tags": {
|
||||||
|
"system": "photovoltaik",
|
||||||
|
"metric": "liftimeEnergyProduced",
|
||||||
|
"unit": "Wh"
|
||||||
|
},
|
||||||
|
"measurement": "environmental_benefits"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": [
|
||||||
|
"overview",
|
||||||
|
"lastYearData",
|
||||||
|
"energy"
|
||||||
|
],
|
||||||
|
"tags": {
|
||||||
|
"system": "photovoltaik",
|
||||||
|
"metric": "current_year_production",
|
||||||
|
"unit": "Wh"
|
||||||
|
},
|
||||||
|
"measurement": "environmental_benefits"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": [
|
||||||
|
"overview",
|
||||||
|
"lastMonthData",
|
||||||
|
"energy"
|
||||||
|
],
|
||||||
|
"tags": {
|
||||||
|
"system": "photovoltaik",
|
||||||
|
"metric": "current_month_production",
|
||||||
|
"unit": "Wh"
|
||||||
|
},
|
||||||
|
"measurement": "environmental_benefits"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": [
|
||||||
|
"overview",
|
||||||
|
"lastDayData",
|
||||||
|
"energy"
|
||||||
|
],
|
||||||
|
"tags": {
|
||||||
|
"system": "photovoltaik",
|
||||||
|
"metric": "current_day_production",
|
||||||
|
"unit": "Wh"
|
||||||
|
},
|
||||||
|
"measurement": "environmental_benefits"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://monitoringapi.solaredge.com/site/{{site_id}}/storageData?api_key={{api_key}}&startTime={{day_start}}&endTime={{day_end}}",
|
||||||
|
"values": [
|
||||||
|
{
|
||||||
|
"path": [
|
||||||
|
"storageData",
|
||||||
|
"batteries",
|
||||||
|
0,
|
||||||
|
"telemetries",
|
||||||
|
-1,
|
||||||
|
"power"
|
||||||
|
],
|
||||||
|
"tags": {
|
||||||
|
"system": "photovoltaik",
|
||||||
|
"metric": "battery_power",
|
||||||
|
"unit": "W"
|
||||||
|
},
|
||||||
|
"measurement": "environmental_benefits"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": [
|
||||||
|
"storageData",
|
||||||
|
"batteries",
|
||||||
|
0,
|
||||||
|
"telemetries",
|
||||||
|
-1,
|
||||||
|
"lifeTimeEnergyDischarged"
|
||||||
|
],
|
||||||
|
"tags": {
|
||||||
|
"system": "photovoltaik",
|
||||||
|
"metric": "battery_lifetime_energy_discharged",
|
||||||
|
"unit": "Wh"
|
||||||
|
},
|
||||||
|
"measurement": "environmental_benefits"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": [
|
||||||
|
"storageData",
|
||||||
|
"batteries",
|
||||||
|
0,
|
||||||
|
"telemetries",
|
||||||
|
-1,
|
||||||
|
"lifeTimeEnergyCharged"
|
||||||
|
],
|
||||||
|
"tags": {
|
||||||
|
"system": "photovoltaik",
|
||||||
|
"metric": "battery_lifetime_energy_charged",
|
||||||
|
"unit": "Wh"
|
||||||
|
},
|
||||||
|
"measurement": "environmental_benefits"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": [
|
||||||
|
"storageData",
|
||||||
|
"batteries",
|
||||||
|
0,
|
||||||
|
"telemetries",
|
||||||
|
-1,
|
||||||
|
"batteryPercentageState"
|
||||||
|
],
|
||||||
|
"tags": {
|
||||||
|
"system": "photovoltaik",
|
||||||
|
"metric": "battery_charge_state",
|
||||||
|
"unit": "%"
|
||||||
|
},
|
||||||
|
"measurement": "environmental_benefits"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": [
|
||||||
|
"storageData",
|
||||||
|
"batteries",
|
||||||
|
0,
|
||||||
|
"telemetries",
|
||||||
|
-1,
|
||||||
|
"fullPackEnergyAvailable"
|
||||||
|
],
|
||||||
|
"tags": {
|
||||||
|
"system": "photovoltaik",
|
||||||
|
"metric": "battery_full_charge_energy",
|
||||||
|
"unit": "Wh"
|
||||||
|
},
|
||||||
|
"measurement": "environmental_benefits"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": [
|
||||||
|
"storageData",
|
||||||
|
"batteries",
|
||||||
|
0,
|
||||||
|
"telemetries",
|
||||||
|
-1,
|
||||||
|
"internalTemp"
|
||||||
|
],
|
||||||
|
"tags": {
|
||||||
|
"system": "photovoltaik",
|
||||||
|
"metric": "battery_temp",
|
||||||
|
"unit": "C"
|
||||||
|
},
|
||||||
|
"measurement": "environmental_benefits"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://monitoringapi.solaredge.com/site/{{site_id}}/envBenefits?api_key={{api_key}}",
|
||||||
|
"values": [
|
||||||
|
{
|
||||||
|
"path": [
|
||||||
|
"envBenefits",
|
||||||
|
"lightBulbs"
|
||||||
|
],
|
||||||
|
"tags": {
|
||||||
|
"system": "photovoltaik",
|
||||||
|
"metric": "lightBulbs",
|
||||||
|
"unit": "pieces"
|
||||||
|
},
|
||||||
|
"measurement": "environmental_benefits"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": [
|
||||||
|
"envBenefits",
|
||||||
|
"treesPlanted"
|
||||||
|
],
|
||||||
|
"tags": {
|
||||||
|
"system": "photovoltaik",
|
||||||
|
"metric": "trees_planted",
|
||||||
|
"unit": "pieces"
|
||||||
|
},
|
||||||
|
"measurement": "environmental_benefits"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": [
|
||||||
|
"envBenefits",
|
||||||
|
"gasEmissionSaved",
|
||||||
|
"nox"
|
||||||
|
],
|
||||||
|
"tags": {
|
||||||
|
"system": "photovoltaik",
|
||||||
|
"metric": "nox_saved",
|
||||||
|
"unit": "kg"
|
||||||
|
},
|
||||||
|
"measurement": "environmental_benefits"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": [
|
||||||
|
"envBenefits",
|
||||||
|
"gasEmissionSaved",
|
||||||
|
"so2"
|
||||||
|
],
|
||||||
|
"tags": {
|
||||||
|
"system": "photovoltaik",
|
||||||
|
"metric": "so2_saved",
|
||||||
|
"unit": "kg"
|
||||||
|
},
|
||||||
|
"measurement": "environmental_benefits"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": [
|
||||||
|
"envBenefits",
|
||||||
|
"gasEmissionSaved",
|
||||||
|
"co2"
|
||||||
|
],
|
||||||
|
"tags": {
|
||||||
|
"system": "photovoltaik",
|
||||||
|
"metric": "co2_saved",
|
||||||
|
"unit": "kg"
|
||||||
|
},
|
||||||
|
"measurement": "environmental_benefits"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,116 @@
|
||||||
|
use chrono::{DateTime, Utc, Timelike, Days};
|
||||||
|
use influxdb::{Client, Timestamp, WriteQuery};
|
||||||
|
use influxdb::InfluxDbWriteable;
|
||||||
|
use clap::Parser;
|
||||||
|
use handlebars::Handlebars;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::fs::File;
|
||||||
|
|
||||||
|
#[derive(InfluxDbWriteable)]
|
||||||
|
struct InfluxData {
|
||||||
|
time: DateTime<Utc>,
|
||||||
|
value: f64,
|
||||||
|
#[influxdb(tag)] system: String,
|
||||||
|
#[influxdb(tag)] metric: String,
|
||||||
|
#[influxdb(tag)] unit: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Parser)]
|
||||||
|
#[command(author, version, about = "Foo", long_about = None)]
|
||||||
|
struct CliOptions {
|
||||||
|
#[arg(short, long, action)]
|
||||||
|
file: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let cli_options = CliOptions::parse();
|
||||||
|
|
||||||
|
let config_data: serde_json::Value = serde_json::from_reader(File::open(cli_options.file).unwrap())
|
||||||
|
.expect("file should be proper JSON");
|
||||||
|
|
||||||
|
let mut data = HashMap::new();
|
||||||
|
for (key, value) in config_data["vars"].as_object().unwrap() {
|
||||||
|
data.insert(key, value.as_str().unwrap().to_string());
|
||||||
|
}
|
||||||
|
let mut today: DateTime<Utc> = Utc::now();
|
||||||
|
today = today.with_hour(0).unwrap().with_minute(0).unwrap().with_second(0).unwrap().with_nanosecond(0).unwrap();
|
||||||
|
let tomorrow = today.checked_add_days(Days::new(1)).unwrap();
|
||||||
|
let day_start = "day_start".to_string();
|
||||||
|
data.insert(&day_start, today.format("%Y-%m-%d %H:%M:%S").to_string());
|
||||||
|
let day_end = "day_end".to_string();
|
||||||
|
data.insert(&day_end, tomorrow.format("%Y-%m-%d %H:%M:%S").to_string());
|
||||||
|
|
||||||
|
let dt = Utc::now();
|
||||||
|
|
||||||
|
let mut write_queries: Vec<WriteQuery> = Vec::new();
|
||||||
|
|
||||||
|
if let Some(configs) = config_data["configs"].as_array() {
|
||||||
|
for config in configs {
|
||||||
|
let mut handlebars = Handlebars::new();
|
||||||
|
handlebars
|
||||||
|
.register_template_string("url", config["url"].as_str().unwrap())
|
||||||
|
.unwrap();
|
||||||
|
let url = handlebars.render("url", &data).unwrap();
|
||||||
|
println!("URL: {}", url);
|
||||||
|
|
||||||
|
let response_json: serde_json::Value = reqwest::get(url)
|
||||||
|
.await?
|
||||||
|
.json()
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
if let Some(values) = config["values"].as_array() {
|
||||||
|
for value in values {
|
||||||
|
if let Some(path) = value["path"].as_array() {
|
||||||
|
let mut sth = &response_json;
|
||||||
|
for segment in path {
|
||||||
|
if sth.is_array() {
|
||||||
|
let segment = segment.as_i64().unwrap();
|
||||||
|
match segment >= 0 {
|
||||||
|
false => {
|
||||||
|
sth = &sth[(sth.as_array().unwrap().len() as i64 + segment) as usize];
|
||||||
|
}
|
||||||
|
true => {
|
||||||
|
sth = &sth[segment as usize];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
let segment = segment.as_str().unwrap();
|
||||||
|
sth = &sth[segment];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let res_value = sth.as_f64().unwrap_or(0.0);
|
||||||
|
let system = value["tags"]["system"].as_str().unwrap().to_string();
|
||||||
|
let metric = value["tags"]["metric"].as_str().unwrap().to_string();
|
||||||
|
let unit = value["tags"]["unit"].as_str().unwrap().to_string();
|
||||||
|
let measurement = value["measurement"].as_str().unwrap().to_string();
|
||||||
|
|
||||||
|
write_queries.push(
|
||||||
|
InfluxData {
|
||||||
|
time: Timestamp::from(dt).into(),
|
||||||
|
value: res_value,
|
||||||
|
system,
|
||||||
|
metric,
|
||||||
|
unit,
|
||||||
|
}.into_query(measurement),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let influx_conf = &config_data["influx"];
|
||||||
|
let url = influx_conf["url"].as_str().unwrap().to_string();
|
||||||
|
let database = influx_conf["database"].as_str().unwrap().to_string();
|
||||||
|
let username = influx_conf["username"].as_str().unwrap().to_string();
|
||||||
|
let password = influx_conf["password"].as_str().unwrap().to_string();
|
||||||
|
let client = Client::new(url, database)
|
||||||
|
.with_auth(username, password);
|
||||||
|
let write_result = client
|
||||||
|
.query(write_queries)
|
||||||
|
.await;
|
||||||
|
assert!(write_result.is_ok(), "Write result was not okay");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
Loading…
Reference in New Issue