Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/ha discovery #27

Merged
merged 23 commits into from
Nov 24, 2023
Merged

Conversation

dominikandreas
Copy link
Collaborator

@dominikandreas dominikandreas commented Nov 12, 2023

This is a work in progress, but wanted to get some early feedback. The main contributions of this PR are:

Other notable changes / additions:

  • added vscode devcontainer support and debug launch configuration to simplify development for future contributors
  • add serde dependency for json serialization
  • version bump to 0.2.0 because of breaking changes (mqtt paths change)
  • refactor log init into its own module
  • add mock_state function to inverter for testing purposes

Note that this is my first time developing in rust and there's probably a lot of things to improve / things that an experienced rust developer would've probably done differently. I'm happy to receive some constructive feedback and improve where necessary :-)

TODO:

@DennisOSRM
Copy link
Owner

Thanks for the PR. It will take a couple of days before I can get around to reviewing this.

From a quick glance, it seems this PR contains a couple of things that likely should be seperate PRs, and the testing code perhaps should not bleed into the implementation. That being said, this isn't a comprehensive review and just an initial impression.

Thanks for the contribution, please keep up the great work.

Copy link
Owner

@DennisOSRM DennisOSRM left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks again for filing this PR. I think it contains very interesting and worthwhile ideas. Since the PR is rather big and contains several unrelated changes, I'd suggest to do the following:

  • remove the development related files and directories
  • the testing code should be done in a distinct PR without having to branch between test and non-test code. I.e. the implementation should be oblivious to the fact whether it is run in a test environment or not.
  • move structs into their own source file
  • consider using protobuf_json crate instead of the rolling your own conversion to json
  • implement the auto discovery in a non-breaking way

While the above may seem like a lot, I think the PR is a great first stab into the right direction. The intent for the PR is great, please keep up the good work.

@@ -0,0 +1 @@
FROM rust:buster
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The files in .devcontainer should not be part of this PR.

@@ -0,0 +1,21 @@
{
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The files in .vscode/* should not be part of this PR.

src/inverter.rs Outdated
@@ -39,7 +40,42 @@ impl<'a> Inverter<'a> {
}
}

pub fn update_state(&mut self) -> Option<HMSStateResponse> {
pub fn mock_state(&mut self) -> Option<HMSStateResponse> {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test code should be separated from the implementation. This could be done in a tool simulating the behavior of an actual inverter. Issue #11 is tracking such a feature. This should be dropped from the PR.

src/main.rs Outdated
mqtt.publish(&r);
}

// TODO: this has to move into the Inverter struct in an async implementation
thread::sleep(Duration::from_millis(REQUEST_DELAY));
if !cli.test{
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above for the comment that API simulation should implemented in #11.

src/mqtt.rs Outdated
impl HMSStateResponse {
fn get_model(&self) -> String {
// TODO: identify model from dtu_sn
"HMS-800W-T2".to_string()
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not necessarily the inverter. While tested, the tool likely works with all devices of the HMS-XXXX-2T series.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, since we currently don't have a way to determine the exact model name, I've removed the mention of 800W-2T

src/mqtt.rs Outdated
}


impl DeviceConfig {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider moving the struct into a separate source file

src/mqtt.rs Outdated
identifiers,
manufacturer: "Hoymiles".to_string(),
/// Rust compiler sets the CARGO_PKG_VERSION environment from the Cargo.toml .
sw_version: env!("CARGO_PKG_VERSION").to_string(),
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is arguably not part the version of the inverter device

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, but I thought it makes sense to log the version of the publisher here (we can also change it in the future in case we figure out a way to extract the sw version of the inverter)

src/mqtt.rs Outdated
/// https://developers.home-assistant.io/docs/core/entity/sensor/
///
#[derive(Serialize)]
pub struct SensorConfig {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider moving this to a separate source file

src/mqtt.rs Outdated
}


fn create_sensor_configs(hms_state: &HMSStateResponse, state_topic: &str) -> Vec<SensorConfig> {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this be a ::from(...) member function rather than a free factory?

self.client
.subscribe("hms800wt2/pv_current_power", QoS::AtMostOnce)
.unwrap();
match self.client.publish(
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this seems like a breaking change.

@dominikandreas
Copy link
Collaborator Author

Thanks for your comprehensive review!

remove the development related files and directories

I will create a separate PR for this

the testing code should be done in a distinct PR without having to branch between test and non-test code.

Good point. Didn't have time to address this properly so just hacked in something quickly that allowed me to do some minimal testing during the addon development. I will remove the testing related code for now

move structs into their own source file

Will do. Wasn't sure how to structure it or whether it's necessary to split the mqtt implementation up in two parts, one for home assistant, one without home assistant support.

consider using protobuf_json crate instead of the rolling your own conversion to json

Thought about this as well, but since the values are scaled during the serialization, I decided to just do it the manual way. I assume the protobuf schemas won't often if at all, so I hope that's okay.

implement the auto discovery in a non-breaking way

The breaking change is unfortunate. But apart from home assistant support, another upside is that it would allow utilizing multiple inverters in the future (part of the serial number is added to the topic). Another part of the breaking change is that the whole update is sent json-encoded to a single topic instead of splitting it to multiple topics. This should make it more efficient in combination with home assistant (and possibly other endpoints)

@DennisOSRM
Copy link
Owner

The breaking change is unfortunate. But apart from home assistant support, another upside is that it would allow utilizing multiple inverters in the future (part of the serial number is added to the topic). Another part of the breaking change is that the whole update is sent json-encoded to a single topic instead of splitting it to multiple topics. This should make it more efficient in combination with home assistant (and possibly other endpoints)

That's a good point. Thanks for the clarification. I think the json-encoded single topic could be done independently, is that right? If so, we could first add things, and consider the breaking change at a later point. Would this make sense?

@dominikandreas
Copy link
Collaborator Author

Yes, we could change the home assistant device configurations and publish on separate topics to delay the breaking change. But if we're certain it's going to happen sooner or later (and I think supporting multiple inverters is a enough good reason), delaying the breaking change will only cause more users to be affected.

While we're at it we should also remove the "800W-2T" references, e.g. from the topic, to prevent a future breaking change.

@DennisOSRM
Copy link
Owner

Ok, that's a convincing argument. Let's do the breaking change now, and aim at the same time to minimize the size of this PR.

@dominikandreas
Copy link
Collaborator Author

I think I addressed all of the review comments and fixed some additional bugs. Here's an example of the provided data in home assistant:

image

In order to enable these changes in the addon, we first need an image on docker hub that I can reference in the Dockerfile of the home assistant addon. I have a build running right now, but it's taking a while. I will hopefully push another update tomorrow when it's done

@DennisOSRM
Copy link
Owner

Very cool. Please have a bit of patience, since it will again take a couple of days before I can get to it.

Copy link
Owner

@DennisOSRM DennisOSRM left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • run cargo fmt
  • run cargo clippy
  • move non-functional changes into distinct PRs to separate concerns

This is looking really close. Couple of remarks on the PR that shouldn't take too long to resolve. Then we can get this in.

To give some perspective of where I am taking the architecture of the tool are probably helpful. Similar to the idea of supporting several inputs, I'd like the tool to support several output channels (for a lack of a better name). I.e. there's a simple MQTT publisher, there's the HA autodiscovery and publishing of this PR, and other outputs like InfluxDB and perhaps others. The user will be able to configure where to publish.

Once this PR is ready, I want to start implementing these channels by building right on top of this branch and then merge the two in short succession once both are ready.

Cargo.toml Outdated Show resolved Hide resolved
.gitignore Show resolved Hide resolved
src/inverter.rs Show resolved Hide resolved
src/mqtt.rs Show resolved Hide resolved
src/mqtt.rs Show resolved Hide resolved
src/mqtt_schemas.rs Show resolved Hide resolved
src/protos/RealData.proto Show resolved Hide resolved
src/main.rs Show resolved Hide resolved
@DennisOSRM
Copy link
Owner

I did a very hasty implementation of output channels (cf. #27 (review)) on top of your PR: 7460c0e

@@ -1,9 +1,12 @@
use std::{thread, time::Duration};
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in light of the output channel feature (see below) it probably makes sense to rename this file to home_assistent.rs since it will implement the output channel to a HA instance.

Copy link
Owner

@DennisOSRM DennisOSRM left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will merge changes and do a couple of minor changes on top. Thanks so much for the contribution

@DennisOSRM DennisOSRM merged commit 0685bac into DennisOSRM:main Nov 24, 2023
1 check passed
This was referenced Nov 24, 2023
@dominikandreas
Copy link
Collaborator Author

Sorry I was preoccupied with my day job and family. I'll have a look at the output channels PR

@DennisOSRM
Copy link
Owner

No worries. Life comes first, hacking on code second. 😉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants