├── .cargo └── config.toml ├── .gitignore ├── .vscode └── settings.json ├── Cargo.lock ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── doc └── screenshot.png ├── rust-toolchain.toml └── src ├── bmp180.rs ├── main.rs └── tiny_mqtt.rs /.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [target.xtensa-esp32-none-elf] 2 | runner = "espflash flash --monitor" 3 | 4 | [build] 5 | rustflags = [ 6 | "-C", "link-arg=-nostartfiles", 7 | "-C", "link-arg=-Wl,-Tlinkall.x", 8 | "-C", "link-arg=-Tesp32_rom_functions.x", 9 | ] 10 | target = "xtensa-esp32-none-elf" 11 | 12 | [unstable] 13 | build-std = ["core"] 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | debug/ 4 | target/ 5 | 6 | # These are backup files generated by rustfmt 7 | **/*.rs.bk 8 | 9 | # MSVC Windows builds of rustc generate these, which store debugging information 10 | *.pdb 11 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "rust-analyzer.checkOnSave.allTargets": false, 3 | } 4 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "aho-corasick" 7 | version = "0.7.20" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" 10 | dependencies = [ 11 | "memchr", 12 | ] 13 | 14 | [[package]] 15 | name = "anyhow" 16 | version = "1.0.70" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4" 19 | 20 | [[package]] 21 | name = "atomic-polyfill" 22 | version = "0.1.11" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "e3ff7eb3f316534d83a8a2c3d1674ace8a5a71198eba31e2e2b597833f699b28" 25 | dependencies = [ 26 | "critical-section", 27 | ] 28 | 29 | [[package]] 30 | name = "atomic-polyfill" 31 | version = "1.0.2" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "c314e70d181aa6053b26e3f7fbf86d1dfff84f816a6175b967666b3506ef7289" 34 | dependencies = [ 35 | "critical-section", 36 | ] 37 | 38 | [[package]] 39 | name = "atomic-waker" 40 | version = "1.1.1" 41 | source = "registry+https://github.com/rust-lang/crates.io-index" 42 | checksum = "1181e1e0d1fce796a03db1ae795d67167da795f9cf4a39c37589e85ef57f26d3" 43 | 44 | [[package]] 45 | name = "autocfg" 46 | version = "1.1.0" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 49 | 50 | [[package]] 51 | name = "bare-metal" 52 | version = "1.0.0" 53 | source = "registry+https://github.com/rust-lang/crates.io-index" 54 | checksum = "f8fe8f5a8a398345e52358e18ff07cc17a568fbca5c6f73873d3a62056309603" 55 | 56 | [[package]] 57 | name = "basic-toml" 58 | version = "0.1.2" 59 | source = "registry+https://github.com/rust-lang/crates.io-index" 60 | checksum = "5c0de75129aa8d0cceaf750b89013f0e08804d6ec61416da787b35ad0d7cddf1" 61 | dependencies = [ 62 | "serde", 63 | ] 64 | 65 | [[package]] 66 | name = "bitflags" 67 | version = "1.3.2" 68 | source = "registry+https://github.com/rust-lang/crates.io-index" 69 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 70 | 71 | [[package]] 72 | name = "bitflags" 73 | version = "2.3.3" 74 | source = "registry+https://github.com/rust-lang/crates.io-index" 75 | checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" 76 | 77 | [[package]] 78 | name = "byteorder" 79 | version = "1.4.3" 80 | source = "registry+https://github.com/rust-lang/crates.io-index" 81 | checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" 82 | 83 | [[package]] 84 | name = "cfg-if" 85 | version = "1.0.0" 86 | source = "registry+https://github.com/rust-lang/crates.io-index" 87 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 88 | 89 | [[package]] 90 | name = "core-isa-parser" 91 | version = "0.2.0" 92 | source = "registry+https://github.com/rust-lang/crates.io-index" 93 | checksum = "23ec98e54b735872e54b2335c2e5a5c7fa7d9c3bfd45500f75280f84089a0083" 94 | dependencies = [ 95 | "anyhow", 96 | "enum-as-inner", 97 | "regex", 98 | "strum", 99 | "strum_macros", 100 | ] 101 | 102 | [[package]] 103 | name = "critical-section" 104 | version = "1.1.1" 105 | source = "registry+https://github.com/rust-lang/crates.io-index" 106 | checksum = "6548a0ad5d2549e111e1f6a11a6c2e2d00ce6a3dafe22948d67c2b443f775e52" 107 | 108 | [[package]] 109 | name = "darling" 110 | version = "0.14.4" 111 | source = "registry+https://github.com/rust-lang/crates.io-index" 112 | checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" 113 | dependencies = [ 114 | "darling_core 0.14.4", 115 | "darling_macro 0.14.4", 116 | ] 117 | 118 | [[package]] 119 | name = "darling" 120 | version = "0.20.3" 121 | source = "registry+https://github.com/rust-lang/crates.io-index" 122 | checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" 123 | dependencies = [ 124 | "darling_core 0.20.3", 125 | "darling_macro 0.20.3", 126 | ] 127 | 128 | [[package]] 129 | name = "darling_core" 130 | version = "0.14.4" 131 | source = "registry+https://github.com/rust-lang/crates.io-index" 132 | checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" 133 | dependencies = [ 134 | "fnv", 135 | "ident_case", 136 | "proc-macro2", 137 | "quote", 138 | "syn 1.0.109", 139 | ] 140 | 141 | [[package]] 142 | name = "darling_core" 143 | version = "0.20.3" 144 | source = "registry+https://github.com/rust-lang/crates.io-index" 145 | checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621" 146 | dependencies = [ 147 | "fnv", 148 | "ident_case", 149 | "proc-macro2", 150 | "quote", 151 | "strsim", 152 | "syn 2.0.26", 153 | ] 154 | 155 | [[package]] 156 | name = "darling_macro" 157 | version = "0.14.4" 158 | source = "registry+https://github.com/rust-lang/crates.io-index" 159 | checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" 160 | dependencies = [ 161 | "darling_core 0.14.4", 162 | "quote", 163 | "syn 1.0.109", 164 | ] 165 | 166 | [[package]] 167 | name = "darling_macro" 168 | version = "0.20.3" 169 | source = "registry+https://github.com/rust-lang/crates.io-index" 170 | checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" 171 | dependencies = [ 172 | "darling_core 0.20.3", 173 | "quote", 174 | "syn 2.0.26", 175 | ] 176 | 177 | [[package]] 178 | name = "embedded-dma" 179 | version = "0.2.0" 180 | source = "registry+https://github.com/rust-lang/crates.io-index" 181 | checksum = "994f7e5b5cb23521c22304927195f236813053eb9c065dd2226a32ba64695446" 182 | dependencies = [ 183 | "stable_deref_trait", 184 | ] 185 | 186 | [[package]] 187 | name = "embedded-hal" 188 | version = "0.2.7" 189 | source = "registry+https://github.com/rust-lang/crates.io-index" 190 | checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff" 191 | dependencies = [ 192 | "nb 0.1.3", 193 | "void", 194 | ] 195 | 196 | [[package]] 197 | name = "embedded-io" 198 | version = "0.4.0" 199 | source = "registry+https://github.com/rust-lang/crates.io-index" 200 | checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" 201 | 202 | [[package]] 203 | name = "embedded-svc" 204 | version = "0.25.3" 205 | source = "registry+https://github.com/rust-lang/crates.io-index" 206 | checksum = "adb928fd4f8e71dee7628bbab86b25df74c503fc5209cfeeb174a9806bb4fd11" 207 | dependencies = [ 208 | "atomic-waker", 209 | "embedded-io", 210 | "enumset", 211 | "heapless", 212 | "no-std-net", 213 | "serde", 214 | ] 215 | 216 | [[package]] 217 | name = "enum-as-inner" 218 | version = "0.4.0" 219 | source = "registry+https://github.com/rust-lang/crates.io-index" 220 | checksum = "21cdad81446a7f7dc43f6a77409efeb9733d2fa65553efef6018ef257c959b73" 221 | dependencies = [ 222 | "heck", 223 | "proc-macro2", 224 | "quote", 225 | "syn 1.0.109", 226 | ] 227 | 228 | [[package]] 229 | name = "enumset" 230 | version = "1.0.12" 231 | source = "registry+https://github.com/rust-lang/crates.io-index" 232 | checksum = "19be8061a06ab6f3a6cf21106c873578bf01bd42ad15e0311a9c76161cb1c753" 233 | dependencies = [ 234 | "enumset_derive", 235 | ] 236 | 237 | [[package]] 238 | name = "enumset_derive" 239 | version = "0.6.1" 240 | source = "registry+https://github.com/rust-lang/crates.io-index" 241 | checksum = "03e7b551eba279bf0fa88b83a46330168c1560a52a94f5126f892f0b364ab3e0" 242 | dependencies = [ 243 | "darling 0.14.4", 244 | "proc-macro2", 245 | "quote", 246 | "syn 1.0.109", 247 | ] 248 | 249 | [[package]] 250 | name = "esp-backtrace" 251 | version = "0.7.0" 252 | source = "registry+https://github.com/rust-lang/crates.io-index" 253 | checksum = "b151ef7db21143b1a3b7a378c16d97ae13d0a5e3cb9682ed1f11bba821cce42d" 254 | dependencies = [ 255 | "esp-println", 256 | ] 257 | 258 | [[package]] 259 | name = "esp-hal-common" 260 | version = "0.10.0" 261 | source = "registry+https://github.com/rust-lang/crates.io-index" 262 | checksum = "05d4498ddbbbf9a21e64f9269d2b4dd4059c34863ff54c702fb99e435f967767" 263 | dependencies = [ 264 | "basic-toml", 265 | "bitflags 2.3.3", 266 | "cfg-if", 267 | "critical-section", 268 | "embedded-dma", 269 | "embedded-hal", 270 | "esp-hal-procmacros", 271 | "esp32", 272 | "fugit", 273 | "lock_api", 274 | "log", 275 | "nb 1.1.0", 276 | "paste", 277 | "serde", 278 | "strum", 279 | "void", 280 | "xtensa-lx", 281 | "xtensa-lx-rt", 282 | ] 283 | 284 | [[package]] 285 | name = "esp-hal-procmacros" 286 | version = "0.6.0" 287 | source = "registry+https://github.com/rust-lang/crates.io-index" 288 | checksum = "042d5a1ef0e01d6de045972779e4aced3a10e6170169a5cb2de7bef31802e28a" 289 | dependencies = [ 290 | "darling 0.20.3", 291 | "proc-macro-crate", 292 | "proc-macro-error", 293 | "proc-macro2", 294 | "quote", 295 | "syn 2.0.26", 296 | ] 297 | 298 | [[package]] 299 | name = "esp-println" 300 | version = "0.5.0" 301 | source = "registry+https://github.com/rust-lang/crates.io-index" 302 | checksum = "af6a511d37dba5fb8f01bf5485bc619a1a1959e1aaf666a7597df8fe615a0816" 303 | dependencies = [ 304 | "critical-section", 305 | "log", 306 | ] 307 | 308 | [[package]] 309 | name = "esp-wifi" 310 | version = "0.1.0" 311 | source = "git+https://github.com/esp-rs/esp-wifi.git?rev=37dd9ed7ae07a86f7afaef34fa4cbb48ad41b210#37dd9ed7ae07a86f7afaef34fa4cbb48ad41b210" 312 | dependencies = [ 313 | "atomic-polyfill 1.0.2", 314 | "critical-section", 315 | "embedded-hal", 316 | "embedded-io", 317 | "embedded-svc", 318 | "enumset", 319 | "esp-hal-common", 320 | "esp-wifi-sys", 321 | "esp32-hal", 322 | "fugit", 323 | "heapless", 324 | "linked_list_allocator", 325 | "log", 326 | "num-derive", 327 | "num-traits", 328 | "smoltcp", 329 | ] 330 | 331 | [[package]] 332 | name = "esp-wifi-sys" 333 | version = "0.1.0" 334 | source = "git+https://github.com/esp-rs/esp-wifi.git?rev=37dd9ed7ae07a86f7afaef34fa4cbb48ad41b210#37dd9ed7ae07a86f7afaef34fa4cbb48ad41b210" 335 | dependencies = [ 336 | "anyhow", 337 | ] 338 | 339 | [[package]] 340 | name = "esp32" 341 | version = "0.24.0" 342 | source = "registry+https://github.com/rust-lang/crates.io-index" 343 | checksum = "4e0a6cd6fdb2f8fd98e65d12c1ccc24d3410def1a8a9b660a64d15dfe70b6857" 344 | dependencies = [ 345 | "critical-section", 346 | "vcell", 347 | "xtensa-lx", 348 | ] 349 | 350 | [[package]] 351 | name = "esp32-hal" 352 | version = "0.13.0" 353 | source = "registry+https://github.com/rust-lang/crates.io-index" 354 | checksum = "769fa34985651980dd337a5784285a24cd7f122700f3d5c4a027d4401b028aa2" 355 | dependencies = [ 356 | "embedded-hal", 357 | "esp-hal-common", 358 | ] 359 | 360 | [[package]] 361 | name = "esp32_nostd_mqtt" 362 | version = "0.1.0" 363 | dependencies = [ 364 | "embedded-hal", 365 | "embedded-io", 366 | "embedded-svc", 367 | "esp-backtrace", 368 | "esp-println", 369 | "esp-wifi", 370 | "esp32-hal", 371 | "heapless", 372 | "log", 373 | "mqttrust", 374 | "nb 1.1.0", 375 | "smoltcp", 376 | ] 377 | 378 | [[package]] 379 | name = "fnv" 380 | version = "1.0.7" 381 | source = "registry+https://github.com/rust-lang/crates.io-index" 382 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 383 | 384 | [[package]] 385 | name = "fugit" 386 | version = "0.3.7" 387 | source = "registry+https://github.com/rust-lang/crates.io-index" 388 | checksum = "17186ad64927d5ac8f02c1e77ccefa08ccd9eaa314d5a4772278aa204a22f7e7" 389 | dependencies = [ 390 | "gcd", 391 | ] 392 | 393 | [[package]] 394 | name = "gcd" 395 | version = "2.3.0" 396 | source = "registry+https://github.com/rust-lang/crates.io-index" 397 | checksum = "1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a" 398 | 399 | [[package]] 400 | name = "hash32" 401 | version = "0.2.1" 402 | source = "registry+https://github.com/rust-lang/crates.io-index" 403 | checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" 404 | dependencies = [ 405 | "byteorder", 406 | ] 407 | 408 | [[package]] 409 | name = "hashbrown" 410 | version = "0.12.3" 411 | source = "registry+https://github.com/rust-lang/crates.io-index" 412 | checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" 413 | 414 | [[package]] 415 | name = "heapless" 416 | version = "0.7.16" 417 | source = "registry+https://github.com/rust-lang/crates.io-index" 418 | checksum = "db04bc24a18b9ea980628ecf00e6c0264f3c1426dac36c00cb49b6fbad8b0743" 419 | dependencies = [ 420 | "atomic-polyfill 0.1.11", 421 | "hash32", 422 | "rustc_version", 423 | "spin", 424 | "stable_deref_trait", 425 | ] 426 | 427 | [[package]] 428 | name = "heck" 429 | version = "0.4.1" 430 | source = "registry+https://github.com/rust-lang/crates.io-index" 431 | checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" 432 | 433 | [[package]] 434 | name = "ident_case" 435 | version = "1.0.1" 436 | source = "registry+https://github.com/rust-lang/crates.io-index" 437 | checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" 438 | 439 | [[package]] 440 | name = "indexmap" 441 | version = "1.9.3" 442 | source = "registry+https://github.com/rust-lang/crates.io-index" 443 | checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" 444 | dependencies = [ 445 | "autocfg", 446 | "hashbrown", 447 | ] 448 | 449 | [[package]] 450 | name = "linked_list_allocator" 451 | version = "0.10.5" 452 | source = "registry+https://github.com/rust-lang/crates.io-index" 453 | checksum = "9afa463f5405ee81cdb9cc2baf37e08ec7e4c8209442b5d72c04cfb2cd6e6286" 454 | 455 | [[package]] 456 | name = "lock_api" 457 | version = "0.4.10" 458 | source = "registry+https://github.com/rust-lang/crates.io-index" 459 | checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" 460 | dependencies = [ 461 | "autocfg", 462 | "scopeguard", 463 | ] 464 | 465 | [[package]] 466 | name = "log" 467 | version = "0.4.18" 468 | source = "registry+https://github.com/rust-lang/crates.io-index" 469 | checksum = "518ef76f2f87365916b142844c16d8fefd85039bc5699050210a7778ee1cd1de" 470 | 471 | [[package]] 472 | name = "managed" 473 | version = "0.8.0" 474 | source = "registry+https://github.com/rust-lang/crates.io-index" 475 | checksum = "0ca88d725a0a943b096803bd34e73a4437208b6077654cc4ecb2947a5f91618d" 476 | 477 | [[package]] 478 | name = "memchr" 479 | version = "2.5.0" 480 | source = "registry+https://github.com/rust-lang/crates.io-index" 481 | checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" 482 | 483 | [[package]] 484 | name = "minijinja" 485 | version = "0.15.0" 486 | source = "registry+https://github.com/rust-lang/crates.io-index" 487 | checksum = "359c4820413be7706e93999171652e140578384f85faac14cb22d350bd0fbabf" 488 | dependencies = [ 489 | "serde", 490 | ] 491 | 492 | [[package]] 493 | name = "mqttrust" 494 | version = "0.6.0" 495 | source = "registry+https://github.com/rust-lang/crates.io-index" 496 | checksum = "ae32f7b780d20b0fc574bba0ca71b33838bb264d7a48b098cd18e3327c30edde" 497 | dependencies = [ 498 | "heapless", 499 | ] 500 | 501 | [[package]] 502 | name = "mutex-trait" 503 | version = "0.2.0" 504 | source = "registry+https://github.com/rust-lang/crates.io-index" 505 | checksum = "b4bb1638d419e12f8b1c43d9e639abd0d1424285bdea2f76aa231e233c63cd3a" 506 | 507 | [[package]] 508 | name = "nb" 509 | version = "0.1.3" 510 | source = "registry+https://github.com/rust-lang/crates.io-index" 511 | checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" 512 | dependencies = [ 513 | "nb 1.1.0", 514 | ] 515 | 516 | [[package]] 517 | name = "nb" 518 | version = "1.1.0" 519 | source = "registry+https://github.com/rust-lang/crates.io-index" 520 | checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" 521 | 522 | [[package]] 523 | name = "no-std-net" 524 | version = "0.5.0" 525 | source = "registry+https://github.com/rust-lang/crates.io-index" 526 | checksum = "1bcece43b12349917e096cddfa66107277f123e6c96a5aea78711dc601a47152" 527 | 528 | [[package]] 529 | name = "num-derive" 530 | version = "0.3.3" 531 | source = "registry+https://github.com/rust-lang/crates.io-index" 532 | checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" 533 | dependencies = [ 534 | "proc-macro2", 535 | "quote", 536 | "syn 1.0.109", 537 | ] 538 | 539 | [[package]] 540 | name = "num-traits" 541 | version = "0.2.15" 542 | source = "registry+https://github.com/rust-lang/crates.io-index" 543 | checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" 544 | dependencies = [ 545 | "autocfg", 546 | ] 547 | 548 | [[package]] 549 | name = "once_cell" 550 | version = "1.17.1" 551 | source = "registry+https://github.com/rust-lang/crates.io-index" 552 | checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" 553 | 554 | [[package]] 555 | name = "paste" 556 | version = "1.0.12" 557 | source = "registry+https://github.com/rust-lang/crates.io-index" 558 | checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" 559 | 560 | [[package]] 561 | name = "proc-macro-crate" 562 | version = "1.3.1" 563 | source = "registry+https://github.com/rust-lang/crates.io-index" 564 | checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" 565 | dependencies = [ 566 | "once_cell", 567 | "toml_edit", 568 | ] 569 | 570 | [[package]] 571 | name = "proc-macro-error" 572 | version = "1.0.4" 573 | source = "registry+https://github.com/rust-lang/crates.io-index" 574 | checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" 575 | dependencies = [ 576 | "proc-macro-error-attr", 577 | "proc-macro2", 578 | "quote", 579 | "syn 1.0.109", 580 | "version_check", 581 | ] 582 | 583 | [[package]] 584 | name = "proc-macro-error-attr" 585 | version = "1.0.4" 586 | source = "registry+https://github.com/rust-lang/crates.io-index" 587 | checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" 588 | dependencies = [ 589 | "proc-macro2", 590 | "quote", 591 | "version_check", 592 | ] 593 | 594 | [[package]] 595 | name = "proc-macro2" 596 | version = "1.0.66" 597 | source = "registry+https://github.com/rust-lang/crates.io-index" 598 | checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" 599 | dependencies = [ 600 | "unicode-ident", 601 | ] 602 | 603 | [[package]] 604 | name = "quote" 605 | version = "1.0.31" 606 | source = "registry+https://github.com/rust-lang/crates.io-index" 607 | checksum = "5fe8a65d69dd0808184ebb5f836ab526bb259db23c657efa38711b1072ee47f0" 608 | dependencies = [ 609 | "proc-macro2", 610 | ] 611 | 612 | [[package]] 613 | name = "r0" 614 | version = "1.0.0" 615 | source = "registry+https://github.com/rust-lang/crates.io-index" 616 | checksum = "bd7a31eed1591dcbc95d92ad7161908e72f4677f8fabf2a32ca49b4237cbf211" 617 | 618 | [[package]] 619 | name = "regex" 620 | version = "1.7.3" 621 | source = "registry+https://github.com/rust-lang/crates.io-index" 622 | checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d" 623 | dependencies = [ 624 | "aho-corasick", 625 | "memchr", 626 | "regex-syntax", 627 | ] 628 | 629 | [[package]] 630 | name = "regex-syntax" 631 | version = "0.6.29" 632 | source = "registry+https://github.com/rust-lang/crates.io-index" 633 | checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" 634 | 635 | [[package]] 636 | name = "rustc_version" 637 | version = "0.4.0" 638 | source = "registry+https://github.com/rust-lang/crates.io-index" 639 | checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" 640 | dependencies = [ 641 | "semver", 642 | ] 643 | 644 | [[package]] 645 | name = "rustversion" 646 | version = "1.0.12" 647 | source = "registry+https://github.com/rust-lang/crates.io-index" 648 | checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" 649 | 650 | [[package]] 651 | name = "scopeguard" 652 | version = "1.1.0" 653 | source = "registry+https://github.com/rust-lang/crates.io-index" 654 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 655 | 656 | [[package]] 657 | name = "semver" 658 | version = "1.0.17" 659 | source = "registry+https://github.com/rust-lang/crates.io-index" 660 | checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" 661 | 662 | [[package]] 663 | name = "serde" 664 | version = "1.0.173" 665 | source = "registry+https://github.com/rust-lang/crates.io-index" 666 | checksum = "e91f70896d6720bc714a4a57d22fc91f1db634680e65c8efe13323f1fa38d53f" 667 | dependencies = [ 668 | "serde_derive", 669 | ] 670 | 671 | [[package]] 672 | name = "serde_derive" 673 | version = "1.0.173" 674 | source = "registry+https://github.com/rust-lang/crates.io-index" 675 | checksum = "a6250dde8342e0232232be9ca3db7aa40aceb5a3e5dd9bddbc00d99a007cde49" 676 | dependencies = [ 677 | "proc-macro2", 678 | "quote", 679 | "syn 2.0.26", 680 | ] 681 | 682 | [[package]] 683 | name = "smoltcp" 684 | version = "0.10.0" 685 | source = "registry+https://github.com/rust-lang/crates.io-index" 686 | checksum = "8d2e3a36ac8fea7b94e666dfa3871063d6e0a5c9d5d4fec9a1a6b7b6760f0229" 687 | dependencies = [ 688 | "bitflags 1.3.2", 689 | "byteorder", 690 | "cfg-if", 691 | "heapless", 692 | "managed", 693 | ] 694 | 695 | [[package]] 696 | name = "spin" 697 | version = "0.9.7" 698 | source = "registry+https://github.com/rust-lang/crates.io-index" 699 | checksum = "c0959fd6f767df20b231736396e4f602171e00d95205676286e79d4a4eb67bef" 700 | dependencies = [ 701 | "lock_api", 702 | ] 703 | 704 | [[package]] 705 | name = "stable_deref_trait" 706 | version = "1.2.0" 707 | source = "registry+https://github.com/rust-lang/crates.io-index" 708 | checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" 709 | 710 | [[package]] 711 | name = "strsim" 712 | version = "0.10.0" 713 | source = "registry+https://github.com/rust-lang/crates.io-index" 714 | checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" 715 | 716 | [[package]] 717 | name = "strum" 718 | version = "0.24.1" 719 | source = "registry+https://github.com/rust-lang/crates.io-index" 720 | checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" 721 | dependencies = [ 722 | "strum_macros", 723 | ] 724 | 725 | [[package]] 726 | name = "strum_macros" 727 | version = "0.24.3" 728 | source = "registry+https://github.com/rust-lang/crates.io-index" 729 | checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" 730 | dependencies = [ 731 | "heck", 732 | "proc-macro2", 733 | "quote", 734 | "rustversion", 735 | "syn 1.0.109", 736 | ] 737 | 738 | [[package]] 739 | name = "syn" 740 | version = "1.0.109" 741 | source = "registry+https://github.com/rust-lang/crates.io-index" 742 | checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" 743 | dependencies = [ 744 | "proc-macro2", 745 | "quote", 746 | "unicode-ident", 747 | ] 748 | 749 | [[package]] 750 | name = "syn" 751 | version = "2.0.26" 752 | source = "registry+https://github.com/rust-lang/crates.io-index" 753 | checksum = "45c3457aacde3c65315de5031ec191ce46604304d2446e803d71ade03308d970" 754 | dependencies = [ 755 | "proc-macro2", 756 | "quote", 757 | "unicode-ident", 758 | ] 759 | 760 | [[package]] 761 | name = "toml_datetime" 762 | version = "0.6.1" 763 | source = "registry+https://github.com/rust-lang/crates.io-index" 764 | checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622" 765 | 766 | [[package]] 767 | name = "toml_edit" 768 | version = "0.19.8" 769 | source = "registry+https://github.com/rust-lang/crates.io-index" 770 | checksum = "239410c8609e8125456927e6707163a3b1fdb40561e4b803bc041f466ccfdc13" 771 | dependencies = [ 772 | "indexmap", 773 | "toml_datetime", 774 | "winnow", 775 | ] 776 | 777 | [[package]] 778 | name = "unicode-ident" 779 | version = "1.0.8" 780 | source = "registry+https://github.com/rust-lang/crates.io-index" 781 | checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" 782 | 783 | [[package]] 784 | name = "vcell" 785 | version = "0.1.3" 786 | source = "registry+https://github.com/rust-lang/crates.io-index" 787 | checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" 788 | 789 | [[package]] 790 | name = "version_check" 791 | version = "0.9.4" 792 | source = "registry+https://github.com/rust-lang/crates.io-index" 793 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 794 | 795 | [[package]] 796 | name = "void" 797 | version = "1.0.2" 798 | source = "registry+https://github.com/rust-lang/crates.io-index" 799 | checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" 800 | 801 | [[package]] 802 | name = "winnow" 803 | version = "0.4.1" 804 | source = "registry+https://github.com/rust-lang/crates.io-index" 805 | checksum = "ae8970b36c66498d8ff1d66685dc86b91b29db0c7739899012f63a63814b4b28" 806 | dependencies = [ 807 | "memchr", 808 | ] 809 | 810 | [[package]] 811 | name = "xtensa-lx" 812 | version = "0.8.0" 813 | source = "registry+https://github.com/rust-lang/crates.io-index" 814 | checksum = "9490addc0a1edd86e571a9ed8063f33d8224f981e61bbf72279671ed0cb4bb7c" 815 | dependencies = [ 816 | "bare-metal", 817 | "mutex-trait", 818 | "spin", 819 | ] 820 | 821 | [[package]] 822 | name = "xtensa-lx-rt" 823 | version = "0.15.0" 824 | source = "registry+https://github.com/rust-lang/crates.io-index" 825 | checksum = "f68fea36eb8e2d5ff4c99d367527f4a56e484b16c5e84abf4195988bd845a3fc" 826 | dependencies = [ 827 | "bare-metal", 828 | "core-isa-parser", 829 | "minijinja", 830 | "r0", 831 | "xtensa-lx-rt-proc-macros", 832 | ] 833 | 834 | [[package]] 835 | name = "xtensa-lx-rt-proc-macros" 836 | version = "0.2.0" 837 | source = "registry+https://github.com/rust-lang/crates.io-index" 838 | checksum = "3283815e334d3e5d21868dc3c7140720b2a784238289b1127b67908c89404b79" 839 | dependencies = [ 840 | "proc-macro2", 841 | "quote", 842 | "syn 1.0.109", 843 | ] 844 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "esp32_nostd_mqtt" 3 | version = "0.1.0" 4 | authors = ["bjoernQ "] 5 | edition = "2021" 6 | license = "MIT OR Apache-2.0" 7 | 8 | [profile.release] 9 | opt-level = "s" 10 | 11 | [dependencies] 12 | esp32-hal = "0.13.0" 13 | 14 | esp-wifi = { git = "https://github.com/esp-rs/esp-wifi.git", features = ["esp32", "embedded-svc", "wifi"], rev = "37dd9ed7ae07a86f7afaef34fa4cbb48ad41b210" } 15 | smoltcp = { version = "0.10.0", default-features=false, features = ["proto-igmp", "proto-ipv4", "socket-tcp", "socket-icmp", "socket-udp", "medium-ethernet", "proto-dhcpv4", "socket-raw", "socket-dhcpv4"] } 16 | embedded-svc = { version = "0.25.3", default-features = false } 17 | mqttrust = "0.6.0" 18 | log = "0.4.16" 19 | nb = "1.0.0" 20 | embedded-hal = "0.2" 21 | esp-println = { version = "0.5.0", features = [ "esp32", "uart", "log" ] } 22 | esp-backtrace = { version = "0.7.0", features = [ "esp32", "panic-handler", "print-uart" ] } 23 | embedded-io = "0.4.0" 24 | heapless = "0.7.16" 25 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright [year] [fullname] 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Demo of Rust on ESP32 (no RTOS) with MQTT and adafruit.io for temperature logging 2 | 3 | ## About 4 | 5 | This will read the temperature from a connected BMP180 sensor via I2C and send it via MQTT to adafruit.io every minute. 6 | 7 | ![Screenshot](./doc/screenshot.png "Screenshot") 8 | 9 | It publishes the temperature value to the topic `/feeds/temperature` 10 | 11 | ## Setting Credentials 12 | 13 | You need to set these environment variables for a successful build. 14 | 15 | |Name|Value| 16 | |---|---| 17 | |SSID|SSID of your WiFi access point| 18 | |PASSWORD|Your WiFi password| 19 | |ADAFRUIT_IO_USERNAME|Your adafruit.io username| 20 | |ADAFRUIT_IO_KEY|Your adafruit.io API key| 21 | 22 | To run the application connect your ESP32 development board with the BMP180 connected and execute `cargo run --release` 23 | 24 | Make sure to have the [Xtensa enabled Rust toolchain](https://github.com/esp-rs/rust-build) installed. 25 | 26 | ## Wiring the BMP180 temperature sensor 27 | 28 | |BMP180|ESP32| 29 | |---|---| 30 | |SDA|IO32| 31 | |SCL|IO33| 32 | |GND|GND| 33 | |VCC|3.3V| 34 | 35 | ## License 36 | 37 | Licensed under either of: 38 | 39 | - Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) 40 | - MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) 41 | 42 | at your option. 43 | 44 | ### Contribution 45 | 46 | Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in 47 | the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without 48 | any additional terms or conditions. 49 | -------------------------------------------------------------------------------- /doc/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bjoernQ/esp32-rust-nostd-temperature-logger/85c3cfccaf1535e5346c7916a41e00e798b46c44/doc/screenshot.png -------------------------------------------------------------------------------- /rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "esp" 3 | -------------------------------------------------------------------------------- /src/bmp180.rs: -------------------------------------------------------------------------------- 1 | use embedded_hal::blocking::i2c::*; 2 | 3 | const ADDRESS: u8 = 0x77; 4 | 5 | pub struct Bmp180 6 | where 7 | T: WriteRead + Read + Write, 8 | { 9 | i2c: T, 10 | ac1: i32, 11 | ac2: i32, 12 | ac3: i32, 13 | ac4: i32, 14 | ac5: i32, 15 | ac6: i32, 16 | b1: i32, 17 | b2: i32, 18 | mb: i32, 19 | mc: i32, 20 | md: i32, 21 | 22 | temp: f32, 23 | 24 | sleep_fn: fn(u32) -> (), 25 | } 26 | 27 | impl Bmp180 28 | where 29 | T: WriteRead + Read + Write, 30 | { 31 | pub fn new(i2c: T, sleep_fn: fn(u32) -> ()) -> Bmp180 { 32 | let mut i2c = i2c; 33 | let mut data = [0u8; 22]; 34 | 35 | i2c.write_read(ADDRESS, &[0xaa], &mut data).ok(); 36 | 37 | let ac1 = ((data[0] as u16) << 8 | data[1] as u16) as i16 as i32; 38 | let ac2 = ((data[2] as u16) << 8 | data[3] as u16) as i16 as i32; 39 | let ac3 = ((data[4] as u16) << 8 | data[5] as u16) as i16 as i32; 40 | let ac4 = ((data[6] as u16) << 8 | data[7] as u16) as i16 as i32; 41 | let ac5 = ((data[8] as u16) << 8 | data[8] as u16) as i16 as i32; 42 | let ac6 = ((data[10] as u16) << 8 | data[11] as u16) as i16 as i32; 43 | let b1 = ((data[12] as u16) << 8 | data[13] as u16) as i16 as i32; 44 | let b2 = ((data[14] as u16) << 8 | data[15] as u16) as i16 as i32; 45 | let mb = ((data[16] as u16) << 8 | data[17] as u16) as i16 as i32; 46 | let mc = ((data[18] as u16) << 8 | data[19] as u16) as i16 as i32; 47 | let md = ((data[20] as u16) << 8 | data[21] as u16) as i16 as i32; 48 | 49 | Self { 50 | i2c, 51 | ac1, 52 | ac2, 53 | ac3, 54 | ac4, 55 | ac5, 56 | ac6, 57 | b1, 58 | b2, 59 | mb, 60 | mc, 61 | md, 62 | 63 | temp: 0f32, 64 | 65 | sleep_fn, 66 | } 67 | } 68 | 69 | pub fn measure(&mut self) { 70 | // Select measurement control register 71 | // Enable temperature measurement 72 | self.i2c.write(ADDRESS, &[0xf4, 0x2e]).ok(); 73 | (self.sleep_fn)(100); 74 | 75 | // Read 2 bytes of data from address 0xF6(246) 76 | // temp msb, temp lsb 77 | let mut data = [0u8; 2]; 78 | self.i2c.write_read(ADDRESS, &[0xF6], &mut data).ok(); 79 | 80 | // Convert the data 81 | let temp = (data[0] as u32) << 8 | data[1] as u32; 82 | 83 | // Select measurement control register 84 | // Enable pressure measurement, OSS = 1 85 | self.i2c.write(ADDRESS, &[0xf4, 0x74]).ok(); 86 | (self.sleep_fn)(100); 87 | 88 | // Callibration for Temperature 89 | let x1: f64 = (temp as f64 - self.ac6 as f64) * self.ac5 as f64 / 32768.0; 90 | let x2: f64 = (self.mc as f64 * 2048.0) / (x1 + self.md as f64); 91 | let b5: f64 = x1 + x2; 92 | let c_temp: f64 = ((b5 + 8.0) / 16.0) / 10.0; 93 | 94 | self.temp = c_temp as f32; 95 | } 96 | 97 | pub fn get_temperature(&self) -> f32 { 98 | self.temp 99 | } 100 | } 101 | 102 | impl core::fmt::Debug for Bmp180 103 | where 104 | T: WriteRead + Read + Write, 105 | { 106 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 107 | f.debug_struct("Bmp180") 108 | .field("ac1", &self.ac1) 109 | .field("ac2", &self.ac2) 110 | .field("ac3", &self.ac3) 111 | .field("ac4", &self.ac4) 112 | .field("ac5", &self.ac5) 113 | .field("ac6", &self.ac6) 114 | .field("b1", &self.b1) 115 | .field("b2", &self.b2) 116 | .field("mb", &self.mb) 117 | .field("mc", &self.mc) 118 | .field("md", &self.md) 119 | .field("temp", &self.temp) 120 | .finish() 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use core::fmt::Write; 5 | 6 | use embedded_hal::watchdog::WatchdogDisable; 7 | 8 | use embedded_svc::ipv4::Interface; 9 | use embedded_svc::wifi::{ClientConfiguration, Configuration, Wifi}; 10 | use esp32_hal::clock::ClockControl; 11 | use esp32_hal::clock::CpuClock; 12 | use esp32_hal::i2c::I2C; 13 | use esp32_hal::peripherals::Peripherals; 14 | use esp32_hal::prelude::_fugit_RateExtU32; 15 | use esp32_hal::timer::TimerGroup; 16 | use esp32_hal::Rtc; 17 | use esp32_hal::IO; 18 | use esp32_hal::{prelude::*, Rng}; 19 | use esp_backtrace as _; 20 | use esp_println::println; 21 | use esp_wifi::wifi::utils::create_network_interface; 22 | use esp_wifi::wifi::WifiMode; 23 | use esp_wifi::wifi_interface::WifiStack; 24 | use esp_wifi::{current_millis, initialize, EspWifiInitFor}; 25 | use mqttrust::encoding::v4::Pid; 26 | 27 | use smoltcp::iface::SocketStorage; 28 | use smoltcp::wire::{IpAddress, Ipv4Address}; 29 | 30 | use crate::bmp180::Bmp180; 31 | use crate::tiny_mqtt::TinyMqtt; 32 | 33 | mod bmp180; 34 | mod tiny_mqtt; 35 | 36 | const SSID: &str = env!("SSID"); 37 | const PASSWORD: &str = env!("PASSWORD"); 38 | const ADAFRUIT_IO_USERNAME: &str = env!("ADAFRUIT_IO_USERNAME"); 39 | const ADAFRUIT_IO_KEY: &str = env!("ADAFRUIT_IO_KEY"); 40 | 41 | const INTERVAL_MS: u64 = 1 * 60 * 1000; // 1 minute interval 42 | 43 | #[entry] 44 | fn main() -> ! { 45 | esp_println::logger::init_logger_from_env(); 46 | 47 | let peripherals = Peripherals::take(); 48 | let system = peripherals.DPORT.split(); 49 | let clocks = ClockControl::configure(system.clock_control, CpuClock::Clock240MHz).freeze(); 50 | let mut peripheral_clock_control = system.peripheral_clock_control; 51 | 52 | let mut rtc_cntl = Rtc::new(peripherals.RTC_CNTL); 53 | rtc_cntl.rwdt.disable(); 54 | 55 | let (wifi, _) = peripherals.RADIO.split(); 56 | let timg1 = TimerGroup::new(peripherals.TIMG1, &clocks, &mut peripheral_clock_control); 57 | let init = initialize( 58 | EspWifiInitFor::Wifi, 59 | timg1.timer0, 60 | Rng::new(peripherals.RNG), 61 | system.radio_clock_control, 62 | &clocks, 63 | ) 64 | .unwrap(); 65 | 66 | let mut socket_set_entries: [SocketStorage; 3] = Default::default(); 67 | let (iface, device, mut controller, sockets) = 68 | create_network_interface(&init, wifi, WifiMode::Sta, &mut socket_set_entries); 69 | let wifi_stack = WifiStack::new(iface, device, sockets, current_millis); 70 | 71 | let io = IO::new(peripherals.GPIO, peripherals.IO_MUX); 72 | 73 | // Create a new peripheral object with the described wiring 74 | // and standard I2C clock speed 75 | let i2c = I2C::new( 76 | peripherals.I2C0, 77 | io.pins.gpio32, 78 | io.pins.gpio33, 79 | 100u32.kHz(), 80 | &mut peripheral_clock_control, 81 | &clocks, 82 | ); 83 | 84 | println!("Measuring"); 85 | let mut bmp180 = Bmp180::new(i2c, sleep_millis); 86 | bmp180.measure(); 87 | println!("Current temperature {}", bmp180.get_temperature()); 88 | 89 | println!("Call wifi_connect"); 90 | let client_config = Configuration::Client(ClientConfiguration { 91 | ssid: SSID.into(), 92 | password: PASSWORD.into(), 93 | ..Default::default() 94 | }); 95 | controller.set_configuration(&client_config).unwrap(); 96 | controller.start().unwrap(); 97 | controller.connect().unwrap(); 98 | 99 | println!("Wait to get connected"); 100 | loop { 101 | let res = controller.is_connected(); 102 | match res { 103 | Ok(connected) => { 104 | if connected { 105 | break; 106 | } 107 | } 108 | Err(err) => { 109 | println!("{:?}", err); 110 | loop {} 111 | } 112 | } 113 | } 114 | 115 | // wait for getting an ip address 116 | println!("Wait to get an ip address"); 117 | loop { 118 | wifi_stack.work(); 119 | 120 | if wifi_stack.is_iface_up() { 121 | println!("Got ip {:?}", wifi_stack.get_ip_info()); 122 | break; 123 | } 124 | } 125 | 126 | println!("We are connected!"); 127 | println!("enter busy loop"); 128 | 129 | let mut rx_buffer = [0u8; 1536]; 130 | let mut tx_buffer = [0u8; 1536]; 131 | let mut socket = wifi_stack.get_socket(&mut rx_buffer, &mut tx_buffer); 132 | socket 133 | .open(IpAddress::Ipv4(Ipv4Address::new(52, 54, 163, 195)), 1883) // io.adafruit.com 134 | .unwrap(); 135 | 136 | let mut mqtt = TinyMqtt::new("esp32", socket, esp_wifi::current_millis, None); 137 | 138 | let mut last_sent_millis = 0; 139 | let mut first_msg_sent = false; 140 | loop { 141 | sleep_millis(1_000); 142 | println!("Trying to connect"); 143 | mqtt.disconnect().ok(); 144 | if let Err(e) = mqtt.connect( 145 | IpAddress::Ipv4(Ipv4Address::new(52, 54, 163, 195)), // io.adafruit.com 146 | 1883, 147 | 10, 148 | Some(ADAFRUIT_IO_USERNAME), 149 | Some(ADAFRUIT_IO_KEY.as_bytes()), 150 | ) { 151 | println!( 152 | "Something went wrong ... retrying in 10 seconds. Error is {:?}", 153 | e 154 | ); 155 | // wait a bit and try it again 156 | sleep_millis(10_000); 157 | continue; 158 | } 159 | 160 | println!("Connected to MQTT broker"); 161 | 162 | let mut topic_name: heapless::String<32> = heapless::String::new(); 163 | write!(topic_name, "{}/feeds/temperature", ADAFRUIT_IO_USERNAME).ok(); 164 | 165 | let mut pkt_num = 10; 166 | loop { 167 | if mqtt.poll().is_err() { 168 | break; 169 | } 170 | 171 | if esp_wifi::current_millis() > last_sent_millis + INTERVAL_MS || !first_msg_sent { 172 | first_msg_sent = true; 173 | 174 | bmp180.measure(); 175 | let temperature: f32 = bmp180.get_temperature(); 176 | 177 | println!("..."); 178 | 179 | let mut msg: heapless::String<32> = heapless::String::new(); 180 | write!(msg, "{}", temperature).ok(); 181 | if mqtt 182 | .publish_with_pid( 183 | Some(Pid::try_from(pkt_num).unwrap()), 184 | &topic_name, 185 | msg.as_bytes(), 186 | mqttrust::QoS::AtLeastOnce, 187 | ) 188 | .is_err() 189 | { 190 | break; 191 | } 192 | 193 | pkt_num += 1; 194 | last_sent_millis = esp_wifi::current_millis(); 195 | } 196 | } 197 | 198 | println!("Disconnecting"); 199 | mqtt.disconnect().ok(); 200 | } 201 | } 202 | 203 | pub fn sleep_millis(delay: u32) { 204 | let sleep_end = esp_wifi::current_millis() + delay as u64; 205 | while esp_wifi::current_millis() < sleep_end { 206 | // wait 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /src/tiny_mqtt.rs: -------------------------------------------------------------------------------- 1 | use embedded_io::blocking::{Read, Write}; 2 | use esp_println::println; 3 | use esp_wifi::{compat::queue::SimpleQueue, wifi::WifiError}; 4 | use mqttrust::{ 5 | encoding::v4::{decode_slice, encode_slice, Connect, Pid, Protocol}, 6 | Mqtt, MqttError, Packet, Publish, QoS, Subscribe, SubscribeTopic, 7 | }; 8 | use smoltcp::wire::IpAddress; 9 | 10 | #[derive(Debug)] 11 | pub enum TinyMqttError { 12 | MqttError(MqttError), 13 | WifiError(WifiError), 14 | } 15 | 16 | impl From for TinyMqttError { 17 | fn from(e: MqttError) -> Self { 18 | TinyMqttError::MqttError(e) 19 | } 20 | } 21 | 22 | impl From for TinyMqttError { 23 | fn from(e: WifiError) -> Self { 24 | TinyMqttError::WifiError(e) 25 | } 26 | } 27 | 28 | #[derive(Copy, Clone)] 29 | pub struct PacketBuffer { 30 | bytes: [u8; 1024], 31 | } 32 | 33 | impl PacketBuffer { 34 | pub fn new(packet: Packet<'_>) -> PacketBuffer { 35 | let mut buf = [0u8; 1024]; 36 | encode_slice(&packet, &mut buf).ok(); 37 | PacketBuffer { bytes: buf } 38 | } 39 | 40 | pub fn parsed(&self) -> Packet<'_> { 41 | // this might panic: "InvalidPid(0)" when I send s.th with QoS > 0 42 | decode_slice(&self.bytes).unwrap().unwrap() 43 | } 44 | } 45 | 46 | pub struct TinyMqtt<'a> { 47 | client_id: &'a str, 48 | socket: esp_wifi::wifi_interface::Socket<'a, 'a>, 49 | queue: core::cell::RefCell>, 50 | recv_buffer: [u8; 1024], 51 | recv_index: usize, 52 | recv_queue: core::cell::RefCell>, 53 | timeout_secs: u16, 54 | last_sent_millis: u64, 55 | current_millis_fn: fn() -> u64, 56 | receive_callback: Option<&'a dyn Fn(&str, &[u8])>, 57 | } 58 | 59 | impl<'a> TinyMqtt<'a> { 60 | pub fn new( 61 | client_id: &'a str, 62 | socket: esp_wifi::wifi_interface::Socket<'a, 'a>, 63 | current_millis_fn: fn() -> u64, 64 | receive_callback: Option<&'a dyn Fn(&str, &[u8])>, 65 | ) -> TinyMqtt<'a> { 66 | let res = TinyMqtt { 67 | client_id, 68 | socket, 69 | queue: core::cell::RefCell::new(SimpleQueue::new()), 70 | recv_buffer: [0u8; 1024], 71 | recv_index: 0, 72 | recv_queue: core::cell::RefCell::new(SimpleQueue::new()), 73 | timeout_secs: 0, 74 | last_sent_millis: 0, 75 | current_millis_fn, 76 | receive_callback, 77 | }; 78 | 79 | res 80 | } 81 | 82 | pub fn connect( 83 | &mut self, 84 | addr: IpAddress, 85 | port: u16, 86 | keep_alive_secs: u16, 87 | username: Option<&'a str>, 88 | password: Option<&'a [u8]>, 89 | ) -> Result<(), TinyMqttError> { 90 | self.timeout_secs = keep_alive_secs; 91 | 92 | self.socket.open(addr, port).unwrap(); 93 | 94 | let connect = Packet::Connect(Connect { 95 | protocol: Protocol::MQTT311, 96 | keep_alive: keep_alive_secs, 97 | client_id: "", //self.client_id(), 98 | clean_session: true, 99 | last_will: None, 100 | username, 101 | password, 102 | }); 103 | self.send(connect)?; 104 | self.last_sent_millis = (self.current_millis_fn)(); 105 | 106 | Ok(()) 107 | } 108 | 109 | pub fn disconnect(&mut self) -> Result<(), TinyMqttError> { 110 | self.socket.disconnect(); 111 | Ok(()) 112 | } 113 | 114 | pub fn publish_with_pid( 115 | &self, 116 | pid: Option, 117 | topic_name: &str, 118 | payload: &[u8], 119 | qos: QoS, 120 | ) -> Result<(), MqttError> { 121 | let packet = Packet::Publish(Publish { 122 | dup: false, 123 | qos, 124 | pid: None, 125 | retain: false, 126 | topic_name, 127 | payload, 128 | }); 129 | 130 | let mut buf = [0u8; 1024]; 131 | let len = encode_slice(&packet, &mut buf).unwrap(); 132 | 133 | // encode_slice doesn't fill in the PID for publish packets 134 | if pid.is_some() { 135 | let pid: u16 = pid.unwrap().into(); 136 | let idx = len - payload.len() - 2; 137 | buf[idx + 0] = ((pid & 0xff00) >> 8) as u8; 138 | buf[idx + 1] = (pid & 0xff) as u8; 139 | } 140 | 141 | self.queue.borrow_mut().enqueue((len, buf)).unwrap(); 142 | Ok(()) 143 | } 144 | 145 | #[allow(dead_code)] 146 | pub fn subscribe<'b: 'a>( 147 | &self, 148 | _pid: Option, 149 | topics: &[SubscribeTopic<'_>], 150 | ) -> Result<(), MqttError> { 151 | let subscribe = Subscribe::new(topics); 152 | let packet = Packet::Subscribe(subscribe); 153 | 154 | self.send(packet)?; 155 | 156 | Ok(()) 157 | } 158 | 159 | pub fn poll(&mut self) -> Result<(), TinyMqttError> { 160 | self.poll_internal(true) 161 | } 162 | 163 | fn poll_internal(&mut self, drain_receive_queue: bool) -> Result<(), TinyMqttError> { 164 | let time = (self.current_millis_fn)(); 165 | 166 | if time > self.last_sent_millis + ((self.timeout_secs as u64 / 2) * 1000) { 167 | // ping 168 | self.send(Packet::Pingreq)?; 169 | self.last_sent_millis = (self.current_millis_fn)(); 170 | } 171 | 172 | self.receive_internal()?; 173 | self.send_internal()?; 174 | 175 | // just drain the received packets for now 176 | if drain_receive_queue { 177 | while let Some(received) = self.recv_queue.borrow_mut().dequeue() { 178 | if let Packet::Publish(publish) = received.parsed() { 179 | if let Some(callback) = self.receive_callback { 180 | callback(publish.topic_name, publish.payload); 181 | } 182 | } 183 | } 184 | } 185 | 186 | Ok(()) 187 | } 188 | 189 | fn receive_internal(&mut self) -> Result<(), TinyMqttError> { 190 | loop { 191 | let mut buffer = [0u8; 1024]; 192 | let len = self.socket.read(&mut buffer).unwrap(); 193 | if len > 0 { 194 | println!("got {} bytes: {:02x?}", len, &buffer[..len]); 195 | } 196 | 197 | self.recv_buffer[self.recv_index..][..len].copy_from_slice(&buffer[..len]); 198 | self.recv_index += len; 199 | 200 | let data = self.recv_buffer[..len].as_ref(); 201 | let packet = decode_slice(data); 202 | 203 | if let Ok(Some(packet)) = packet { 204 | println!("{:?}", packet); 205 | self.recv_index = 0; 206 | self.recv_queue 207 | .borrow_mut() 208 | .enqueue(PacketBuffer::new(packet)) 209 | .ok(); 210 | } 211 | 212 | if len == 0 { 213 | return Ok(()); 214 | } 215 | } 216 | } 217 | 218 | fn send_internal(&mut self) -> Result<(), TinyMqttError> { 219 | loop { 220 | let dq = self.queue.borrow_mut().dequeue(); 221 | match dq { 222 | Some((len, buffer)) => loop { 223 | println!("try sending a buffer, len = {}", len); 224 | if self.socket.write(&buffer[..len]).is_ok() { 225 | println!("fine"); 226 | return Ok(()); 227 | } 228 | }, 229 | None => return Ok(()), 230 | } 231 | } 232 | } 233 | } 234 | 235 | impl<'a> Mqtt for TinyMqtt<'a> { 236 | fn send(&self, packet: mqttrust::Packet<'_>) -> Result<(), mqttrust::MqttError> { 237 | let mut buf = [0u8; 1024]; 238 | let len = encode_slice(&packet, &mut buf).unwrap(); 239 | 240 | self.queue.borrow_mut().enqueue((len, buf)).ok(); 241 | Ok(()) 242 | } 243 | 244 | fn client_id(&self) -> &str { 245 | self.client_id 246 | } 247 | } 248 | --------------------------------------------------------------------------------