aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.claude/commands/release.md36
-rw-r--r--Cargo.lock2
-rw-r--r--Cargo.toml2
-rwxr-xr-xrelease.sh59
-rw-r--r--src/command_policy.rs4
-rw-r--r--src/entity_sensor.rs4
-rw-r--r--src/entity_switch.rs4
-rw-r--r--src/lib.rs20
-rw-r--r--src/mqtt/rx.rs18
-rw-r--r--src/mqtt/tx.rs1
10 files changed, 115 insertions, 35 deletions
diff --git a/.claude/commands/release.md b/.claude/commands/release.md
new file mode 100644
index 0000000..c0f072e
--- /dev/null
+++ b/.claude/commands/release.md
@@ -0,0 +1,36 @@
1# Release Command
2
3Create a new cargo release for embassy-ha.
4
5## Instructions
6
71. **Ask for the new version number** - Prompt the user for the version (e.g., "0.3.0"). Do not include the "v" prefix in the version number itself.
8
92. **Verify clean working directory** - Run `git status --porcelain` and fail if there are any uncommitted changes. The working directory must be clean before proceeding.
10
113. **Run pre-release checks** - Run the following commands in order. If any command fails, **stop immediately**, report the error, and let the user fix the issues manually. Do NOT attempt to fix issues automatically:
12 - `cargo fmt --check` - Verify code is properly formatted
13 - `cargo clippy` - Run linter (must have no warnings)
14 - `cargo check --tests --examples` - Check compilation of tests and examples
15 - `cargo test` - Run the test suite
16 - `cargo publish --dry-run` - Verify the package can be published
17
184. **Update version in Cargo.toml** - Only after all pre-release checks pass, update the `version` field in `Cargo.toml` to the new version.
19
205. **Create release commit** - Create a commit with the message: `chore: release v{version}`
21
226. **Create tag** - Create an annotated tag with the name `v{version}` and message `v{version}`
23
247. **Push to remote** - Push both the commit and the tag to the remote:
25 - `git push`
26 - `git push --tags`
27
28## Important Notes
29
30- If any pre-release check fails, **stop immediately** and report the failure. Do NOT:
31 - Attempt to fix the issues automatically (e.g., running `cargo fmt` to fix formatting)
32 - Update the version in Cargo.toml
33 - Create the commit or tag
34- The user is responsible for fixing any issues and re-running the release command
35- The tag format must be `v{version}` (e.g., `v0.3.0`) to match existing conventions
36- Use `--dry-run` for cargo publish to verify without actually publishing
diff --git a/Cargo.lock b/Cargo.lock
index fe3eb21..4574afe 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -175,7 +175,7 @@ source = "git+https://github.com/embassy-rs/embassy#dd4b0ae19e97101dab86af061e69
175 175
176[[package]] 176[[package]]
177name = "embassy-ha" 177name = "embassy-ha"
178version = "0.2.0" 178version = "0.3.0"
179dependencies = [ 179dependencies = [
180 "critical-section", 180 "critical-section",
181 "defmt 1.0.1", 181 "defmt 1.0.1",
diff --git a/Cargo.toml b/Cargo.toml
index 5821533..62a777c 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
1[package] 1[package]
2name = "embassy-ha" 2name = "embassy-ha"
3version = "0.2.0" 3version = "0.3.0"
4edition = "2024" 4edition = "2024"
5authors = ["diogo464 <[email protected]>"] 5authors = ["diogo464 <[email protected]>"]
6description = "MQTT Home Assistant integration library for Embassy async runtime" 6description = "MQTT Home Assistant integration library for Embassy async runtime"
diff --git a/release.sh b/release.sh
new file mode 100755
index 0000000..e79aa17
--- /dev/null
+++ b/release.sh
@@ -0,0 +1,59 @@
1#!/bin/bash
2set -euo pipefail
3
4VERSION="${1:-}"
5
6if [[ -z "$VERSION" ]]; then
7 echo "Usage: $0 <version>"
8 echo "Example: $0 0.3.0"
9 exit 1
10fi
11
12if [[ ! "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
13 echo "Error: Version must be in format x.y.z"
14 exit 1
15fi
16
17echo "Releasing version $VERSION"
18
19# Verify clean working directory
20if [[ -n "$(git status --porcelain)" ]]; then
21 echo "Error: Working directory has uncommitted changes"
22 git status --short
23 exit 1
24fi
25
26echo "Running pre-release checks..."
27
28echo " cargo fmt --check"
29cargo fmt --check
30
31echo " cargo clippy"
32cargo clippy -- -D warnings
33
34echo " cargo check --tests --examples"
35cargo check --tests --examples
36
37echo " cargo test"
38cargo test
39
40echo " cargo publish --dry-run"
41cargo publish --dry-run
42
43echo "All checks passed. Updating version..."
44
45sed -i "s/^version = \".*\"/version = \"$VERSION\"/" Cargo.toml
46
47echo "Creating commit..."
48git add Cargo.toml
49git commit -m "chore: release v$VERSION"
50
51echo "Creating tag..."
52git tag -a "v$VERSION" -m "v$VERSION"
53
54echo "Pushing to remote..."
55git push
56git push --tags
57
58echo "Release v$VERSION complete!"
59echo "To publish to crates.io, run: cargo publish"
diff --git a/src/command_policy.rs b/src/command_policy.rs
index e5859bb..a1bb3bf 100644
--- a/src/command_policy.rs
+++ b/src/command_policy.rs
@@ -63,8 +63,7 @@
63/// # } 63/// # }
64/// # async fn turn_on_motor() -> Result<(), ()> { Ok(()) } 64/// # async fn turn_on_motor() -> Result<(), ()> { Ok(()) }
65/// ``` 65/// ```
66#[derive(Debug, Clone, Copy, PartialEq, Eq)] 66#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
67#[derive(Default)]
68pub enum CommandPolicy { 67pub enum CommandPolicy {
69 /// Automatically publish the entity's state when a command is received. 68 /// Automatically publish the entity's state when a command is received.
70 #[default] 69 #[default]
@@ -73,4 +72,3 @@ pub enum CommandPolicy {
73 /// Do not automatically publish state. The application must manually update the state. 72 /// Do not automatically publish state. The application must manually update the state.
74 Manual, 73 Manual,
75} 74}
76
diff --git a/src/entity_sensor.rs b/src/entity_sensor.rs
index e221141..fd5e7f7 100644
--- a/src/entity_sensor.rs
+++ b/src/entity_sensor.rs
@@ -18,8 +18,7 @@ impl StateClass {
18 } 18 }
19} 19}
20 20
21#[derive(Debug, Clone, Copy, PartialEq, Eq)] 21#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
22#[derive(Default)]
23pub enum SensorClass { 22pub enum SensorClass {
24 #[default] 23 #[default]
25 Generic, 24 Generic,
@@ -77,7 +76,6 @@ pub enum SensorClass {
77 Other(&'static str), 76 Other(&'static str),
78} 77}
79 78
80
81impl SensorClass { 79impl SensorClass {
82 pub fn as_str(&self) -> Option<&'static str> { 80 pub fn as_str(&self) -> Option<&'static str> {
83 match self { 81 match self {
diff --git a/src/entity_switch.rs b/src/entity_switch.rs
index 2b799a1..b685ce5 100644
--- a/src/entity_switch.rs
+++ b/src/entity_switch.rs
@@ -14,15 +14,13 @@ pub enum SwitchClass {
14/// Configuration for a switch entity. 14/// Configuration for a switch entity.
15/// 15///
16/// See [`CommandPolicy`] for details on how commands are handled. 16/// See [`CommandPolicy`] for details on how commands are handled.
17#[derive(Debug)] 17#[derive(Debug, Default)]
18#[derive(Default)]
19pub struct SwitchConfig { 18pub struct SwitchConfig {
20 pub common: EntityCommonConfig, 19 pub common: EntityCommonConfig,
21 pub class: SwitchClass, 20 pub class: SwitchClass,
22 pub command_policy: CommandPolicy, 21 pub command_policy: CommandPolicy,
23} 22}
24 23
25
26impl SwitchConfig { 24impl SwitchConfig {
27 pub(crate) fn populate(&self, config: &mut EntityConfig) { 25 pub(crate) fn populate(&self, config: &mut EntityConfig) {
28 self.common.populate(config); 26 self.common.populate(config);
diff --git a/src/lib.rs b/src/lib.rs
index 2d1ecfb..35d50ca 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -346,6 +346,7 @@ pub struct DeviceConfig {
346 pub model: &'static str, 346 pub model: &'static str,
347} 347}
348 348
349#[derive(Default)]
349pub struct DeviceBuffersOwned { 350pub struct DeviceBuffersOwned {
350 pub publish: Vec<u8, 2048>, 351 pub publish: Vec<u8, 2048>,
351 pub subscribe: Vec<u8, 128>, 352 pub subscribe: Vec<u8, 128>,
@@ -357,21 +358,6 @@ pub struct DeviceBuffersOwned {
357 pub attributes_topic: String<128>, 358 pub attributes_topic: String<128>,
358} 359}
359 360
360impl Default for DeviceBuffersOwned {
361 fn default() -> Self {
362 Self {
363 publish: Default::default(),
364 subscribe: Default::default(),
365 discovery: Default::default(),
366 availability_topic: Default::default(),
367 discovery_topic: Default::default(),
368 state_topic: Default::default(),
369 command_topic: Default::default(),
370 attributes_topic: Default::default(),
371 }
372 }
373}
374
375impl DeviceBuffersOwned { 361impl DeviceBuffersOwned {
376 pub fn as_buffers_mut(&mut self) -> DeviceBuffers<'_> { 362 pub fn as_buffers_mut(&mut self) -> DeviceBuffers<'_> {
377 DeviceBuffers { 363 DeviceBuffers {
@@ -1093,10 +1079,8 @@ fn generate_entity_discovery(
1093/// 1079///
1094/// ```no_run 1080/// ```no_run
1095/// # use embassy_ha::{Device, Transport}; 1081/// # use embassy_ha::{Device, Transport};
1096/// # async fn example(mut device: Device<'_>, create_transport: impl Fn() -> impl Transport) { 1082/// # async fn example(mut device: Device<'_>, mut transport: impl Transport) {
1097/// loop { 1083/// loop {
1098/// let mut transport = create_transport();
1099///
1100/// match embassy_ha::run(&mut device, &mut transport).await { 1084/// match embassy_ha::run(&mut device, &mut transport).await {
1101/// Ok(()) => { 1085/// Ok(()) => {
1102/// // Normal exit (this shouldn't happen in practice) 1086/// // Normal exit (this shouldn't happen in practice)
diff --git a/src/mqtt/rx.rs b/src/mqtt/rx.rs
index 10b775a..0dfd858 100644
--- a/src/mqtt/rx.rs
+++ b/src/mqtt/rx.rs
@@ -37,7 +37,9 @@ impl From<varint::Error> for Error {
37 fn from(value: varint::Error) -> Self { 37 fn from(value: varint::Error) -> Self {
38 match value { 38 match value {
39 varint::Error::NeedMoreData => Self::NeedMoreData, 39 varint::Error::NeedMoreData => Self::NeedMoreData,
40 varint::Error::InvalidVarInt => Self::InvalidPacket("invalid variable integer encoding"), 40 varint::Error::InvalidVarInt => {
41 Self::InvalidPacket("invalid variable integer encoding")
42 }
41 } 43 }
42 } 44 }
43} 45}
@@ -92,8 +94,10 @@ pub fn decode<'a>(buf: &'a [u8]) -> Result<(Packet<'a>, usize), Error> {
92 protocol::PACKET_TYPE_PUBLISH => { 94 protocol::PACKET_TYPE_PUBLISH => {
93 // Extract flags from the fixed header 95 // Extract flags from the fixed header
94 let retain = (packet_flags & protocol::PUBLISH_FLAG_RETAIN) != 0; 96 let retain = (packet_flags & protocol::PUBLISH_FLAG_RETAIN) != 0;
95 let qos_value = (packet_flags & protocol::PUBLISH_FLAG_QOS_MASK) >> protocol::PUBLISH_FLAG_QOS_SHIFT; 97 let qos_value = (packet_flags & protocol::PUBLISH_FLAG_QOS_MASK)
96 let qos = Qos::from_u8(qos_value).ok_or(Error::InvalidPacket("PUBLISH has invalid QoS value"))?; 98 >> protocol::PUBLISH_FLAG_QOS_SHIFT;
99 let qos = Qos::from_u8(qos_value)
100 .ok_or(Error::InvalidPacket("PUBLISH has invalid QoS value"))?;
97 let dup = (packet_flags & protocol::PUBLISH_FLAG_DUP) != 0; 101 let dup = (packet_flags & protocol::PUBLISH_FLAG_DUP) != 0;
98 102
99 // Track position after fixed header to calculate data length 103 // Track position after fixed header to calculate data length
@@ -113,7 +117,9 @@ pub fn decode<'a>(buf: &'a [u8]) -> Result<(Packet<'a>, usize), Error> {
113 let variable_header_len = reader.num_read() - variable_header_start; 117 let variable_header_len = reader.num_read() - variable_header_start;
114 let data_len = (packet_len as usize) 118 let data_len = (packet_len as usize)
115 .checked_sub(variable_header_len) 119 .checked_sub(variable_header_len)
116 .ok_or(Error::InvalidPacket("PUBLISH remaining length is too short for headers"))?; 120 .ok_or(Error::InvalidPacket(
121 "PUBLISH remaining length is too short for headers",
122 ))?;
117 123
118 Packet::Publish { 124 Packet::Publish {
119 topic, 125 topic,
@@ -140,7 +146,9 @@ pub fn decode<'a>(buf: &'a [u8]) -> Result<(Packet<'a>, usize), Error> {
140 } 146 }
141 if packet_len < 3 { 147 if packet_len < 3 {
142 // Minimum: 2 bytes packet ID + 1 byte return code 148 // Minimum: 2 bytes packet ID + 1 byte return code
143 return Err(Error::InvalidPacket("SUBACK remaining length must be at least 3")); 149 return Err(Error::InvalidPacket(
150 "SUBACK remaining length must be at least 3",
151 ));
144 } 152 }
145 let packet_id = PacketId::from(reader.read_u16()?); 153 let packet_id = PacketId::from(reader.read_u16()?);
146 let return_code = reader.read_u8()?; 154 let return_code = reader.read_u8()?;
diff --git a/src/mqtt/tx.rs b/src/mqtt/tx.rs
index 7a4d443..3b2ed66 100644
--- a/src/mqtt/tx.rs
+++ b/src/mqtt/tx.rs
@@ -209,4 +209,3 @@ pub fn pingreq(buffer: &mut FieldBuffer) {
209 ))); 209 )));
210 buffer.push(Field::VarInt(0)); 210 buffer.push(Field::VarInt(0));
211} 211}
212