[{"element_type":"text","content":"\n  \n  \n        \u003ch1\u003eHow to fail with CircuitPython\u003c/h1\u003e\n\u003cp\u003e\u0026nbsp;\u003c/p\u003e\n\u003cp\u003eAll code will have errors. You might find it sooner or later, or the error might be in your code, in a library that you are using or even in CircuitPython itself!\u003c/p\u003e\n\u003cp\u003eIt is also very common to write some code on your lab environment, test it a bunch of times, then take it out into the field and watch it fail in lots of ways you would never though of. Exactly the same happens when you give your device to a user or a kid who will test it in ways that will make your coding skills feel silly.\u003c/p\u003e\n\u003cp\u003eIn my case this is happening for a weather station. This should be a simple project, right? Grab some data from a sensor like a Stemma QT thermometer, then send that data to Adafruit.IO and watch it get graphed in a lovely dashboard. Or at least that was my expectation for this project.\u003c/p\u003e\n\u003cp\u003eAs you can see, I started getting missing data for days, and only when I went to the semi-remote location where I am testing my weather station, and manually rebooted the devices, I would get start getting data again. But now the graph is ruined, it has a large gap in the data and to all whom I showed the graphs, the first thing they mentioned is 'what happened to the missing data?'. Now what do I do?\u003c/p\u003e\n      \n\n","metadata":{}},{"element_type":"user_image","content":"https://cdn-learn.adafruit.com/user_assets/assets/000/000/680/original/Screenshot_2024-02-07_at_20.45.20.png?1707360340","metadata":{"caption":""}},{"element_type":"text","content":"\n        \u003cp\u003eLook at the last hours of the graph. Even if I am missing only a little bit of data, it looks terrible right? You, the reader have no idea how hot it is during the day, how cold it is during the night, or what is the coldest hour. Your eyes go straight to the missing data at the end, with the graphs looking like a shark tooth and being jumpy. What a disaster.\u003c/p\u003e\n\u003cp\u003eI thought about blaming Adafruit.IO or maybe CircuitPython or maybe it's the fault of the ESP32 that is reading the data. Then I thought about adding extra hardware to it like a \u003ca href=\"https://learn.adafruit.com/adafruit-tpl5110-power-timer-breakout/\" target=\"_blank\"\u003eTPL5110 power timer\u003c/a\u003e but that would require some soldering and would break the wifi workflow that I love so much from CircuitPython 8.\u003c/p\u003e\n\u003cp\u003eI cloud also get my code full of \u003ccode\u003etry\u003c/code\u003e and \u003ccode\u003eexcept\u003c/code\u003e Python blocks on all of the parts of my code. To be honest, I did tried to do it this way, but things would still keep failing so I kept adding more \u003ccode\u003etry/except\u003c/code\u003e blocks until the code looked terrible. I was this close to having a project that was not fun for me, and that I would not like to share how it works with this amazing community that makes CircuitPython what it is. Not sharing? That doesn't sound like me at all. Time to do things a different way.\u003c/p\u003e\n\u003ch1\u003eLoving to fail\u003c/h1\u003e\n\u003cp\u003eThere is a bit of a hidden gem in CircuitPython and it's the \u003ccode\u003esupervisor\u003c/code\u003e module. I was only able to find a little bit of technical documentation without a simple example that I could just copy and paste into my project, and I also found another example which was close to what I wanted to do in Tod's CircuitPython tricks.\u003c/p\u003e\n\u003cp\u003eAfter staring at the code I had available for a couple of minutes, I realized that this is what I had to do. I needed to let go of my impulse of keep the code failure free, and embrace CircuitPython failing. I would let if fail any time it wanted, and then I would ask it to try again.\u003c/p\u003e\n\u003cp\u003eWith two simple lines, my weather station code can now fail because the wifi router is down, because the Stemma QT cables had a problem with talking to the sensor, because it was running for so long that it was finding errors in the CircuitPython base code or the request library. It doesn't matter, the board will accept that something weird happened, and would try again. Try this in your code and love to fail as much as I do now!\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003e\u003cspan\u003eimport supervisor\u003c/span\u003e\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003e\u003cspan\u003esupervisor.set_next_code_file(filename='code.py', reload_on_error=True)\u003c/span\u003e\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan\u003eIt should not be this simple, right? Here's how it works:\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan\u003eIn the first line of code we are calling a library called \u003ccode\u003esupervisor\u003c/code\u003e. Don't worry, you don't have to install anything, it comes as a standard CircuitPython library and will probably work on any board that you have CircuitPython running on. What it does, is talk to one of the internal parts of CircuitPython and modify how it will behave.\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan\u003eThe second like, is the one that changes how it works. It's using a function called \u003ccode\u003eset_next_code_file\u003c/code\u003e. It's normally used so that you can run the well known \u003ccode\u003ecode.py\u003c/code\u003e file and if something happens, you can define a second file with another name and that code would do something like recover things, blink a light or beep to indicate that it will not behave as it would normally do. I am not calling a second file, instead I'm telling it to go to \u003ccode\u003ecode.py\u003c/code\u003e so that it can \u003cstrong\u003etry again\u003c/strong\u003e.\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan\u003eAnd my favorite part comes with the code that says \u003ccode\u003ereload_on_error=True\u003c/code\u003e. The way CircuitPython works is that when it fails it will take you to the \u003cem\u003eREPL\u003c/em\u003e console, and show you why it failed. This is a good thing as that is the way that we learn, we make mistakes, the \u003cem\u003eREPL\u003c/em\u003e shows us what those mistakes are, and we go and fix them.\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan\u003eBut for my weather station, once the code was ready and it was doing what I wanted, if there is a failure like the wifi is down, it would go to the console and wait for me to do something. This weather station is located on a dry forest in Costa Rica and it doesn't know that is not next to my computer where it's easy for me to tell it to try again. So what \u003ccode\u003ereload_on_error=True\u003c/code\u003e tells it to do, is to change what it would have usually do and take me to the console, and instead it will do something similar as if I was close so the board, pushing the \u003cstrong\u003eRESET\u003c/strong\u003e button every time something unexpected happens.\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan\u003eThis way, CircuitPython will keep on trying over and over until wifi comes back, and hopefully the graphs will have\u0026nbsp;\u003c/span\u003esmaller gaps in the data, and they will look much better and should be able to work like a weather station should. Read the thermometer. Send it to Adafruit.IO. Go to sleep to save some battery.\u003c/p\u003e\n\u003cp\u003eI love you CircuitPython! You and me can fail as many times as we need to, as long as we do it together and without feeling bad. \u0026lt;3.\u003c/p\u003e\n\u003cp\u003e\u0026nbsp;\u003c/p\u003e\n      ","metadata":{}}]