This project reinforced that even small IoT setups are really about the whole stack, not just one board or sensor. On the hardware side, working with LoRa, ESP32, and basic sensors showed how sensitive long-range radio links are to wiring quality, antennas, and power. A single loose jumper or bad solder joint can easily masquerade as a protocol bug until you track it down. Soldering LoRa modules and sensor connections turned out to be more fragile than expected, and getting the ESP32 reliably into programming mode meant spending a bit of time understanding its boot pins and reset sequence.
On the software side, keeping the firmware simple and well-structured paid off when debugging. Having clear responsibilities for each layer—nodes, gateway, server—made it easier to isolate problems. Running TLS on the ESP32 pushed its memory harder than expected, and adding validation on the server side helped filter out noise and bad readings from the LoRa link.
The distributed backend brought its own set of lessons. Getting Kafka, Spark, and Elasticsearch to work together in Docker required careful version matching—mismatched connector versions caused cryptic errors that took time to debug. Spark jobs needed to be compiled with the right Java version (8, not 11) to run in the container. Elasticsearch 8.x dropped support for document types, which broke older examples. And coordinating service startup order in Docker Compose required custom health checks and delays. The Prometheus integration also showed that not all services expose metrics out of the box; some need dedicated exporters.
Overall, the main takeaway so far is that building a useful smart-farm platform is less about one clever algorithm and more about a lot of small decisions: sensible wiring, clear message formats, basic security, and a backend that can grow a little as the project does.