aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock112
-rw-r--r--Cargo.toml8
-rw-r--r--examples/constant-temperature.rs171
3 files changed, 291 insertions, 0 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 1fadd29..61ede9e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -27,6 +27,41 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
27checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" 27checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b"
28 28
29[[package]] 29[[package]]
30name = "darling"
31version = "0.20.11"
32source = "registry+https://github.com/rust-lang/crates.io-index"
33checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee"
34dependencies = [
35 "darling_core",
36 "darling_macro",
37]
38
39[[package]]
40name = "darling_core"
41version = "0.20.11"
42source = "registry+https://github.com/rust-lang/crates.io-index"
43checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e"
44dependencies = [
45 "fnv",
46 "ident_case",
47 "proc-macro2",
48 "quote",
49 "strsim",
50 "syn",
51]
52
53[[package]]
54name = "darling_macro"
55version = "0.20.11"
56source = "registry+https://github.com/rust-lang/crates.io-index"
57checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead"
58dependencies = [
59 "darling_core",
60 "quote",
61 "syn",
62]
63
64[[package]]
30name = "defmt" 65name = "defmt"
31version = "0.3.100" 66version = "0.3.100"
32source = "registry+https://github.com/rust-lang/crates.io-index" 67source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -77,6 +112,36 @@ dependencies = [
77] 112]
78 113
79[[package]] 114[[package]]
115name = "embassy-executor"
116version = "0.9.1"
117source = "registry+https://github.com/rust-lang/crates.io-index"
118checksum = "06070468370195e0e86f241c8e5004356d696590a678d47d6676795b2e439c6b"
119dependencies = [
120 "critical-section",
121 "document-features",
122 "embassy-executor-macros",
123 "embassy-executor-timer-queue",
124]
125
126[[package]]
127name = "embassy-executor-macros"
128version = "0.7.0"
129source = "registry+https://github.com/rust-lang/crates.io-index"
130checksum = "dfdddc3a04226828316bf31393b6903ee162238576b1584ee2669af215d55472"
131dependencies = [
132 "darling",
133 "proc-macro2",
134 "quote",
135 "syn",
136]
137
138[[package]]
139name = "embassy-executor-timer-queue"
140version = "0.1.0"
141source = "registry+https://github.com/rust-lang/crates.io-index"
142checksum = "2fc328bf943af66b80b98755db9106bf7e7471b0cf47dc8559cd9a6be504cc9c"
143
144[[package]]
80name = "embassy-futures" 145name = "embassy-futures"
81version = "0.1.2" 146version = "0.1.2"
82source = "registry+https://github.com/rust-lang/crates.io-index" 147source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -86,7 +151,9 @@ checksum = "dc2d050bdc5c21e0862a89256ed8029ae6c290a93aecefc73084b3002cdebb01"
86name = "embassy-ha" 151name = "embassy-ha"
87version = "0.1.0" 152version = "0.1.0"
88dependencies = [ 153dependencies = [
154 "critical-section",
89 "defmt 1.0.1", 155 "defmt 1.0.1",
156 "embassy-executor",
90 "embassy-futures", 157 "embassy-futures",
91 "embassy-net", 158 "embassy-net",
92 "embassy-sync", 159 "embassy-sync",
@@ -96,6 +163,7 @@ dependencies = [
96 "heapless 0.9.2", 163 "heapless 0.9.2",
97 "serde", 164 "serde",
98 "serde-json-core", 165 "serde-json-core",
166 "static_cell",
99] 167]
100 168
101[[package]] 169[[package]]
@@ -151,6 +219,7 @@ dependencies = [
151 "defmt 1.0.1", 219 "defmt 1.0.1",
152 "document-features", 220 "document-features",
153 "embassy-time-driver", 221 "embassy-time-driver",
222 "embassy-time-queue-utils",
154 "embedded-hal 0.2.7", 223 "embedded-hal 0.2.7",
155 "embedded-hal 1.0.0", 224 "embedded-hal 1.0.0",
156 "embedded-hal-async", 225 "embedded-hal-async",
@@ -167,6 +236,16 @@ dependencies = [
167] 236]
168 237
169[[package]] 238[[package]]
239name = "embassy-time-queue-utils"
240version = "0.3.0"
241source = "registry+https://github.com/rust-lang/crates.io-index"
242checksum = "80e2ee86063bd028a420a5fb5898c18c87a8898026da1d4c852af2c443d0a454"
243dependencies = [
244 "embassy-executor-timer-queue",
245 "heapless 0.8.0",
246]
247
248[[package]]
170name = "embedded-hal" 249name = "embedded-hal"
171version = "0.2.7" 250version = "0.2.7"
172source = "registry+https://github.com/rust-lang/crates.io-index" 251source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -234,6 +313,12 @@ dependencies = [
234] 313]
235 314
236[[package]] 315[[package]]
316name = "fnv"
317version = "1.0.7"
318source = "registry+https://github.com/rust-lang/crates.io-index"
319checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
320
321[[package]]
237name = "futures-core" 322name = "futures-core"
238version = "0.3.31" 323version = "0.3.31"
239source = "registry+https://github.com/rust-lang/crates.io-index" 324source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -277,6 +362,12 @@ dependencies = [
277] 362]
278 363
279[[package]] 364[[package]]
365name = "ident_case"
366version = "1.0.1"
367source = "registry+https://github.com/rust-lang/crates.io-index"
368checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
369
370[[package]]
280name = "litrs" 371name = "litrs"
281version = "1.0.0" 372version = "1.0.0"
282source = "registry+https://github.com/rust-lang/crates.io-index" 373source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -304,6 +395,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
304checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" 395checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d"
305 396
306[[package]] 397[[package]]
398name = "portable-atomic"
399version = "1.11.1"
400source = "registry+https://github.com/rust-lang/crates.io-index"
401checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483"
402
403[[package]]
307name = "proc-macro-error-attr2" 404name = "proc-macro-error-attr2"
308version = "2.0.0" 405version = "2.0.0"
309source = "registry+https://github.com/rust-lang/crates.io-index" 406source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -411,6 +508,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
411checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" 508checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
412 509
413[[package]] 510[[package]]
511name = "static_cell"
512version = "2.1.1"
513source = "registry+https://github.com/rust-lang/crates.io-index"
514checksum = "0530892bb4fa575ee0da4b86f86c667132a94b74bb72160f58ee5a4afec74c23"
515dependencies = [
516 "portable-atomic",
517]
518
519[[package]]
520name = "strsim"
521version = "0.11.1"
522source = "registry+https://github.com/rust-lang/crates.io-index"
523checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
524
525[[package]]
414name = "syn" 526name = "syn"
415version = "2.0.111" 527version = "2.0.111"
416source = "registry+https://github.com/rust-lang/crates.io-index" 528source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index 908e183..d37e957 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -14,3 +14,11 @@ defmt = "1.0.1"
14embassy-sync = { version = "0.7.2", features = ["defmt"] } 14embassy-sync = { version = "0.7.2", features = ["defmt"] }
15embassy-futures = "0.1.2" 15embassy-futures = "0.1.2"
16embedded-io-async = "0.6" 16embedded-io-async = "0.6"
17
18[dev-dependencies]
19embassy-time = { version = "0.5.0", features = ["std"] }
20embassy-executor = { version = "0.9.1", features = ["arch-std", "executor-thread"] }
21embassy-sync = { version = "0.7.2" }
22static_cell = "2.1.1"
23embedded-io-async = { version = "0.6", features = ["std"] }
24critical-section = { version = "1", features = ["std"] }
diff --git a/examples/constant-temperature.rs b/examples/constant-temperature.rs
new file mode 100644
index 0000000..27e1076
--- /dev/null
+++ b/examples/constant-temperature.rs
@@ -0,0 +1,171 @@
1use std::{
2 io::{Read, Write},
3 net::{TcpStream, ToSocketAddrs},
4 sync::{Arc, Mutex},
5 thread::JoinHandle,
6};
7
8use embassy_executor::{Executor, Spawner};
9use embassy_sync::waitqueue::AtomicWaker;
10use embassy_time::Timer;
11use static_cell::StaticCell;
12
13static EXECUTOR: StaticCell<Executor> = StaticCell::new();
14static RESOURCES: StaticCell<embassy_ha::DeviceResources> = StaticCell::new();
15
16struct AsyncTcp {
17 write_handle: JoinHandle<()>,
18 write_buffer: Arc<Mutex<Vec<u8>>>,
19 read_buffer: Arc<Mutex<Vec<u8>>>,
20 waker: Arc<AtomicWaker>,
21}
22
23impl AsyncTcp {
24 fn connect(addr: impl ToSocketAddrs) -> Self {
25 let stream = TcpStream::connect(addr).expect("failed to connect to remote");
26 let mut read_stream = stream.try_clone().unwrap();
27 let mut write_stream = stream;
28
29 let read_buffer: Arc<Mutex<Vec<u8>>> = Default::default();
30 let write_buffer: Arc<Mutex<Vec<u8>>> = Default::default();
31
32 let waker = Arc::new(AtomicWaker::new());
33
34 let write_handle = std::thread::spawn({
35 let write_buffer = write_buffer.clone();
36 move || {
37 loop {
38 let buffer = {
39 let mut buffer = write_buffer.lock().unwrap();
40 std::mem::take(&mut *buffer)
41 };
42 if !buffer.is_empty() {
43 println!("writing {} bytes", buffer.len());
44 write_stream.write_all(&buffer).unwrap();
45 write_stream.flush().unwrap();
46 } else {
47 std::thread::park();
48 }
49 }
50 }
51 });
52
53 std::thread::spawn({
54 let read_buffer = read_buffer.clone();
55 let waker = waker.clone();
56 move || {
57 let mut scratch = [0u8; 1024];
58 loop {
59 let n = read_stream.read(&mut scratch).unwrap();
60 if n == 0 {
61 panic!("EOF");
62 }
63
64 {
65 let mut buffer = read_buffer.lock().unwrap();
66 buffer.extend_from_slice(&scratch[..n]);
67 waker.wake();
68 }
69 }
70 }
71 });
72
73 Self {
74 write_handle,
75 write_buffer,
76 read_buffer,
77 waker,
78 }
79 }
80}
81
82impl embedded_io_async::ErrorType for AsyncTcp {
83 type Error = std::io::Error;
84}
85
86impl embedded_io_async::Write for AsyncTcp {
87 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
88 {
89 let mut buffer = self.write_buffer.lock().unwrap();
90 buffer.extend_from_slice(buf);
91 }
92 self.write_handle.thread().unpark();
93 Ok(buf.len())
94 }
95}
96
97impl embedded_io_async::Read for AsyncTcp {
98 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
99 struct WaitForWaker<'a>(&'a AtomicWaker, bool);
100
101 impl<'a> Future for WaitForWaker<'a> {
102 type Output = ();
103
104 fn poll(
105 mut self: std::pin::Pin<&mut Self>,
106 cx: &mut std::task::Context<'_>,
107 ) -> std::task::Poll<Self::Output> {
108 if self.1 {
109 std::task::Poll::Ready(())
110 } else {
111 self.as_mut().1 = true;
112 self.0.register(cx.waker());
113 std::task::Poll::Pending
114 }
115 }
116 }
117
118 loop {
119 {
120 let mut buffer = self.read_buffer.lock().unwrap();
121 if !buffer.is_empty() {
122 let copy_n = buf.len().min(buffer.len());
123 buf[..copy_n].copy_from_slice(&buffer[..copy_n]);
124 buffer.drain(..copy_n);
125 return Ok(copy_n);
126 }
127 }
128 WaitForWaker(&self.waker, false).await
129 }
130 }
131}
132
133#[embassy_executor::task]
134async fn main_task(spawner: Spawner) {
135 let mut stream = AsyncTcp::connect("mqtt.d464.sh:1883");
136
137 let mut device = embassy_ha::Device::new(
138 RESOURCES.init(Default::default()),
139 embassy_ha::DeviceConfig {
140 device_id: "example-device-id",
141 device_name: "Example Device Name",
142 manufacturer: "Example Device Manufacturer",
143 model: "Example Device Model",
144 },
145 );
146
147 let temperature_sensor = device.create_temperature_sensor(
148 "temperature-sensor-id",
149 "Temperature Sensor Name",
150 embassy_ha::TemperatureUnit::Celcius,
151 );
152
153 spawner.must_spawn(temperature(temperature_sensor));
154
155 device.run(&mut stream).await;
156}
157
158#[embassy_executor::task]
159async fn temperature(mut sensor: embassy_ha::TemperatureSensor<'static>) {
160 loop {
161 sensor.publish(42.0);
162 Timer::after_secs(1).await;
163 }
164}
165
166fn main() {
167 let executor = EXECUTOR.init(Executor::new());
168 executor.run(|spawner| {
169 spawner.must_spawn(main_task(spawner));
170 });
171}