 Hello, everyone, and welcome to a Circuit Python Day chat with Katnie, Jeff, and Dan. We are getting together to talk about some of the best things in our own minds that we worked on in Circuit Python in the last year. Can be Circuit Python specific stuff or projects. We will see what everyone has to discuss. So I'm Katnie. I am sponsored by Adafruit to work on Circuit Python. I oversee the libraries, I oversee the community, and I write a lot of guides. So that's the majority of what I'm up to, but there's a lot of other things. Let's bring in Jeff and Dan. Hi. Who's going first? Go ahead, Dan. I'll reintroduce myself. I'm Dan. I'm sponsored by Adafruit to work on Circuit Python. I work mostly on the core parts of Circuit Python, especially things having to do with keypad stuff and HID, but a lot of other things. Also, those are just recent, and I did a lot of work on Bluetooth a while ago. And Dan is also our excellent release manager. So thank you for releasing Circuit Python 8 beta. Yes. Thank you. I'll try out 800 beta zero, and if you haven't seen Scott's intro to what's in 800, including the web workflow, find that on YouTube to re-watch. And I'm Jeff. I usually go by Jebler, and I've been working on Circuit Python for about three years now. And I usually work in the core, but I enjoy all the parts of it and seeing the projects that you all put together out of the foundation that we create. All right. Excellent. Now you know who we are, so let's get into it. Who would like to get started? Don't everybody jump at once? I'm bringing up my window, so I'm not doing that. Oh, well, I guess I can talk. I had planned to have some demos of the camera stuff I'd recently been doing, but I really ended up with just one. So if you can bring up my shared window, I will talk about this. So well, maybe I should have. Expressive has some cool little camera development boards. This one has the ESP32S3 on it, and it's got the camera up here and the LCD here, and you've got the live viewfinder. And the other thing that this demo does is when I hit the button, it is going to upload that image to Adafruit.io, which is my shared window. So if you want to come on back to that. And each time, if you want to see my desk here, it is an unholy mess. There's the desk. So it's a little camera that when you click it, it uploads to Adafruit.io all using CircuitPython. And so while we were working on version 8, and there's kind of been a camera board in the we'd like to make it phase for a really long time, and a couple of weeks ago, Lamar said to me, can you look into whether we can support the ESP32S3 also? Because we initially did it with just the S2. And the answer is yes, because Expressive has a really good library for interfacing to the camera, which I created a wrapper around called ESP32 Camera. So it's a break from the past where we created one library that worked on a couple of different microcontrollers, but it gets a lot more capabilities like support for about around 10 different camera types, rather than the three camera types that I've been able to implement. And thank you, Dan, for keypad.keys. It was really easy to kind of wait for the shutter button to be pressed. And it's using the Adafruit.io library, so more boilerplate for that. And then once you get past the setup, it is a super simple program. Your forever loop, take a picture from the camera and send it to the display. Writing it like this makes it go faster than going through Display.io, because I wanted kind of the swiftest, silkiest refresh rate there on the viewfinder. And then if the shutter button has just been pressed, you change it over to taking a JPEG and encode it in the format that I own needs and ship it off. And that is essentially the whole program. Then you switch it back to the RGB format for showing on the screen. And so that is how easy it's going to be to do a project with camera and Wi-Fi in CircuitPython 8. And it should work on the ESP32 and the ESP32. The ESP32 S2 and the ESP32 S3. There's also this cool guy, which has the original ESP32. I have it, and there are some bugs. And I will be figuring those out, hopefully, in the near future. But getting this working is not as important as getting the board with the S3 working. We're really excited about that one. So Zandelen asks, does this mean that the ESP32 cam boards will work? There's a common board on Amazon and other websites that calls itself ESP32 cam. I don't have that one. This ESP32 is from Expressive. It's called the ESPI. And so those use the same microcontroller. So it might have the same quirks that are keeping this one from working. But hopefully, we'll get that working too. Yeah, I don't have one in my hands yet. But we'll see. And DJ Devon asks, would you be able to use Adafruit Bitmap Saver to screenshot output from a TF2 to Adafruit I.O.? Yes, I think sort of. I'm not sure whether it supports the BMP format. And there's also limits on the file size of 100K. And so like a 240 by 240 screen, which is what's on this, expands to too much data to upload it to I.O. So you'd have to make sure you're saving it as a supported image type and that it fits within the file size limitation of Adafruit I.O. So Jeff, what went into getting started with working with this camera stuff? So where it started was on the, well, it started on a board with the Atmel microcontroller. And then it went on to some other boards. But basically, these modules are on Amazon and other websites with this particular pinout on the back. And originally, what I did was I read all the data sheets and learned the exact sequence of commands to send out to the camera to configure it and all this. And with the ESP32 camera, it's like you didn't have to know that at all because their library had already put all these parts together for you. And in particular, supporting each different camera's initialization steps, there are hundreds and hundreds of lines of data of commands and configuration you have to send to the camera just before you can get the first image out. And being able to use somebody else's library to do that was really helpful. So, yeah. It was like weeks. Oh, it took a long time. It was like one week or a day or something, right? Yeah. I mean, the fact that I was doing this now for essentially the fourth time because we did it on three different microcontrollers and then we redid it on expressive, that made it go much faster. But just starting with a good library rather than starting with a data sheet is a huge difference in how long it takes you to do something. But in any case, doing it in your Python code is going to be nice and fast now because you just have to write a few lines of code. Yeah, so you have to configure the data clock, another clock, some more control signals, and then these come from the board definition. So that's easy if it's designed to have the camera built in. And then what kind of picture do you want? How many pixels? And then these other things that you just have to have. And then you can do things like flip it, mirror it, do some color effects, basic stuff. And yeah, so the other demos I was going to have, we're going to show how you can read QR codes, which I had tried to demo on this device and this device was misbehaving. And then we've got some stuff for taking animated GIFs, which is also fun. And then you can upload them to your TikTok or whatever it is that kids do. These days, I'm not clear on what you do next with that. Yeah, so that's me and cameras, and that's kind of foremost on my mind because it's really new code from just July and August. And I've been having a good time playing with it. That's excellent. What else have you been working on? What else have I been working on? Well, this is a little 30 key keypad. And although the guide I actually did was using it with QMK, it is super to set it up with CircuitPython and just use it as a macro pad. Also, you can unhook it, and it's just a fidget item. So yes, those are the ESP32 cams. ZyneLyn was sharing a picture in the Discord chat. I hope those will work someday. They don't work yet. We'd love help from somebody who can sort out a weird, impossible error that happens when you're running Python code. The camera module itself, the image comes in. It's just the boards that I've been testing, the ESPI, are just unreliable. They give impossible Python errors, like can't assign to int when it's not even aligned with an assignment. So the error doesn't make any sense yet. And that's where I left it last week before I took a week off. And I feel like I got diverted from the actual question. What else have I been up to? Well, let's talk to somebody else, and then if there's time to come back around to me. No problem. Dan, what have you been working on? So recently, I've been doing a lot of bug fixes. For 8.00, we have kind of a laundry list of things to do. And before that, I spent quite a while trying to figure out why there were issues with the matrix portal, which would crash after a little while. And that was a whole debugging saga. But it turned out there was a very small and intermittent race condition inside the code where we should have locked something that we didn't when we were sending it something to the SPI device on the board. So that's all done. And now I'm just knocking things off. But in the past year, what really has happened in the past year is that I did spend quite a while on async.io, which is a way of having multiple tasks run in your circuit Python program so that you have things that run independently and take turns running. And you don't have to, often when you're doing something in certain Python, you end up writing a big loop. Part of the loop will read some buttons. And then you might do some animation. And then you might write it right to the display. And you often have to check for things inside other things if they take a certain amount of time. For instance, if you're doing some neopixel animation, you might need to check every time around the animation to see, well, did somebody press a button to see whether something went off? And it tends to make for spaghetti code. So async.io is a way of doing something called cooperative multitasking. And Katnie, if you put up my screen briefly, I'll go really directly to a picture. This is from the async.io guide, the cooperative multitasking circuit Python guide. And somebody could post that in live broadcast chat if they like. So the basic idea with async.io is that there are these tasks that run. And they all run in the same Python program. They're not threads. They're not separate processes. They're just basically functions that run. And only one of those tasks runs at a time. There's a scheduler that manages those tasks. And a task is either running, only one of them is running. A task could be ready to run so that when task one in this diagram says, OK, I'm done temporarily. Let somebody else run. The scheduler will say, oh, let's who's ready to run. Oh, let's run task two. Or a task could be not ready. And it's waiting for something or other. And we don't know what. So the scheduler would say, when task two finishes in this diagram, it'll see whether task three is ready. And if it's not ready, it'll go back around to task one. So the scheduler is doing a fair scheduling of the three tasks. It's doing them in a round, robin manner. And the tasks always take turns. And what cooperative means is that these tasks are being nice to each other, and they're not hogging the processor. So they take turns, all right? Just like we take turns talking in here. And when one is done, it'll say, I graciously give the floor to the other task to let it run. If the task is greedy, it won't let the other tasks run. And then you need something called preemptive multi-tasking where the scheduler says, stop. I need command you to stop, or I'll prevent you from running, and I'll let this other guy run. And that's what happens on your Windows or Mac or Linux computer, is that there are a whole bunch of processes running. And there's a scheduler that keeps interrupting them. And they don't know. They don't give up control. They just might get interrupted so something else can run. But in the cooperative world, you assume that you wrote the program so you know how long things take, and each task will take its turn and then go on and move on to the next thing. So let me switch to another window here. Let me just change what I'm sharing here. Okey-dokey, if you can put that one up. OK, any thanks. OK, so this is a very simple. And I'm looking off to the left because I have two screens. So it's not that I'm ignoring you. This is a really trivial program. It's kind of in either this exact program or a similar one is in the async guide, async IO guide. So you can follow along. And what this is doing is there are two tasks that are running. They're each blinking one LED. And unfortunately, my desktop camera doesn't work. So I'll just have to hold this up. But there are two LEDs here. And if I reset everything, I don't know if you can see that. Are they blinking at different rates? I don't know if you can see that or not. But they each blink for a certain amount of time and they blink at different rates. I don't think you can see it, but sorry. OK, so what's happening here is that there's this blink in the program. There's an async IO, an async function called blink, which takes which pin to blink and the interval between blinks and how many times to blink. And it's just turning an LED on and off. And in between this interval, each time it does something, it says await async IO dot sleep for the interval. So the interval is like a quarter of a second or 0.1 seconds. This one is quarter of a second. This one is 0.1 seconds. And so when the program gets here, this async IO dot sleep, it will give up control back to the scheduler. So the main program, what it does is that it creates two tasks and each of them are basically an invocation of this blink routine. And then we say, let's run both of those using this gather function. And the scheduler will run one and then the other. So we'll run LED one task. It'll turn on the LED and then go to sleep. And then the scheduler says, oh, great. I'll let the other person get the other person run. And it says, I'm going to go to sleep for this amount of time. So it lets the other one run. That one turns on its LED. And then it goes back. It gives up control of the scheduler. And the scheduler says, hey, is LED one task ready to run? And it says, no, no, the sleep time hasn't occurred yet. OK, well, I'll go to the next one in line. Is LED two tasks ready to run? And it says, no, no, the sleep time hasn't elapsed yet. So the scheduler will just wait until the sleep time for one of the other has expired. And then it'll let that one run. And so what will happen then is that the LED will get turned off. And again, it will go to sleep. So these two things are running completely independently, blinking at different rates. And they don't have to know each other. And there's not one big loop where we have to keep checking what time it is and has the time elapsed for one or the other. So it's a really nice way of breaking apart things that need to run independently. And this is the most trivial example. But you can use this for all kinds of things that need to run independently. And you can write, for instance, we don't have this yet, but we're going to have a version of the requests library, which does Wi-Fi requests. And it will say, OK, I'll make a web request. And then I'll go back immediately. And you can wait for the web request to finish. But in the meantime, another task can run. So for instance, if you're talking to a slow web server and you don't want to wait for it, you want to do something else in the background, like talk to another web server or do an animation or something or update the display, you can do that. And then when the task that's waiting on the web request finishes, or when it gets the request, then it will go ahead and be ready to run. And this will work out very nicely, we hope. Async I go has been in Python for a long time. It was originally put in to do network programming. So that's kind of an example of what I was talking about. But there are so many other uses for it when you're talking to external devices, which wasn't really a consideration for regular Python, for CPython. So that's what we hope to continue developing things. We need to make more and more things be sort of async-capable. And Jeff recently did some work to make the keypad module be more friendly and more async-capable and be able to run faster, which is way down in the depths of how these things work. But we hope to make that work out better. So this has kind of been on hold for eight. My work on this has been on hold for eight. But once we get eight out, I hope to come back to this and do some more things that make and have more examples and write more libraries that are async-capable. Hey, Dan, try holding it up again, except hit Reset once you've got it closer to the thing. I didn't have you big at the time. So let me just see if I can get this. Perfect. Wait, is it not like press Reset? It's not blinking. No, I think a wire fell out or something. Yeah, so I kind of researched it. Oh, I know why it's not, because it's not code.py. All right, hold on a second. I researched into what does it take to make an object in the core be something that you can apply that can apply that weight, a weight keyword to. And the answer is you can't quite. You still need a little bit of helper code written in Python. But I was able to understand enough so that everything in the keypad library, there's a very small wrapper you can put around it that makes it awaitable. There it goes. And so one thing that means is, because keypad.keys will sense when the key is pressed and when the key is released, it is a lot like having an interrupt, quote unquote, because after the signal goes from high to low, that await, an event will go in the event queue and then the await will return because there's now an event available. So this is very close to what people are asking for when they asked for interrupt pin support in CircuitPython. It's not technically an interrupt. It still is pulled every x number of milliseconds by code in the core rather than being a true microprocessor interrupt, but it lets you wait for a change on a pin and come back to your code in a very efficient way. So I'm excited about that addition and kind of the way that I did that I think we can extend to other items. The other element that we need here is some kind of wrapper library that you could import that would make it easy, not make you have to individually write that Python wrapper code each time. I will drop a link about that little feature in the Discord chat. And I'd love to hear what anybody thinks about that or thinks would be good to add in that respect. I really appreciate Jeff working on this. And looking at the guts of the insides to see how it should work, that was wonderful. So Dan, a lot of work went into implementing async.io. It seemed like a lot of that was you working to understand it. How did that go for you? That was the hardest part, yeah. Because async.io as used in regular Python, people have complained about it a lot because it was very hard to understand and I myself didn't bother to try to understand it. And then I found some people who had written libraries that aren't async.io. Async.io is just one way of doing async.io in this cooperative multitasking in Python. And there's another library called Trio which was kind of more structured and easier to understand. And once I read that, then I really understood really understood what was going on. Unfortunately, we can't have Trio in Circuit Python. It's too big. But there's a key part of Trio called task groups that are very structured way of using tasks. And that's going into Python 3.11. And there's also going to be a version in MicroPython. It's really just something that you can implement in Python. And so we expect to adopt that really soon. There are some features that were added to Python 3.11 that have to do with exception handling from multiple tasks that are really complicated. And maybe we just omit that because it's kind of complicated and not really that necessary. But so what I had to do was understand ASIC IO well enough to write a guide. And that's basically how I educated myself and how I came up with the simplest examples that weren't tricky. And all the CPython examples I found were more complicated than what I put in the guide. So the guide is really the result of me trying to make it as simple as possible for myself and then explaining it to you. The regular emphasis you've said this a couple times about ASync IO and desktop Python is networking at PyCon 2022 this year that I attended thanks to Adafruit. I attended a talk where somebody was talking about it from the point of view of creating a video game in which each actor in the video game was a different ASync def function. And to me that was an interesting talk because that corresponds a little more to the things you might want to do with ASync in a circuit Python program. You've got a sensor or you've got a button or you've got an LED and you want to think of them as independent things leading independent lives. And so it kind of fits into this mold of I'm using ASync to talk about the objects in my video game. So I will also find a link to that talk and put it in the Discord chat because it was a non-networky way to think about it. Although the particular presenter had their own ASync library like you were talking about Trio is different from ASync IO. So it doesn't directly translate over to circuit Python but it's definitely a good way to think about a reason to use coroutines. Right and I think yeah what's really going on the way the way the stuff really works in Python is that Python has coroutines which means that in the middle of a routine you can temporarily return a value or not temporarily but you can return a value and then when you call the routine again it starts up where it left off. So really that's like kind of like a task and that mechanism was adopted to make a sync IO but it was really used for another purpose. It was used for generators and stuff and it was kind of repurposed into cooperative multitasking and because of that a lot of the early work on ASync IO in Python was very ad hoc and there were a lot of things about passing data around that weren't understood well and so forth. I mean the key to making things when you have multiple tasks or threads or processes running the key to not having a lot of problems is to make sure that they're not sharing a lot of state because if one thing changes something the other one doesn't expect it that's where the bugs come from. So in threads this is especially bad because there's no control over that and I thought unfortunately there aren't that many globals so you can avoid that in processes if you have multiple processes running they share state using the file system and sometimes there's a race condition there so the key is always to avoid sharing to share as little state as possible. And if you're not on a Discord you should join us and hang out but the title of the talk is Why I Reimplemented Trio in a Game Engine and it was presented by Daniel Pope at Python 2022 at Python US 2022. Good talk. Okay so I think we could move on. Katnie I'd love to hear about your Mailbox project. This is a great project which is not like what kind of project will you make but this project was inspired by a real world need which is the right way to figure out how to do something and what you really need to do that's great. So this whole thing started because a year and a half ago maybe two years ago my dad said, hey, I'd like to know when I have mail in my mailbox can you make a flag or something that stands up and then I can look at it with binoculars and see it. And I said, no, I can do way better than that and did nothing about it for quite a while. The way that their place is set up is the mailbox is about 800 feet from the house. So and there's trees, you can kind of see it from certain places but there are trees in the way. And so walking all the way down that driveway to get to the mailbox and check it and not have mail was annoying. So that's what this came out of. And so I wanted to do something where when the mailbox door opened something would send a message to something in the house. The ideal situation was to send a text message to his phone but I will explain in a bit why that didn't work. But I wanted to be able to send something, a signal to the house that said, hey, there's mail. So the easiest way to do that as far as I understood it was using Laura which is long range radio signals. And we have plenty of Laura boards for different microcontrollers and different for Raspberry Pi as well. And the process was, I figured used a Raspberry Pi as the receiver mostly because it can handle that kind of code. It might be a little bit overkill but the Laura Bonnet which works on any Raspberry Pi but it's designed to fit exactly on the Raspberry Pi zero or zero W or zero two W. So I wanted to use one of the smaller pies so that it wasn't overkill, like real overkill. And by the way, thanks to Carter for sending me two Raspberry Pi zero Ws. I have a bunch somewhere. I have no idea where they are. I've moved twice and lost them all. And Carter had a couple sitting around so I was able to move forward with this how I wanted to. So I don't know anything about Laura. I still understand very little of it. I get the gist of it, it's sending signals and so on but I certainly didn't understand the code and I didn't understand how to write the code. And I knew of one community member who was really interested in it and I thought that he would be able to write the code. So another thanks to Jerry for helping me out with this. The code that he wrote, well, let's talk about the hardware first. I used a Feather ESP32 S2 because that was the only board at the time that had a battery monitor built into it. So I didn't need to add an extra board for that. And the Laura Feather Wing. And on the Raspberry Pi side, I used the Raspberry Pi and a Laura Bonnet which has a display on it, which is super handy. Other required, well, it's powered by a battery or a solar panel. There's a, let's bring it up actually. Let's do this. Oh, that didn't work. Hold on, let me try something. Nope, doesn't work. Okay, so we're going to do this mode and do this. So here is, it's gonna knock everything out of the way, but then of course it set it off. So this is the solar charger. It is a breakout board where you can plug a loadout, which is the Feather and a battery into it. And then on the other side, you plug in a solar panel with an adapter. And I wanted it to be able to sort of run on its own and not require external power like from USB or anything like that as it was going to be attached to a mailbox 900 feet from a house. And it also requires a normally, hold on, I wrote it down, normally open read switch. Read switch concepts are confusing. They're not really intuitive, but the normally open is a crucial thing because the circuit Python code uses a panel arm to wake up when the signal is sent and that normally closed isn't supported, which I tried to make it work and it didn't work. And it turns out that's just, we don't support the concept at the moment. So that's a crucial thing. I also attached a giant chunky LED to this bonnet, which I don't want to unplug the pie because it's working right now. So as soon as I demo the actual thing, I can take the pie off and show how I attach the LED because it's kind of ridiculous. And so when the mailbox opens, which is that this switch is mounted to the mailbox and the mailbox door, it sends a signal, it sends a packet to the pie, which is waiting to receive at all times, well, it wakes up the feather, sends the signal and it shows that on the display, which my dad asked specifically for it to say, you've got mail, which didn't quite fit. So it's just you got mail and the LED blinks. So it's got both, you know, it lets you know on the screen but also from a distance you can see the LED blinking from, you know, the other side of the house. So basically I open this switch as though the door has been opened. Sometimes it takes a second for the signal to be received and there we go. So the display says, well, now it says mailbox times two. And what that means is that it thinks the switch is open twice. I think that's because the feather reloaded in the middle of this. I've got the serial console open and it did the reload. But that tells you maybe that you've gone and gotten the mail and opened the door yourself. And then you can reset it by pressing any one of these buttons. And if you leave this switch open, obviously it continues to send that packet and so it would receive it immediately. But now I've cleared it. And the little bit that shows up on the bottom, the top, the artifacts on the top, we never quite figured out why those were happening but this little bit that shows up on the bottom is the wifi signal. We just wanted to have an indicator of that on the Pi so we knew what was going on. So let's talk about the build. So I'm gonna unplug this so I can take the bonded off of it without causing problems. The Pi requires headers. So that's part of the soldering for that. You wanna get, well actually it really doesn't matter, you can use single row headers and just put two of them on there. But you would wanna solder the header to the Pi. And then this big LED, I wanted to be as compact and flush as possible which I received several suggestions as to how to mount the LED because the LED needs a resistor and none of them quite fit what I wanted. So I did a super hacky work around with this and the positive pin is connected to a pin, the TX pin specifically because all the pins of the Pi are broken out in this row. And then the ground side of it is actually shoved through, let's see if I can get this to focus, probably not. The mounting hole and the resistor is connected to ground, it's bent weird and the two pins are connected. I put a piece of capton tape which is high temperature polymide tape and it is not conductive. And I put that across any pads that this might have touched just to make sure I wasn't sending urine signals. And it worked great and it made it so that it was very much not sticking up higher than I needed and there's no extra hardware on the top. Definitely not necessary but it was a good workaround for me. In terms of the feather, this is the Laura Featherwing, it does require you to solder these wires which the guide for the Featherwing has on it options. Apparently there are multiple options for the Feather ESP32 S2 but this is the configuration I went with mostly because it's what Jerry suggested. And you wanna run whatever the ground line is from the read switch to ground which is wacky right now because for me, because this is actually the ground line, the white one and the black one is the signal line which is backwards in my brain so I had to double check that about 16 times. And it's just plugged in using female headers on the feather. Now for powering, there's a couple things. The solar panel itself requires an adapter to plug into the charger and there's two adapters available on Adafruit but this one has this, basically this bit here that makes it, I can't even do it with my arms straight out. The bit that sticks out past it actually clips right over the plug and you have to push it in there hard and now it's sealed. So I didn't have to actually seal the solar panel cable the adapter did that for me. So this was a great one. And because the feather has charging circuitry on it because it will charge a battery if you plug a battery directly into the feather to avoid any chance of the charging circuitry trying to work over top of the solar charger you need a JST to JST cable and you need a shot key diode on the power line basically. So I kept this one visible to just show what we did and because the cable is the same on both sides even if you plug it in backwards it just won't power it. You won't break anything and then you know to flip it. And then this amazing USB-C solar charger it worked great. It's difficult to show here because I don't have a window close enough to put the solar panel into. But I used a smaller battery one size down from this one in the actual one that is mounted on my dad's mailbox. And because of the fact that there was such a distance and things that could interfere I included an antenna which I don't have extras of so I can't show it but it's a black antenna that is an option if you need more signal but you can actually attach a wire of the proper length which the guide covers out as well. And as long as the wire on the pie and the wire on the feather are oriented in the same direction it works really well. Right now there's no antennas attached to these because they're literally two inches apart. One thing I will say is to attach that the black antenna that has the little connector on it to the feather wing you have to solder this tiny connector to it. I didn't do it. I had somebody else who solders better than I do help me out with that one. It's very tiny and I'm sure it could be a pain for some folks to do because soldering a wire to these pads is much easier. So give that a try first and then worry about adding an antenna if the signal is an issue after that point. So I also got one of the small clear top project box that Adafruit sells and drilled holes out for the antenna and the solar adapter and then sealed those with a silicone sealant and that is in the switch as well. And we had to extend the wires on the switch quite a bit to get them from the project box to the door. And it worked. The, my dad wanted, we initially had all these other ideas, you know, let's have it send a text message, let's have it send an email instead. It turns out there's this registry now that you have to, if you're gonna try and send a text message to any major carrier, you have to be part of this registry and it costs a bonkers amount of money and things like Twilio, which you used to just be able to use that service to send an SMS, don't work anymore that way. This is as of March, 2022, I think. So we ran into that and that was like we kept figuring, couldn't figure out why everything was crashing and why it wasn't sending. And we finally figured that out. And then the email thing we just never got to work and I wanted this built for Father's Day. So I had a deadline and I managed to almost meet the deadline, I had it mostly done. But basically when it was all said and done, my dad said, you know, this LED is working for me. Can you just make the code not do the rest and just have it blink the LED? And I said, yes, we can absolutely do that. So this is what we ended up with. I used 3M command adhesive Velcro to mount everything in the project box so that if you need to remove anything, it's removable but it's held solid otherwise. And I guess, you know, that's it. We, thanks to Jerry for the help and thanks to my partner Rose for help with the Raspberry Pi code. The code that Jerry wrote handled the signals. That was the basic code. And then we needed to add all the notification stuff. And that was a little outside my wheelhouse to do actual Python code that had all the signal stuff in it and actually had the notification stuff in it as well. So Rose did most of that as well. So I had a lot of help with this but the build was all me. My dad actually rebuilt the whole base for the mailbox to handle the solar panel on the back of it and where we could mount the project box as well. And so that was a lot of fun. So for wireless, the circuit Python board is using Laura, not Wi-Fi, right? Say it again. For the wireless from the circuit Python board that's using the Laura and not Wi-Fi, right? Correct. The Wi-Fi was superfluous to this project. I wanted the battery monitor and that's why I went with the ESP32 S2. It's every bit of signal coming from one to the other is using Laura. So I could go over the code a little bit if... I've never seen Laura code, so... Okay, let's take a look. Let's see what happens if I... I think it's interesting also is that there are so many design decisions in here. Like there's kind of the UI of the whole thing and whether the two boards should exchange information or just should be one way. There were so many design decisions beyond just like... There were so many things that caused you to make certain decisions. And I think that's interesting for a project, even a project that you might say, quote, oh, this seems really simple, but in fact, it's not simple at all. And to get the right... To get what you wanted to do, to get it to do what you wanted to do reliably, yeah. And yeah, that's interesting. You mentioned that my partner's really bad about scope creep, which is a term for continuing to add features beyond what you actually need, beyond the minimum viable thing. And so when it came down to it, I had to very specifically say only this, just add that I don't want anything else, only this. We've worked together previously on the LED animation library and the API for that was entirely my doing. And a lot of the code was hers. So we've worked together in this way before. She's much more fluent in Python than I am. So it's always a good collaboration there. But yes, for sure, there was decisions on exactly what I wanted it to do. And then obviously what I wanted it to do was one thing, then once it was in my dad's hands, what does he want it to do? Which is really ultimately what I needed to provide. And so that's when he was like, well, I'd like the message to be something else. Or I'd like just the LED to blink. And so we did all that around what he wanted. So let's take a look at... Let me remove this, there we go. Let's take a look at some code. So I have the Raspberry Pi code as well, but that is, like I said, a little bit outside my wheelhouse, the circuit Python code. I understand for the most part. So we'll go over that instead of the Raspberry Pi code. All this is available on GitHub. I will drop a link in the chats when I am done. So, basically, and again, I don't quite grasp what alarm does. One of you may be able to help me with this section here. But we set up the battery monitor, which is built into the feather. And that allows us to get the battery voltage. And that appears on the Pi display when the notification shows up. And that way, if at any point it has dropped significantly, we know we need to check on wiring or reposition the solar panel or something like that. We set up the little red LED here for informational use later. And the alarm pin is what the read switch is connected to. So basically, when that switch is separated, it sends a signal and that's what we wanted to capture to wake it up. Because we wanted this whole thing to go into deep sleep when it was not in use so that it's using very little power. The idea being that if the solar panel isn't working, is covered up, or it hasn't been very light out for a while, it would still be able to run for a very long time. And so we need a pin, obviously, to wake it up to be able to send the signal at all. This is Laura related. This is setting the frequency. It turns out, if I understand it properly, in the US, only 900-ish megahertz is allowed. Is that right Dan? Yeah, without a license, yeah. Yeah, so that's a standard thing. That would be anywhere in the US. And then this is standard, I wanna say, in Europe and elsewhere, but check and make sure that you have the right Laura board and that you put that in your code for your local area. And then the RFM chip, which is on the Laura featherwing, requires some setup as well. And this says, apparently send a message as long as the pin is low. Now, the way that the packets are sent here is as a byte array, which there are, there's three different versions of the code that Jerry wrote for me. And I don't recall what the other two do, but they send the information in different ways. And it's just, it all is allowable. The pie can receive in multiple formats, but this is the one that we went with. So basically this refers, the reason it's not pin.value is the way that the normally open switch works. It sends false when it's, basically sends false when it's separated. And this is what we are sending. The important bits here are the, these sections here and then, which again, I'm not entirely clear on what alarm.sleep memory is doing, but this is the things from the battery monitor, which allows you to send the voltage and the battery percent. And to be clear, this is only happening while this is open. So if you were to run this code without, with the switch closed, it'll hurry through it and go to sleep. And then it will wait. So this is the sleep code here. And, but when it opens, it then sends a packet to the pie. If it doesn't receive an answer, it prints this, it hits this, and then I believe retries. And that would be if the pie is not on and present and waiting to receive. And then sleeps a bit. And we de-initialize the pin here. So I think so that it, whatever signal is sending is fresh. And then we put the RFM chip to sleep. And then we create this panel alarm and that's using the pin that we attached the read switch to the value when we want the alarm to signal, which is why it gives false when it's open. So we want it to send on false and this, because the pin requires a pull up, I think this is true. And then it goes to sleep. It goes into deep sleep. If it's connected to USB, it pretends to go into deep sleep. If it is not connected to USB, it goes into actual deep sleep. And it waits until the pin alarm happens, which is when the read switch sends a signal and then it starts all over again. And like I said, it will only run this bit if the switch is closed when the code initially runs. So it would just go straight through it and then go to sleep and wait until the switch is opened. And part of the reason I wanted it to work like this is the important thing was to have it run for as long as possible without needing to be charged because charging it would be kind of difficult. We have to remove the thing from the mount and like all this other stuff, you know, and you got to open the box and plug things in and so on and so forth. So I didn't want it periodically sending information, which was one of the things that was initially discussed was periodically sending the battery information. And I'm like, that's just really a waste of power, energy rather. So we didn't go that route. It only sends when the box is open, which obviously if the box got left open, it would continue to send. But it tracks, let's pull up the Raspberry Pi code. And that worked. All right. So there's a lot of import stuff going on here. I actually have no idea what some of this is, but we get into the, if you recall, this is the Laura Bonnet and it's a very similar setup to the Feather. You don't have to do those wiring connections. They're done automatically, but it's the same frequency and will require similar setup. This is for the little Wi-Fi indicator that's on the Pi screen. This is the message that it shows when there's new mail. This is when the door opens multiple times before it's reset. This sets up that little blue LED, well kind of chunky blue LED that I put on there. And then you, because there's stuff that uses I squared C, the display, you set up I squared C and then you set up the display. There's a lot of code here that clears the display and then shows, there's a blinking dot that tells you that it's running. That sets that up. And then this is the pins that are actually connected to the chip. The Bonnet has three buttons on it. At the moment, they all do the same thing, but this is the setup for the buttons. This is basic button pulling and a debounce on it. Here we initialize the spy code and set up the RFM chip. And then we get into a lot of stuff that I, this is part where I'm fuzzy, but this talks about the pack and I think it actually sets it up so that it can count the packets and that's how it knows multiple mailbox opening. This is the state of things at any given point in time. This is for the wifi signal bit and this draws the wifi signal bit, which this is just a lot of display code here. This checks the, or this blinks the LED when or this blinks the LED, but this is when to blink the LED and the interval, which obviously can be customized. This is the wifi, getting the wifi strength at any point in time. This is where it's getting packet information and that's what is being sent from the feather. There's some try and accept going on here because you don't want the, if a partial packet is sent or it only receives a partial packet, you don't want it to crash. So it logs that it got an invalid packet, but it doesn't stop the program, which is what you want to avoid if it's something you want to just leave running long term. This was from us trying to use Adafruit IO to send an email. We just didn't get a chance to really work with it, but this was the initial start of that because Adafruit IO can send emails based on triggers and we just never got a chance to really set it up. And then my dad said, please just make the LED blink. So we stopped that. This is checking the buttons and so that whenever one of them is pressed, it uses that to clear the notification. This is what is used to display the text for the mailbox message or the more mail message. This updates the display. Again, this is just standard display code. This is to make the display blank, handle the packets. Once the mailbox is triggered, it sets this off. This is when you clear it. I think that the pie can also look for information and that's what is going on here. This is where the buttons, if any of them get read as pressed, it clears the notification. I don't have it up right now, there's no point in demoing it. And then this is if there are packets to get them and then update the display to show the more mail thing. And then the mailbox sequence is that if there's a packet available, you trigger the things that we just talked about. It sets up the buttons to read in the packet, whether or not there are packets in the queue. And if it's available, it runs this. If there's buttons, it uses the button handler to verify that the buttons have been pressed. Here is the button handler. This updates the different flags, which are that when the mailbox was opened, was it opened the last battery percent and the last packet data? This I believe has to do with the LED if I remember correctly. And then this uses threads which are way outside my wheelhouse. So I will not be able to explain what's going on here, but the idea is that it's looking for packets, it's waiting to blink the LED when the mailbox is opened. It has to continue to check for signals so that it can say that it's now been opened twice or three times, et cetera, and waiting for the buttons to be pressed for it to clear. So there's a lot of things that it's trying to do at the same time. And that is what it does. And then here is where everything is running. So this is what's actually running the code that we just went through. Apologies for the very vague. Explanation of this, but this is definitely code that I had help with. So basically you're always looking for a packet on the receiver end and you're sending packets on the sending end. And that is basically Laura code with a sender and a receiver. I don't know if there's actual terms for that or not, but that is what it looks like. I was going to jokingly interrupt you and ask if you were gonna use async.io, but then you talked about threads, so. Yeah. So with the deep sleep and the sleep memory, basically when the deep sleep finishes, it's like almost everything about your program was erased, but these items within the sleep memory specifically are kept. So that's how you communicate with your future self after waking up. Okay, that makes a lot of sense. This is whether or not it woke up then. So yeah, the first block, the if at nine, it goes into line 10 if it woke up and it goes into line 13 like it was just plugged in. Okay. So let's do I clear out some things that I remember or do I increment the count of something? So zero looks like the count of ever woke up. And I think one is the count of ever saw that the mailbox was open and two was the account I've ever had an error transmitting or failed to get an act or something. Yeah, that sounds about right. And then here, it's sending that information within the packet that is getting sent to the pie. And then this is also where it's incrementing that error. Right. Which makes sense, cause you don't need to keep that on wake up. So I understand why it would be cleared at the top. And this is incrementing the, I think the mailbox status like is, hasn't been opened and how many times, that's how many times it's been opened. Yeah. So one way to make that a little less obtuse. That's a good word is sleep memory does, you have to use the brackets and the number. Although I think Tim wrote a nice library for doing nicer than that. But you could also just give names to the zero, one and two values. So you could say number of times open equals one or whatever it is, you know, whatever name you want to give to it. I don't know if that's the right meaning. And then instead of in brackets one, you could say in brackets number of times open. Oh. And then it would be more self-documenting. I follow. Okay. Each time you have the one in brackets, you change it to the named thing in brackets. So you're just setting a variable. So you're just setting a variable. Zero, one and two. What it does for you as a human is, it helps you understand. Okay, I was tracking for a second there. I thought you meant the whole alarm sleep memory thing. You name that something else. No, just the part in brackets, you give it a name. And then, you know, it's like self-documenting. Yes. Much more human readable. That is a great suggestion. But other than that, I mean, it's nice compact code that does what it needs to do. Yeah. And I'm really happy with it. I had not, I built this last, like yesterday. I didn't like, I obviously don't have the original. The demo version you built. Yeah, I've got my, yeah, this secondary prototype. And I soldered everything up and the feather already had the code on it. And so did the pie or a version of the code. I plugged it all in and it just worked. So that was really excellent. We needed to update the pie code because the pie code was like an earlier iteration that had a bunch of other nonsense going on. So we did that. But that is, yeah, that is the thing. I swear there were a couple other gotchas that I ran into, but I have since forgotten them. I remember passing by and looking for the code, a document that said mailbox notes. I didn't end up looking at it, but that might have some of the gotchas. What I did do was I put it on GitHub and included in the read me all of the parts necessary with links, except a link to the Raspberry Pi because you can use whatever one you want. And I didn't put a link to the read switch either because, again, they're all over the place. But I put all the parts in there and the options for antennae and then also tools and extras required because there's, if you wanna actually put it in a project box, you're gonna need a power drill to be able to obviously drill through the project box. What I would recommend, which is not the greatest thing because it means wasting one, but get two project boxes and practice on one. I was really glad I did that. I wanted to know whether I could drill really close to the edge and all this other stuff without shattering it, and that really worked out. It does mean potentially wasting a project box, but if you managed to drill through the first one perfectly, you don't need the second one, but it definitely would give you an option in case you mess up the drilling at any point in time. You can practice it again and try a different side of the box or something to that effect. Any solar panel will do with this particular connector on it. Adafruit cells, let me add this back in. Adafruit sells a bunch of these. There's a different one that I used and I linked to the different one on GitHub, but if you go to that page, it actually lists a huge number of them and the one that I used is no longer in stock, but the one that he uses no longer in stock but the other ones, there's a ton of other ones available. And there's another solar adapter that has a wire on it. Again, that one doesn't have the seal clip. So, and also for whatever reason, it didn't fit right, which was something I ran into and actually almost didn't because I had to order parts at the very last minute. It doesn't have the little bit that clips over to make it waterproof. So I kind of highly recommend using that little L1. It does mean drilling a larger hole through the project box and it's a very weird size. I needed a 29, 64th inch drill bit, which is not included in a standard set and I had to buy it individually, but I really wanted the right size. You could definitely go with something a little bit bigger, which is more standard and still have the same effect. But I haven't documented the build. This was obviously a personal project, so there's no guide to go along with it, but what I'm hoping is to get some better pictures of the one that is on my dad's mailbox, which has the holes drilled into it and the sealant on it and so on and so forth, and at least push those on GitHub or something to that effect. So it's a little more obvious how the build went. Getting, that's the other thing. So Jerry built this as well. He mentioned it to his wife and his wife was like, no, we really need that. So I felt a lot less bad about asking Jerry for help with the code because he was also building the project, but he used a big project box and I was like, I bet I can fit this. And I had to Tetris it basically to fit it all in the small project box, but it did work. The battery is attached to the top because really like putting everything in bottom is not necessary because you have extra space upward. And the rest of the bits are Velcroed down and then the wiring is kind of just finagled in there. That's what I'm hoping to get. That's what I'm hoping to get pictures of. See Grover asks, unfortunately mailbox baseball is a thing here. Did your dad have to reinforce the final installation? So that has been a thing. I don't know how recently, but it has been a thing on my parents' street as well. And so it's mounted on a wooden pole that's about that big and I think cemented into the ground. And then the mailbox is mounted on two boards that are about this that combine and that's what's holding the solar panel. And he has boxes for newspapers, which I think he no longer gets delivered, but the boxes are still there that are on one side of the mailbox. So we put it between the two boxes. So if mailbox baseball happens, it's gonna happen from the opposite side. So it's really unlikely that anybody would damage the feather setup because there's like a protective thing outside of it as well. You've got decoy mailboxes. Basically. So to get the antenna to sit upright, we had to put it on a block and then there's a 3D printed mount that we designed to go with the project box. You could actually screw the project box right into the mount and then put the lid on the project box and it worked. But we didn't reinforce it beyond that. I asked him whether that was something he wanted to do or whether we needed to do it, like add a giant hose clamp or something to it to like keep it, you know, keep it good to go. But he didn't think that was necessary. So we're giving this a try so far, so good. But it's only been a couple months. We'll see how it goes, you know, for the next however many years, I guess. And that is true, brick mailboxes do prevent that. But my dad's is plastic, but the point is this mounted like lower on the pole. So damaging it would be kind of difficult unless you specifically stopped and just like hit it from the top. So that's kind of how we handled mounting. Link to the waterproof adapter. Oh, that one's been linked, excellent. I will have to see. Obviously project guides are up to folks other than me. So whether or not this will get turned into a guide is not up to me. I did not document the build very well. So I would actually need to order parts again and actually document the setup. But overall it's actually relatively simple. So I think it would be a good guide, but we will see whether that ends up happening. Well, congratulations, Katnie. Out of the three of us, you actually built a useful thing. I mean, you guys built stuff that lots of folks are gonna be using. I mean, that's also excellent. There's that word simple again. I think you underestimate how good you guys are. It's true that with a lot of practice you start to underestimate how difficult things are for a newcomer, but if you feel intimidated by this, I think my advice is try it for a while and you'll find that things are getting easier for you too. And that's why even though I've been doing this for a really long time, that's still the way it goes. I get better at things. And so, yeah, don't sell yourself short and you'll get better at it. And expect to make mistakes and expect to realize that you need to change something because that's what engineering is. I was actually really surprised. I was able to replicate this LED soldering because I got it to work once and I thought I'm never gonna get this to work again, which is why I insisted on using the original bonnet for my dad's version, but I was able to do it. It's a little bit cleaner on this one too. But there's only a few things that need to be soldered. The code would be provided in the guide and will be provided on GitHub. So you can even preview it long before any guide exists. And so as long as you have the right parts, it shouldn't, I guess I'll rephrase it. It shouldn't be too difficult. It's how I will put it. My colleagues at my former job used to say I had two modes, which is me going around saying, this is impossible, it will never work. It will never work and then, oh, it's done. And there's not a lot of in between because it works or it doesn't. Right. There's not a lot of partially working. You can say a couple of features have been implemented, but if it works or it doesn't, yeah, that's definitely the case. Has anybody else have anything to add, any more questions? I'm about to really appreciate the audience. They've had some excellent questions for us today. That's true. We can also answer general circuit Python questions. We do have a little bit of time. A little bit of time. And thanks, Mr. Certainly, for keeping an eye on things all day. It makes for a long day and we're glad to have you back there. And everybody else, I don't know the names of everybody who's probably behind the scenes on this, but thanks. Yeah, we have Kelly, one of our internal folks who's been keeping track of things as well and obviously Phil of Adafruit fame has been keeping an eye on things too. And thanks to Ann for all the blog posts as we put this together. Thanks to Kenny for putting together the schedule and making it work. That was a bit of a beast. A lot of people had different requirements. So we had to, or I mean, I wanted to work around and make sure that everybody, you know, had something that worked for them. How many years until we've got so many people that it's circuit Python week? Well, I mean, today was full. That hasn't happened yet. So we've at least reached the time that we have filled up a day. And the next stream actually, which starts at 6 p.m. Eastern, which is 40 minutes from now, we'll be going for a few hours. So good on Tim for having the stamina to keep folks entertained for that long. But we basically had a video content from 11 a.m. to about 9 p.m. Eastern. So we've filled up a full day. And obviously, if we've got anybody else next year, it'll have to be either shifted to circuit Python days, or we'll have to have synchronous video streams going or something like that. One more use of world time zones. I mean, if y'all are in Australia or Europe or Asia, we can, you know, extend it to the full world time zone. We'd love to have more international content too. Yeah, that would be excellent. We had a Spanish speaking show in Tel last year hosted by Alvaro, who's on Discord as Fitted2. And that was excellent. So definitely understand that that sort of opportunity is available. We were able to do that at a time that worked for the host and so on. And, you know, we can accommodate a lot of things. So. Yeah, well, our snakeologists are probably already studying what is the snakeiest day of 2023. But I think there's a good chance it'll be August. I think so too. It's twofold. One, it kind of works out. Two, there's no holidays in August and Adafruit provides a paid day off for Adafruit folks at headquarters for circuit Python day. So having another day for us though. We're here. It's hardly work though. So that, that's an opportunity for that as well. And since there's no other holidays in August, it makes a great month to do it. Yeah, everyone built a badge. So this could be a badge. Alvaro says he promises to do a Microsoft circuit Python day next year. So we'll definitely have that. And we've had in other years, was it last year or before there was like a circuit Python kind of workshop in India, I think, on circuit Python day or? Yeah, I think so. Yeah. So if you want to do some local events. Yeah, my local makerspace is actually doing a circuit Python day event this evening. If you're in the Detroit area, I3 Detroit is doing circuit Python day event. There's Q&A, demos and just opportunities to tour the place and learn more about circuit Python. So that was excellent to see as well. And I had nothing to do with that. They reached out to me to let me know that it was happening. So that was also excellent. All right. Well, I think we're good to go. I want to say, since I'm not going to get another opportunity, thank you to everyone who participated in circuit Python day. It's been amazing. I'm really glad that everything has worked out. Thank you to all of our hosts. Thank you to all of the folks that participated in different streams. Thank you to our community for making all of this possible. We say code plus community equals circuit Python and we mean it. We can build code all day long, but without the community could contribute and be a part of it and use it, we wouldn't have what we have today. So thank you to Paul Cutler for doing the introduction. I did not have to do that either. And next step is going to be Fome Guy's Game Jam live stream where he's going to build a game using circuit Python and hopefully have working code by the end of the stream. And all of that will get posted on GitHub. So if you're interested in looking into that after the fact, all the code should be available. So thank you so much to everyone. I can't express that enough. I hope that the rest of your circuit Python day is amazing and please feel free to email us with your experience if you feel up to it. CircuitPythonDayatatafruit.com is available. I won't go away. So if you wanna let us know how it went for you or anything you'd like to see next year, feel free to reach out. And finally, we do a call for what folks wanna see out of CircuitPython at the beginning of every year. And we talked about doing it more than once a year. So I think CircuitPython Day is an excellent time to put that out there. It won't be nearly as official. We probably won't aggregate all the posts this time as we usually do at the beginning of the year. But if you have ideas or concepts or things that you would like to see out of CircuitPython or let us know what has been great for you and what hasn't worked out for you, feel free to email CircuitPythonDayatatafruit.com with a post or a gist or any kind of way to write down what it is that you want to see or have seen, et cetera and let us know. It's always really great to hear from the community and I think folks don't always realize that we don't mind hearing from you all year long. So we put out these calls so that people know. So feel free to send that in. It's not required obviously, but we would love to see where things are at for you in CircuitPython as we're moving towards version eight and so on. So thank you again. Let's blink an LED. There we go. I got mail. And now I don't. And with that, I will go ahead and wrap this up. Thanks again to everyone who watched and thank you, Jeff and Dan for joining me once again this year for another amazing chat. Great, it was fun. All right, so thank you everyone and hopefully we will see you next year.