-
Notifications
You must be signed in to change notification settings - Fork 10
Add display brightness control #83
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
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @weberval - I've reviewed your changes - here's some feedback:
- The
brightness_to_u8
test callsBrightness::from(i.0)
incorrectly – it should directly useu8::from(i.0)
since you only implementedFrom<Brightness> for u8
. - Consider providing a builder-style
.brightness()
setter or allowing brightness to be modified on an existingPayloadBuffer
for consistency with other style setters instead of only via the constructor. - Changing the header size by removing a magic byte and inserting
brightness
breaks protocol compatibility; ensure you document this change clearly and bump the protocol version accordingly.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The `brightness_to_u8` test calls `Brightness::from(i.0)` incorrectly – it should directly use `u8::from(i.0)` since you only implemented `From<Brightness> for u8`.
- Consider providing a builder-style `.brightness()` setter or allowing brightness to be modified on an existing `PayloadBuffer` for consistency with other style setters instead of only via the constructor.
- Changing the header size by removing a magic byte and inserting `brightness` breaks protocol compatibility; ensure you document this change clearly and bump the protocol version accordingly.
## Individual Comments
### Comment 1
<location> `src/protocol.rs:536` </location>
<code_context>
+ (Brightness::OneQuarter, 0x30),
+ ];
+
+ for i in VALID_BRIGHTNESS_VALUES {
+ assert_eq!(u8::from(Brightness::from(i.0)), i.1);
+ }
</code_context>
<issue_to_address>
Redundant use of Brightness::from in test.
You can simplify `u8::from(Brightness::from(i.0))` to `u8::from(i.0)` since `i.0` is already a Brightness.
</issue_to_address>
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
I'm still waiting for review. Is there any chance this happens in the next month? |
Before I start with the review, can you please point me to the place where those brightness values are used in the firmware. I could only find a brightness value controlled by button presses or a new BLE characteristic. Or is this only implemented in the OEM firmware? |
@weberval I don't want to put you under pressure or anything, I just want to mention you explicitly in case you weren't notified about the previous message. |
It seems it is not (yet) implemented in the OSS firmware. Instead, it seems like the "magic" header is longer than required and the brightness value is the last byte of that header. (see firmware vs my protocol implementation) I have not found any validation of the magic header |
@weberval Do you have a link to a fork of the firmware with the brightness already implemented? Is this implemented in any other software to talk to the badges (e.g. Android App, Go implementation, etc.)? If this is not implemented anywhere else, how / why did you pick the values |
I used the values from the python project. I don't know what padding is applied to the value in the proprietary firmware or what the other bits could be used for, but those values seem to work. |
Ok, awesome. So it is from a commit from 2019 (fossasia/led-name-badge-ls32@6640ee3). Therefore I would assume that this is implemented in the proprietary firmware from the manufacturer. Then lets look at the actual code... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the PR. I have added a few comments. And thanks for fixing a lot of my typos 👍
Note I just updated the dependencies and fixed the new clippy lints. You can pull these changes into your PR. |
4894bde
to
a9b38fb
Compare
@sourcery-ai dismiss |
@sourcery-ai review |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @weberval - I've reviewed your changes and they look great!
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location> `src/protocol.rs:214` </location>
<code_context>
+ }
+}
+
+impl TryFrom<u8> for Brightness {
+ type Error = TryFromIntError;
+
+ fn try_from(value: u8) -> Result<Self, Self::Error> {
+ Ok(match value {
+ 0x00 => Self::Full,
+ 0x10 => Self::ThreeQuarters,
+ 0x20 => Self::Half,
+ 0x30 => Self::OneQuarter,
+ _ => return Err(u8::try_from(-1).unwrap_err()),
+ })
+ }
</code_context>
<issue_to_address>
Using u8::try_from(-1) to generate an error is indirect and may be confusing.
Use a more explicit error, like core::num::TryFromIntError::default() or a custom error type, to clarify intent and avoid depending on u8::try_from(-1).
</issue_to_address>
<suggested_fix>
<<<<<<< SEARCH
+impl TryFrom<u8> for Brightness {
+ type Error = TryFromIntError;
+
+ fn try_from(value: u8) -> Result<Self, Self::Error> {
+ Ok(match value {
+ 0x00 => Self::Full,
+ 0x10 => Self::ThreeQuarters,
+ 0x20 => Self::Half,
+ 0x30 => Self::OneQuarter,
+ _ => return Err(u8::try_from(-1).unwrap_err()),
+ })
+ }
=======
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub struct BrightnessParseError;
+
+impl core::fmt::Display for BrightnessParseError {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ write!(f, "invalid value for Brightness")
+ }
+}
+
+#[cfg(feature = "std")]
+impl std::error::Error for BrightnessParseError {}
+
+impl TryFrom<u8> for Brightness {
+ type Error = BrightnessParseError;
+
+ fn try_from(value: u8) -> Result<Self, Self::Error> {
+ match value {
+ 0x00 => Ok(Self::Full),
+ 0x10 => Ok(Self::ThreeQuarters),
+ 0x20 => Ok(Self::Half),
+ 0x30 => Ok(Self::OneQuarter),
+ _ => Err(BrightnessParseError),
+ }
+ }
>>>>>>> REPLACE
</suggested_fix>
### Comment 2
<location> `src/protocol.rs:342` </location>
<code_context>
+ }
+
/// Return the current number of messages
pub fn num_messages(&mut self) -> usize {
self.num_messages as usize
</code_context>
<issue_to_address>
The num_messages method takes &mut self but does not mutate state.
Changing the receiver to &self would improve flexibility since no mutation occurs.
</issue_to_address>
<suggested_fix>
<<<<<<< SEARCH
/// Return the current number of messages
pub fn num_messages(&mut self) -> usize {
self.num_messages as usize
&self.data
}
=======
/// Return the current number of messages
pub fn num_messages(&self) -> usize {
self.num_messages as usize
}
>>>>>>> REPLACE
</suggested_fix>
Hi @weberval! 👋
Thanks for trying out Sourcery by commenting with @sourcery-ai review
! 🚀
Install the sourcery-ai bot to get automatic code reviews on every pull request ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.&self.data | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion: The num_messages method takes &mut self but does not mutate state.
Changing the receiver to &self would improve flexibility since no mutation occurs.
&self.data | |
} | |
/// Return the current number of messages | |
pub fn num_messages(&self) -> usize { | |
self.num_messages as usize | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not related to this change set, but should be fixed 😅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @weberval - I've reviewed your changes - here's some feedback:
- The TryFrom implementation for Brightness uses a workaround (
u8::try_from(-1).unwrap_err()
) to generate errors—consider defining a dedicated error type or using a more idiomatic approach for invalid values. - Changing the protocol header (MAGIC length changed and a brightness byte added) is a breaking change—make sure the version bump follows semver (major version) or include upgrade notes.
- Consider adding unit tests for invalid brightness inputs to verify that TryFrom correctly returns Err for out-of-range values.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The TryFrom<u8> implementation for Brightness uses a workaround (`u8::try_from(-1).unwrap_err()`) to generate errors—consider defining a dedicated error type or using a more idiomatic approach for invalid values.
- Changing the protocol header (MAGIC length changed and a brightness byte added) is a breaking change—make sure the version bump follows semver (major version) or include upgrade notes.
- Consider adding unit tests for invalid brightness inputs to verify that TryFrom<u8> correctly returns Err for out-of-range values.
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a few tiny points left. But I thought a bit about the current representation in the config file:
brightness = "full"
brightness = "three-quarters"
brightness = "half"
brightness = "one-quarter"
Feels a bit weird to write the names out. Alternative representations:
- Percentage numbers like in the python implementation:
brightness = 100 brightness = 75 brightness = 50 brightness = 25
- Percentages but with a percent sign (needs to be a string):
brightness = "100%" brightness = "75%" brightness = "50%" brightness = "25%"
- Consecutively numbered brightness levels:
brightness = 4 brightness = 3 brightness = 2 brightness = 1
- Floating point numbers with
1
as the max:brightness = 1 brightness = 0.75 brightness = 0.5 brightness = 0.25
I think I like the float variant the most since it allows for future extension if the OSS firmware would add additional brightness levels (The percent based variants would need floats to represent 8 brightness levels 12.5%
, etc.). But I am open to other opinions.
I haven't thought about his at all, but it makes sense. Option four seems to be the most intuitive, so I'm in favour of that, too.
|
@mgjm Have you had the time to have a look at my changes? |
Summary by Sourcery
Introduce brightness control by adding a Brightness enum and integrating it into the protocol header, payload buffer, and CLI configuration, along with related tests and minor documentation fixes.
New Features:
Enhancements:
Documentation:
Tests: