Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/aabbtree77/esp32-vpn
Experiments with ESP32, Wi-Fi resilience, global connectivity.
https://github.com/aabbtree77/esp32-vpn
android awl edgevpn esp32 go-libp2p hyprspace iot libp2p linux micropython mosquitto mqtt nat resilience soil ssd1306 ssh vpn wifi
Last synced: about 2 months ago
JSON representation
Experiments with ESP32, Wi-Fi resilience, global connectivity.
- Host: GitHub
- URL: https://github.com/aabbtree77/esp32-vpn
- Owner: aabbtree77
- License: mit
- Created: 2022-04-18T09:48:29.000Z (over 2 years ago)
- Default Branch: main
- Last Pushed: 2023-09-22T20:23:59.000Z (about 1 year ago)
- Last Synced: 2024-01-30T15:48:52.440Z (11 months ago)
- Topics: android, awl, edgevpn, esp32, go-libp2p, hyprspace, iot, libp2p, linux, micropython, mosquitto, mqtt, nat, resilience, soil, ssd1306, ssh, vpn, wifi
- Language: Python
- Homepage:
- Size: 1.82 MB
- Stars: 8
- Watchers: 2
- Forks: 3
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
> “...the bullshit piled up so fast... you needed wings to stay above it.”
– Apocalypse Now, 1979
Towards Reliable IoT
## Introduction
[DOIT DEvKit V1 ESP32-WROOM-32](https://en.wikipedia.org/wiki/ESP32) is an inexpensive (15€) microcontroller board with Wi-Fi, Bluetooth LE, and ESP-NOW. One can connect it to [a lot of sensors](https://esphome.io/#sensor-components) with ready-made drivers. The challenge is to control such a board globally, via the internet.
## ESP32 and IoT
There are several ways to make the ESP32 visible globally:
1. Cloud services: [ESP RainMaker](https://github.com/espressif/esp-rainmaker/issues/96), [Firebase](https://randomnerdtutorials.com/firebase-control-esp32-gpios/), [Blynk](https://blynk.io/blog/esp32-blynk-iot-platform-for-your-connected-product), [Arduino IoT Cloud](https://www.youtube.com/watch?v=rcCxGcRwCVk), [Yaler.net](https://yaler.net/), [Amazon API Gateway with Websocket API](https://www.youtube.com/watch?v=z53MkVFOnIo), [Amazon API Gateway with RESTful API](https://aws.amazon.com/blogs/compute/building-an-aws-iot-core-device-using-aws-serverless-and-an-esp32/), [Husarnet](https://husarnet.com/docs/tutorial-esp32-platformio), [CloudMQTT](https://www.cloudmqtt.com/blog/cloudmqtt-cute-cat-free-plan-out-of-stock.html), [HiveMQ](https://community.hivemq.com/t/connection-fail-in-hivemq-cloud/579/4), [RemoteXY](https://www.youtube.com/watch?v=dyEnOyQS1w8&t=1s), [Google Cloud IoT](https://www.elementzonline.com/blog/Connecting-ESP32-to-Google-Cloud-IoT), Viper/Zerynth: [1](https://zerynth.com/blog/python-on-esp32-getting-started/), [2](https://lemariva.com/blog/2021/12/zerynth-esp32-google-iot-core-part-1-sending-data-to-the-cloud), [3](https://zerynth.com/customers/case-studies/zerynth-powered-smart-iot-display/), [Tuya IoT Development Platform](https://www.hackster.io/vilaksh01/tuya-mqtt-with-esp32-434ad6), Thingschain: [1](https://docs.thingschain.net/apps/esphome), [2](https://www.linkedin.com/pulse/decentralized-technology-tokens-designed-internet-things-bhatia/), Azure IoT: [1](https://learn.microsoft.com/en-us/azure/iot-develop/quickstart-devkit-espressif-esp32-freertos), [2](https://www.espressif.com/products/devkits/esp32-azure-kit/overview), [ZeroTier?](https://github.com/zerotier/ZeroTierOne/issues/668), Notehub: [1](https://blues.io/products/notehub/), [2](https://blues.io/blog/easiest-cellular-iot-esp32/), [ngrok](https://ngrok.com/blog-post/putting-the-esp32-microcontroller-on-the-internet)...
Google IoT Core [was discontinued on August 16, 2023](https://news.ycombinator.com/item?id=32475298). [Free plans come and go](https://twitter.com/heroku/status/1562817050565054469). Husarnet is the only one from the listed above which provides [its open source code](https://husarnet.com/business/open-source).
2. An HTTP web app: [1](https://randomnerdtutorials.com/control-esp32-esp8266-gpios-from-anywhere/), [2](https://randomnerdtutorials.com/esp32-esp8266-mysql-database-php/). Notice that the board needs to know the URL or the IP address of the app to send GET/POST requests, but the app does not need to know the address of the board.3. [A similar MQTT intermediary](https://habr.com/ru/articles/504716/) which could just be the SSH tunnel from your local MQTT broker to a rented VPS. The MQTT has its [pros and cons](https://news.ycombinator.com/item?id=34171406). Subjectively, (i) the MQTT is more reliable than the HTTP in the ESP world, and (ii) there is no need to write a web app to send/receive data (although the same may hold for the HTTP). One can simply run the tunnelled Mosquitto broker as an "MQTT app" on the VPS, and issue "mosquitto_pub/sub" commands w.r.t. the MQTT topics that the board will pub/sub to.
4. [Wireguard](https://blog.thestaticturtle.fr/lets-talk-about-wireguard/) on the ESP32: [0](https://news.ycombinator.com/item?id=34171406), [1](https://github.com/ciniml/WireGuard-ESP32-Arduino/issues), [2](https://github.com/trombik/esp_wireguard/issues), [3](https://github.com/droscy/esp_wireguard), [4](https://github.com/esphome/feature-requests/issues/1444), [5](https://www.reddit.com/r/esp32/comments/110f2ey/esp32_ap_tunneling_all_devices_to_my_vpn_server/), [6](https://techoverflow.net/2021/12/31/esp32-wireguard-example-with-http-access-over-wireguard-platformio/). This is for some overly optimistic dubious uses where the ESP32 becomes a VPN node on a par with Linux boards. No MicroPython support, no ssh, a tiny fractured [LwIP](https://forum.micropython.org/viewtopic.php?t=7569) networking user base. Wireguard still needs a public static IP.
5. Connecting the ESP32 to the Linux PC over Wi-Fi that runs the MQTT broker within its LAN, thus delegating the problem of global connectivity effectively to the PC space.
The last option is our choice here. It is the most reliable as the ESP32 communicates only within its LAN. We do not need to hunt for the reviews of all these clouds and make tough choices. When things go wrong, we can locate the problem easier since the global connectivity happens only in the Linux space. We do not need to deal with opaque evolving 3rd party services, vendor lock-in, opaque firmware/software on the ESP32, we can add as many devices as we want, run MicroPython, there are no subscription payments. The downside is that this demands running 24/7 an extra PC/Linux board (Ubuntu1 shown in the figure above). Many out of the box Android conveniences present in, say, the ESP RainMaker cloud, will not be available, like a simple push button/dash board Android app, Wi-Fi provisioning, device discoverability, OTA updates. However, we can control the ESP32 globally from Android via the Linux intermediary and go-libp2p.
One can run an MQTT broker on a router, e.g. with [OpenWrt Linux](https://cgomesu.com/blog/Mesh-networking-openwrt-batman/): [1](https://www.onetransistor.eu/2019/05/run-local-mqtt-broker-on-openwrt-router.html), [2](https://esp8266.ru/esp8266-openwrt-mosquitto-mqttwarn-thingspeak-email-android-ios-twitter-cloudmqtt/) or [RutOS](https://teltonika-networks.com/lt/resursai/webinarai/rutos-an-extensive-introduction), but these router OSes (6-8MB .bin image size) are too limiting. More importantly, one cannot use go-libp2p with them.
In order to establish remote PC connections, we have tested [Hyprspace](https://github.com/hyprspace/hyprspace/issues/94), [EdgeVPN](https://github.com/mudler/edgevpn/issues/25), and [anywherelan (awl)](https://github.com/anywherelan/awl). All of them are built on top of [go-libp2p](https://github.com/libp2p/go-libp2p) which is both, the FOSS code, and the running network with [NAT](https://discuss.libp2p.io/t/how-nat-traversal-and-hole-punching-work-in-ipfs/1422) [traversal](https://github.com/ipfs/camp/blob/master/DEEP_DIVES/40-better-nat-traversal-so-that-relay-servers-are-a-last-not-first-resort.md) aka hole punching. This software allows to ssh into a remote computer without a public static IP.
According to [Max Inden, 2022](https://archive.fosdem.org/2022/schedule/event/libp2p/attachments/audio/4917/export/events/attachments/libp2p/audio/4917/slides.pdf), the libp2p network "powers the IPFS, [Ethereum 2](https://blog.libp2p.io/libp2p-and-ethereum/#how-ethereum-beacon-nodes-use-libp2p-%F0%9F%94%8D), Filecoin and Polkadot network and there are ~100K libp2p based nodes online at any given time".
Do these tools always work though, are they equally good?
[hyprspace](https://github.com/hyprspace/hyprspace): 895 LOC of Go. Minimal, but weaker hole punching.
[awl](https://github.com/anywherelan/awl): 6.5 KLOC of Go. Just about right.
[EdgeVPN](https://github.com/mudler/edgevpn): 7.5 KLOC of Go. Solid punching, but problems with 24/7 runs. No Android support.[go-libp2p](https://github.com/libp2p/go-libp2p): 67 KLOC of Go. The base layer for the three above.
EdgeVPN may have an [edge](https://github.com/mudler/edgevpn/issues/25) over Hyprspace, but there is [a problem with longer runs](https://github.com/mudler/edgevpn/issues/137). [awl](https://github.com/anywherelan/awl) is more reliable. It is also more convenient (desktop browser GUI for one-click handshakes, runs on Android), but not always. If for some reason one has to reinstall the Android app, the latter generates a new peer id which then needs to be confirmed again on the other end. EdgeVPN simply shares the same secret file and has no handshakes.
## Some Photos
This hobby/demo hardware has been assembled and soldered by Saulius Rakauskas (InfoVega).
![gThumb01](./images/esp32-ssd1306-dht22-front.jpg "ESP32 on a custom board: Front.")
![gThumb02](./images/esp32-ssd1306-dht22-back.jpg "ESP32 on a custom board: Back.")
## Circuit Diagram
- [esp32-30pin] (the 30-pin variant of DOIT DEVIT V1 ESP32-WROOM-32, not 36).
- DHT22, Multiple LEDs, Capacitive Soil Moisture Sensor v1.2, see boot.py.
- ~~SSD1306 with in-software I2C.~~ Dropped it, rewind to "the last before revamp" commit if interested.
## Commands
- Ubuntu PC:
```console
sudo apt-get install python3-pip
sudo pip3 install esptool
sudo pip3 install rshell
```- USB connection:
```console
ls /dev/ttyUSB*
dmesg | grep ttyUSB
```- Flashing/reflashing [MicroPython firmware][MicroPython firmware] via USB:
```console
sudo esptool.py --port /dev/ttyUSB0 flash_id
sudo esptool.py --port /dev/ttyUSB0 erase_flash
sudo esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 460800 write_flash -z 0x1000 esp32-ota-20220618-v1.19.1.bin
```- Release:
```console
rshell --buffer-size=30 -p /dev/ttyUSB0 -a
boards
ls /pyboard
cp main.py /pyboard
cp umqttsimple.py /pyboard
cp boot.py /pyboard
```Disconnect the device from USB and use only a power supply.
- MQTT:
```console
sudo apt install mosquitto mosquitto-clients
hostname -I
ifconfig -a | grep inet
```The hostname/ifconfig command will provide the local IP address assigned by the router to a computer (PC-1) which runs the MQTT broker (Moscquitto), such as '192.168.1.107'. It will have to be entered in boot.py manually/explicitly.
The Mosquitto broker always runs on Ubuntu by default once the OS starts. However, depending on the exact Ubuntu and Mosquitto versions one may need some additional minimal configuration.
Since Mosquitto version 2.0, one needs to create a custom config file and place it somewhere, say at /home/sara/esp32/custom_mosquitto.conf, with this minimal content:```console
listener 1883
allow_anonymous true
```
Then start the MQTT broker with this config:```console
mosquitto -c /home/sara/esp32/custom_mosquitto.conf
```Sometimes you may get "Error: Address already in use". That means you are starting another Mosquitto broker on the same machine. Kill one or the other with
```console
ps -ef | grep mosquitto
sudo kill 1234
```
One should get the console message indicating the connected MicroPython MQTT client with its local IP address such as 192.168.1.108, the latter may change
with each device reboot, it is assigned by a router.Read the sensor data from the device:
```console
mosquitto_sub -d -h 192.168.1.107 -t "testincr"
```Publish the messages "on" or "off" to control the LED output:
```console
mosquitto_pub -d -h 192.168.1.107 -t "output" -m "on" -q 1
mosquitto_pub -d -h 192.168.1.107 -t "output" -m "off" -q 1
```- EdgeVPN:
Download the latest edgevpn executable for your OS, e.g. [edgevpn-v0.23.1-Linux-x86_64.tar.gz](https://github.com/mudler/edgevpn/releases/tag/v0.23.1).
Use the same release version on all the computers that will be connected into a VPN, otherwise there might be conflicts as some versions have changed the way the keys are stored and decoded.
cd into extracted folder and generate config.yaml:
```console
./edgevpn -g > config.yaml
```Distribute it on all the machines that will be connected to EdgeVPN (manually by carrying a USB stick, via email, etc.).
Assuming the machine runs Ubuntu, place the executable with config.yaml in the same folder and run
```console
sudo IFACE=edgevpn0 ADDRESS=10.1.0.7/24 EDGEVPNCONFIG=config.yaml ./edgevpn --log-level debug
```
The command assigns a virtual IP address 10.1.0.7 to the machine on which it is executed. Assign a different address to each machine that you connect to EdgeVPN, i.e. 10.1.0.1.. 10.1.0.254. but use the same config.yaml in each case.
It may take several minutes for the node to join the EdgeVPN network which is the libp2p network under the hood. [The Linux desktop GUI](https://github.com/mudler/edgevpn-gui) is totally unnecessary.
If everything is fine, you should be able to connect to any Linux computer of your VPN, e.g.
```console
ssh [email protected]
[email protected]'s password:
Last login: Mon Jul 10 15:13:34 2023 from 10.1.0.4
...
exit
logout
Connection to 10.1.0.8 closed.
```
When you are able to connect from A to B, A's ./edgevpn --log-level debug will show a lot of information including the following lines:
```
{"level":"DEBUG","time":"2023-07-11T14:44:39.455+0300","caller":"discovery/dht.go:204","message":" Announcing ourselves..."}
{"level":"DEBUG","time":"2023-07-11T14:44:56.542+0300","caller":"discovery/dht.go:207","message":" Successfully announced!"}
{"level":"DEBUG","time":"2023-07-11T14:44:56.542+0300","caller":"discovery/dht.go:210","message":" Searching for other peers..."}
{"level":"DEBUG","time":"2023-07-11T14:44:56.583+0300","caller":"discovery/dht.go:230","message":" Known peer (already connected):
```
followed by the list of so called multiaddresses of known/connected peers which will include global or local IPv4. While being on the A side, you should be able to see the local LAN IPv4 address of B assigned to B by its encompassing router on the B side!
- awl:
There is [one unsolved issue](https://github.com/mudler/edgevpn/issues/137) with edgevpn that occurs on the 24/7 runs, so we switched to [awl](https://github.com/anywherelan/awl) which seems to be more reliable.
Download the [awl-tray binary](https://github.com/anywherelan/awl/releases) and run it, see [1](https://github.com/anywherelan/awl#desktopandroid) and [2](https://github.com/anywherelan/awl#desktop-awl-tray) for more details.
awl is nice in that once you start it on Android, you can then run an SSH app such as [JuiceSSH](https://play.google.com/store/apps/details?id=com.sonelli.juicessh&hl=en&gl=US) and get the remote access to your Linux terminal. Make sure the awl VPN has no overlapping/duplicated addresses and delete all the previous connections on JuiceSSH before connecting. awl is not very polished yet so one can sometimes mess up virtual addresses with many-to-one connections and loops.
## ESP32 and MicroPython- **Hardware errors.** When the DHT sensor is detached from the chip's pin, executing the line "dht_sensor.measure()" or "dht_sensor.start()"
in the MicroPython REPL will reboot the device with a "useful" error message:```console
>>> import main
ets Jun 8 2016 00:22:57rst:0x8 (TG1WDT_SYS_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0030,len:4540
ho 0 tail 12 room 4
load:0x40078000,len:12448
load:0x40080400,len:4124
entry 0x40080680
W (57) boot.esp32: PRO CPU has been reset by WDT.
W (58) boot.esp32: WDT reset info: PRO CPU PC=0x400803c0
W (59) boot.esp32: WDT reset info: APP CPU PC=0x40093cb2
MicroPython v1.17 on 2022-01-10; 4MB/OTA module with ESP32
Type "help()" for more information.
>>>
```
- **Too little RAM.** ESP12e/ESP8266 has a [pathetic amount of RAM](https://github.com/espressif/esp-rainmaker/issues/8), but ESP32 is no cake either. Importing the font arial35 from Peter Hinch's ssd1306 lib along with freesans20
is still possible when running the DHT measurement with the display without the networking stack. Adding the async networking and the MQTT libs exposes insufficient RAM:
```console
"MemoryError: memory allocation failed, allocating 6632 bytes" (breaks at "#import gui.fonts.arial35 as arial35").
```
- **Low quality sensors**, see e.g. this [discussion](https://www.youtube.com/watch?v=IGP38bz-K48) of Capacitive Soil Moisture Sensor v1.2.
The solutions based on the electrical resistance are worse due to a rapid corrosion of the electrodes. We have tried submerging them into a cheap industrial gypsum, but that did not work at all.
- Monitoring soil moisture is a harder problem than sensing air humidity. Perhaps the best way is to set up a camera and observe the ground surface, but that is out of the scope of the low RAM devices, unless one is content with [320x240@25FPS](https://github.com/cspwcspw/ESP32_CamToLCD).
- Despite all the amazing async MQTT lib work by Peter Hinch, the device could only send the MQTT messages, the receiving did not work. So we went back to umqttsimple.- After a long search and disappointment the resilience w.r.t. the Wi-Fi loss was reached thanks to this [code by Rui and Sara Santos][micropython-Rui-Santos].
## Notes- Tiny ESP32 RAM = very limited software, esp. limited global connectivity options. With some acrobatics one may run "Wireguard" on the ESP32, but the go-libp2p apps are beyond the reach.
- All this gigantic Web2 VPN service activity exists mostly because A and B do not have proper addresses. We cannot use MAC, we do not have the IPv6. So how does one send a message to a board/PC? One must deal with the OSI model, overlay mesh networks, proxies and reverse proxies, [tunneling and self-hosting](https://github.com/anderspitman/awesome-tunneling), TUN/TAP, STUN/TURN/ICE, TCP meltdown, CGNAT, SOCKS5, ARP, ICMP, subnet masks (CIDR), gateways, stream multiplexing, [vsock/socat](https://github.com/balena/go-libp2p-vpn/issues/3), ports aka socket numbers, port forwarding, host names, DNS and mDNS, UPnP, DHCP, virtual interfaces, iptables/firewalls, Linux kernel routes, routers and routing... [B.A.T.M.A.N.](https://en.wikipedia.org/wiki/B.A.T.M.A.N.)- The p2p tools such as Hyprspace, EdgeVPN, [awl](https://github.com/anywherelan/awl), Syncthing: [1](https://www.reddit.com/r/Syncthing/comments/1324xrm/how_reliable_is_synthing/), [2](https://forum.syncthing.net/t/how-syncthing-communicates-with-my-server-when-im-in-a-public-network/20437/2) solve the global connectivity problem without imposing paid services.
- Connect a webcam to a remote Ubuntu PC, install ffmpeg. Run awl-tray followed by [this one liner](https://unix.stackexchange.com/questions/2302/can-i-pipe-dev-video-over-ssh) with mplayer. It worked in the year 2010, it still works in 2023.
- 24/7 concerns: Idle mode with a monitor shut off consumes about 0.036A electric current at 220V, which amounts to 7.92W power. 720-hour monthly run will demand 5.7 kWh of energy. The rate of 0.30€ per 1kWh will induce a monthly electricity fee of **1.71€**. Non-Idle mode: Consider the worst case upper bound which is running perpetually youtube in a browser with the laptop monitor on. It may increase the power consumption **5x**.
- [KVM1 on Hostinger](https://www.hostinger.lt/vps-serveriai) costs 4.99€ and one gets a public static IP and 1TB of bandwidth with it, but we do not need that in the IoT. There are ways to push down power consumption. [Raspberry Pi Zero W 2](https://www.pidramble.com/wiki/benchmarks/power-consumption) may demand only 0.7W power, and notice that [awl](https://github.com/anywherelan/awl/releases) should run on both, ARM64 and ARM32 (hence Raspberry Pi Zero 2 W and older models too). The problem is that these platforms are little tested with go-libp2p. awl may run on ARM32, but delve, the Go debugger, [may not](https://github.com/go-delve/delve/issues/2051).
- There exist inexpensive (sub-30€) one-time payment-based IoT devices designed for direct remote control and monitoring with the Android apps, see e.g. [Clas Ohlson](https://play.google.com/store/apps/details?id=com.clasohlson.android.plug&hl=en&gl=US&pli=1) for a smart plug, and [YCC365](https://play.google.com/store/apps/details?id=com.ycc365plus.aws&hl=en&gl=US) for a remote 180° IP camera. The latter could even be [hackable to some extent](https://github.com/cspwcspw/CloudCameraGK7102), but these are limited closed source proprietary products where one relies on their respective IT clouds for communication. However, if this fits your needs, you get the simplest time-saving solution.
- The most basic services are tricky. 70 KLOC of go-libp2p to give your computer a proper VPN address.
- Some go-libp2p-based FOSS efforts worth mentioning, and the lines of code (LOC):
[Syncthing](https://github.com/syncthing/syncthing/tree/main): p2p Dropbox. 110 KLOC of Go, 38 KLOC of Js, 11 KLOC of CSS.
[Berty](https://github.com/berty/berty): p2p messenger built with React Native, blocked in Iran. 80 KLOC of Go, 50 KLOC of TypeScript/Js, 5 KLOC of Java.[zkvote?](https://hackmd.io/@juincc/B1QV5NN5S): anonymous p2p voting based on zero-knowledge protocols. 4 KLOC of Go, 6 KLOC of Js.
[peerchat](https://github.com/manishmeganathan/peerchat) (MIT), [cryptogram](https://github.com/gbaranski/cryptogram) (GPL3): Minimal (sub 1 KLOC of Go) working p2p Linux chat terminals.
...
## Some ESP32 ReferencesEssential:
- [MicroPython firmware]
- [micropython-Rui-Santos]
- [umqtt.simple]
- [esp32-30pin]Optional (problems to be aware of):
- [micropython-mqtt-async]
- [micropython-nano-gui]
- [umqtt.robust]
- [umqtt.robust dies when MQTT broker gets restarted #102]
- [umqtt.simple socket behaviour when WiFi is degraded #103]
- [umqtt.robust: Resubscribe to topics after doing reconnect. #186]
- [can't await mqtt.simple publish method #357]
- [unstable MQTT on ESP8266 (4+ days) #2568]
- [umqtt cannot import MQTTClient #250][Getting Started]: https://www.youtube.com/watch?v=_vcQTyLU1WY&list=PLKGiH5V9SS1hUz5Jh_35oTFM4wPZYA4sT&index=2
[MicroPython firmware]: https://micropython.org/download/esp32-ota/
[micropython-mqtt-async]: https://github.com/peterhinch/micropython-mqtt/tree/master/mqtt_as
[micropython-nano-gui]: https://github.com/peterhinch/micropython-nano-gui
[micropython-Rui-Santos]: https://github.com/RuiSantosdotme/ESP-MicroPython/tree/master/code/MQTT/Node_RED_Client
[umqtt.simple]: https://github.com/micropython/micropython-lib/blob/master/micropython/umqtt.simple/example_sub_led.py
[esp32-30pin]:https://www.mischianti.org/wp-content/uploads/2020/11/ESP32-DOIT-DEV-KIT-v1-pinout-mischianti.png
[umqtt.robust]: https://github.com/micropython/micropython-lib/blob/master/micropython/umqtt.robust/example_sub_robust.py
[umqtt.robust dies when MQTT broker gets restarted #102]: https://github.com/micropython/micropython-lib/issues/102
[umqtt.robust: Resubscribe to topics after doing reconnect. #186]: https://github.com/micropython/micropython-lib/pull/186
[can't await mqtt.simple publish method #357]: https://github.com/micropython/micropython-lib/issues/357
[umqtt.simple socket behaviour when WiFi is degraded #103]: https://github.com/micropython/micropython-lib/issues/103
[unstable MQTT on ESP8266 (4+ days) #2568]: https://github.com/micropython/micropython/issues/2568
[umqtt cannot import MQTTClient #250]: https://github.com/micropython/micropython-lib/issues/250## Appendix: Some Non-Toy Applications of Low RAM Devices
1. [Waste bin level detectors based on ultrasonic distance sensors](https://www.ecubelabs.com/bin-level-sensors-5-reasons-why-every-city-should-track-their-waste-bins-remotely/)?
2. A bus card reader? We used to have some early low RAM devices here in Vilnius for about 5-10 years. This year (2023) the bus card readers got replaced with Estonian Ridango devices which, I suspect, run Linux.
3. Mapping out minefields? See [1](https://youtu.be/suxLa6kWsrw?t=2000) and [2](https://cepdnaclk.github.io/e17-3yp-Landmine-Detector/) for two completely different systems. The first one presents a radar mounted on a drone, while the second one is a Colpitts oscillator-based metal detector on a four-wheel robot.4. [A GPS Tracker](https://how2electronics.com/esp32-gps-tracker-using-l86-gps-module-oled-display/).
5. AirTag: [1](https://ldej.nl/post/sending-an-airtag-from-the-netherlands-to-india/), [2](https://www.pcmag.com/how-to/what-is-ultra-wideband-uwb), [3](https://screenrant.com/apple-airtag-track-mail-package-benefits-limitations-explained/).
6. Non-invasive blood glucose and hemoglobin monitoring: [1](https://ijrpr.com/uploads/V2ISSUE9/IJRPR1274.pdf), [2](https://www.ncbi.nlm.nih.gov/pmc/articles/PMC8230267/), [3](https://www.mdpi.com/1424-8220/22/13/4855). Ketones, alcohol: [1](https://www.cnet.com/health/medical/wearable-sensors-that-track-glucose-ketones-and-alcohol-levels-are-the-future/). eCO2.
7. [A smart walking cane for the blind](https://github.com/manishmeganathan/smartwalkingcane).8. [Motor control](https://github.com/aabbtree77/adast).