 Right. Hello everybody. Happy Friday to everyone. Started it up just too early here, so I will wait just a moment for folks to come in and then we'll do the introduction and get go on the road as they say. Looks like I got sound pretty well. Let's make sure we could probably make the volume a little better. That should be the right source. Looks like we got it coming into OBS, so we should be good there. I don't hear myself anywhere, so this is good. Is the YouTube chat working? Yeah, it looks like it. I didn't know for sure if I was gonna have to re-up the chat window for YouTube because I opened it up a little while ago and sometimes like you open it up a while ago and then like you change accounts and stuff and I don't know if it carries through or I feel like I had it stop updating at one point. So here we go. Yeah, it looks like we are updating over there, so good day. Be out of graph. Paul hanging out with us from home. Oh isolation. Got the coronavirus. Oh no. Well, I hope you know, I hope you're not feeling too bad and you know, hopefully that you will be recovering pretty quick here, so definitely, definitely no fun. So wishing you the best there. Let's check in on Discord chat as well. I'm still kind of shuffling around some windows here. Happy Friday to Liz. Sound is good. Thank you. Appreciate the heads up there. All right, we don't really need this one. See Grover. How's it going? Happy Friday. Let's close this. And I think I could minimize this one. Just a cough so far. That's good. That's good. All right. And I did change the scene, right? You guys, yeah, you can see my screen. You can see me. We're good to go there. So hello everyone. My name is Tim and I go by FOMIGuy on GitHub and Discord. This is going to be the deep dive program where we will be looking at some of the innards of Circuit Python. So you know, it is a pretty intensive level thing. If you're brand new and you haven't heard about any of this stuff, there are some, you know, there is some better content out there that's more suited towards folks who are brand new. This one we are going to be getting pretty deep into it. The name deep dive is a reference to that. I will say though, if you are brand new or you're watching this in the future and you don't know what I'm talking about, this is the website where you can go to learn more, circuitpython.org. Basically, this is a implementation of Python that runs on tiny computers called microcontrollers. There is an example of a bunch of them here on the downloads page. So you can see they're all different shapes and sizes. And then over here, I actually have the camera loaded up and this will be one of the ones we're going to be using today. So this is a Circuit Python device. We're writing Python code that runs on this device and even is interpreted by this device as well. So it does the code interpretation and executes for you all on the device. Circuit Python is an open source project. Again, you can learn more at circuitpython.org. You can get involved with contributing over on circuitpython.org. Also, I would encourage you, if you do want to get involved in the community or the project, head over to the Discord and join us in there. The Discord, which is on the screen, I think right below me there is the live broadcast chat on the Adafruit Discord. So head over there and join us. All of the Circuit Python dev developers, all of the core team and the wider community all hang out on the Discord and communicate through there. So come and join us. If you are interested in playing around with Circuit Python and doing things like this, what you can do is head to Adafruit.com. Adafruit is a hardware and software company based out of New York. Adafruit is the company that is providing all of the financial backing for Circuit Python. So they're paying the team that works on Circuit Python full-time. They're paying some folks who work on Circuit Python part-time, like myself. So if you want to get your hardware and you purchase it from Adafruit, that is definitely most appreciated because then you are helping support the Adafruit company, which of course is who's paying folks to work on the Circuit Python project. So on behalf of myself and everybody else on the team, definitely thank you and do appreciate purchasing hardware from Adafruit. I do notice on the website here, they have the note up about Memorial Day. So if you are going to be ordering this weekend, of course, there won't be any shipping going on Monday. So it will be probably an extra day or two added onto the normal order time, I suppose, for that. So keep that in mind if you do want to purchase something. So to Shippu, how's it going? Mark Gambler, Touch Calibrator. Yeah, that's one of the things I'm going to look at. C Grover, thanks for not only creating that, but also thanks for doing the process to get the PR in. That's one of the things I have on the table to look at today. Ola from the Colorado, love the factory. How's it going over there in Colorado, I should say? Okay, so we did the introduction. So let's look at what I'm getting into more specifically today. One of which, so I got two kind of things lined up. Both are dealing with touchscreens. Where's my key? Okay, I'm still getting used to the camera being on a separate window. What I've got here is Adafruit Pie Portal device. This one happens to be the Pie Portal Titanic, which is just a little bit bigger version of the Pie Portal. It has a nice big screen on the front of it. It has a touch overlay. So we're able to have buttons and things like that. We can make soft interfaces on the display. So a couple of the things I'm going to be playing with today are going to deal with the touch screen. Over in YouTube, Ola from VA, Virginia there, I believe. Ryan Motley, how's it going? Thanks for tuning in. Just ordered a couple of things to try to start contributing. That's awesome. Thank you for that. Isaac Ben, appreciate that over there on the Discord. So first thing that I do want to look at is the touch screen library. There is a PR, which C Grover just mentioned here. I saw this come in the other day. I have not done a lot of Circuit Python stuff in the last couple of days. I've been super busy at work this week and had some other stuff. So I've been doing lots of like Stardew Valley is kind of what I've been doing when I'm not working for the last couple of days. But I'm getting back into it today, of course, for the stream. So I saw this come through the other day and I kind of threw it in the back of my mind to come and look at this, of course. So thank you to C Grover. I think I asked for you to put this out there. So I definitely really appreciate you making this and getting the PR in for it. For folks that haven't caught on, I think, I've talked about this a few times here and there on the stream. I don't know how deep I have, you know, dived into it, you know, so to speak, deep dive. But it's basically a calibration script for the touch screen. So the touch screen, this particular style of touch screen that's on the PyPortal Titano here and the PyPortal regular as well. It's basically two analog sensors. It's kind of like two flex resistors is the way I think of it. Or I don't know, that's probably not the right term. But basically, there's two analog pins, one for horizontal, one for vertical. And of course, you can rotate this around artificially and software. So, you know, I say horizontal and vertical, because that's how it is right now, but you can switch it 90 degrees or 270 or whatever you need as well. And you get an analog value representing sort of the proportion of the way through the screen, right? So like, you know, zero is over here on the left or the top, you know, max value, I think 63,000 or some power of two is over here on the right, you know, and then bottom and top for the vertical one. And the touch screen library is basically converting those two analog values in and taken into consideration as well the number of pixels on the display. And it's converting those analog values into the pixel coordinates that is represented by that particular spot on the screen. So this is an amazing feat of sort of analog sensing technology. It's super awesome that it works this way. The kind of like, you know, pitfall or downside, if you will, to this over like a capacitive screen is that it can get shifted a little bit. So you see, like in the image here, there's a depiction of a stylus. And the point is intended to be right on the stylus, but this one, it's shifted by a couple of pixels. Now, if you use your finger, right, switch back here, if you use your finger, you know, if it was shifted by this amount here, it's probably not going to matter. It's still going to kind of be under your finger, it may be sort of off to one side, but probably not going to make too big of a difference. If you are using a stylus, though, like they have in the picture, then that shifted amount becomes much more apparent. So this script here is a calibration script that it allows you to basically calibrate your touchscreen to set up some configuration values so that it has a finer grained detail of like exactly where the different analog sensor values lie in relation to the screen. Sometimes they can be different just on different screens. I imagine like environmental factors probably matter for this. I don't really know all of the electrical theory behind it, but I would think, you know, things like temperature, humidity in the room, stuff like this might make some kind of difference. I don't really know for sure, maybe not. But just different stuff about it makes it so these values are not always exact. And you can run this calibrator script to get yours set up so that, you know, it's dialed in for your specific screen and your specific environment. And then you'll get really, really accurate results with it. So that's what this is. And it got added as I think an example here to the, yeah, inside examples got added as an example to the touchscreen library, which of course, this is the driver library that interfaces with that actual analog touchscreen, you know, component device. It gets plugged into the to some pins, some GPIO pins that are available. And then this library reads those analog values, converts it over to the pixels, and then gives you a nice, easy to use interface, programming interface to interact with it, figure out what got touched, when and where and all that stuff. Already imagining my CNC router with a little G code and a pen holder, automating the calibration. Oh, that would be pretty sweet. Yeah, that would actually be super cool. Calibrate with the CNC machine. Yeah, because then you could get input and feed it back into the machine kind of. That'd be super cool. One of the things I did this week was I updated PyCharm. And one of the things I noticed about the new PyCharm, and maybe the old one had this, I don't actually know, I never looked into it. But one of the things I noticed is, I can actually look at pull requests inside PyCharm. Now, I have done it just enough to see that it's there. I haven't actually done it, you know, for real, like to actually leave a review and stuff. So I figured I'll do that on stream. That seems kind of fun, right? Let's try it out. So if you use PyCharm and you have a relatively new version, I think, I don't really know, the previous version I had was like two years ago. And then I finally just updated. So, you know, maybe this was even there then, and I just never saw it, or maybe it was sometime between then and now, don't actually know for certain. So if you do use a newer version of PyCharm, you should have access to this. And it's inside of Git, there's a view pull requests. And boom, it will pull up a list of the pull requests from GitHub and show them to me in the IDE here, which is really cool, because I don't have to then bounce back and forth between the IDE and the browser. And so I can click into here. And it shows me all the details from the pull request. So I can see the pictures, I can see all the text that Sieger ever submitted, I can see who submitted it. I can see the number, basically all the relevant information, the date, the commits, all this stuff. There is a button here, checkout, which I think is going to check out the branch for this PR, which it looks like is Cedar Grove Studios main. So let's do that, create. And we cannot set tracking branch. I think that's probably fine. We're not going to commit to it anyway, so it doesn't need to be tracking. Cedar Grove is ambiguous, I'm not sure why it's ambiguous exactly. And so again, this is the first time I've used this, I'm not sure what all of these little errors and things are going to mean, but we'll see as we go along here. So let's read this, simple I will resist the touchscreen for built in displays to use it run as a standalone module, include the following line in the calling of the module, or type it in the REPL, so import, touch calibrator built in, operational parameters such as screen rotation, REPL only measurement, and REPL only measurement display can be set, REPL only measurement, I'm not sure what that means, I bet we'll see a little bit more once we look into the code and maybe call it, let's see. When the test screen appears, use a stylus to swipe to the four edges of the visible display. As the screen is calibrated, the small dot tracks the stylus tip. When REPL only is false, here we go, minimum and maximum calibration values will display on the screen and in the REPL, the REPL values can be copied, this is probably my favorite thing about this is it outputs in the exact same format you need to paste into your own script. So you can just like copy it out of the REPL into your own thing, which is super sweet. The REPL values can be copied. Let's see here, hope I skipped a line and paste it into the target's code for the initialization of the touchscreen, calibration values measured for a display rotation of zero degrees, use calibration values in the target orientation, I think that means correlate the touchscreen pins and the calibration values, the order of the tuples is determined by the display rotation value. For example, the tuple of this one here would be inserted into the instantiation statement in the order shown depending on the orientation. So basically you're taking the values and flopping some of them around, both the pins in the way they're listed and the calibration numbers here, depending on the orientation of your screen. But I think there's more, I almost said destructions, more destructions in the file here as well. So let's take a look in the file. This is it here. One thing I think we'll want to do is probably rename this to have touchscreen in the name specifically. I don't know for certain, I think there's a tool somewhere that is expecting the examples to have the first word, well the, because this one happens to be one word because the name of the library is one word touchscreen. So I'll try to be careful and phrase it correctly for some other cases as well. The beginning, the first prefix part of the example name should always be the name of the library. So like the base name, this one is touchscreen. So all the examples should be touchscreen underscore. So you could either do I would probably just add the screen right here, but it doesn't matter too much. As long as you start with touchscreen, so you could say touchscreen calibrator built in. So that's one thing we'll do. And I know Cedar Grove is watching, so you probably hear me talking, but I'm also curious to use this interface as well. So I'm going to try to leave that as a comment also and see what we can do here. Do you think I can do the like comment inside the code at a certain, well, I guess it's like, doesn't really make sense though, right? Because it's not a certain line of code that we care about. It's the name of the file. Yeah, certain line of code doesn't make much sense. I don't see anything for it here. Let's see. Entity. Oh, add review comment. Actually, yeah, it looks like add review comment. Oh, look at that. Okay. Yeah, yeah. So I do think I'll go back though. I'm not going to do it for now. Let's go back and let's just do the comment on. Let's see, how do I get back here? Info. Let's just do the comment on the base. How do I do that? Let's see. Conversation. There we are. Yeah. Let's see. I think we need, we need the example, need the examples to follow the pattern of starting the file name with the name of the library. I think it's like, I think it's like the bundling tool, the bundling tool or the project bundling system, something somewhere I think is maybe the screenshot thing or something. Something I'm pretty sure is hard coded to, well, not hard coded per se, but hard coded dynamically to expect the name of those examples to be that, to have the prefix of that base library name. Follow the pattern. I don't know exactly what it is or where it's at though. That's just a nugget I feel like I've picked up at some point in my time with CirclePython in the file name. So for example, maybe, oh, okay. What's the ending one for me? Oops, now I got an extra one again. Oh goodness. Okay, here we go. Touch screen, touch screen, and then calibrate. What is it? Calibrate or built-in. And then just enter or let's see, post. Boom, looks like it showed up. Let's check here. I mean, obviously I wouldn't, I mean, I have it in the browser also, so I'm going to go refresh it, but I'm mostly just curious if it showed up and it's correct and everything. Yeah, looks good. Okay, that's awesome. Yeah, super cool. Okay, so there's that one. Let's keep checking it out though, because we don't need to, I mean, CGrover can push commits to this anytime to change it up, but we can still look at the code as well and test it out here. So inside the file, and of course this is a brand new file. So we're not like comparing old version, new version, we're just going to look at the new version that now exists and then try it on our device. And so a lot of this, I think, actually is the same from the comment text here, is it? Let's see when the screen appears. Yeah, maybe reworded, but as the screen is calibrated, yeah, yeah. Okay, REPL only. Oh, REPL only, it's like, whether it's going to have like display IO interface or not, whether it's going to draw the colored background in the square, the red square, and also I think it has some text as well with the current X, Y, and maybe the current calibration values. Okay, and then REPL only, I guess, would just print instead. You put your rotation in here, we're going to stick with zero to start with. Okay, nice, it's double check in to make sure that it's a valid rotation. There's only four, they're the multiples of 90. Yep, yep, so REPL only, it's going to not create the group, touch screen setup. Yep, getting ready to show the display IO stuff. Again, if it's not REPL only, then we do this. Colors, what does colors come from? Oh, colors is in here, okay. Is there color constants in rainbow IO? Serious. Don't need that. TO. Oh, no, uh-oh. Oh, I see, right, we're not in device, yeah. For rainbow, rainbow IO? I think maybe LED animation possibly has some, but that wouldn't make sense to import from there for this, so where did I, I clicked away from color. I made a coffee before I started going, I got to actually drink it though. If I go too slow, it'll be kind of late for drinking coffee. That's all right. Okay, so print some instructions, here's our main loop, any sleep, check the touch point, if it's actually being touched, if we need to update the display IO stuff. Oh, let's see, if touch, if, oh, I see, right, right. Okay, so if not REPL only, then do these things here, so if we are going to show it on the screen, update the location of the box on the screen, the little red box, after that, for every, every mode, doesn't matter if we're REPL only or not, we do these, which is get the minimum, store the basically highest and lowest for both X and Y orientations, and it's keeping a running history basically of the lowest value it's ever seen for X, the highest value it's ever seen for X, the lowest value it's ever seen for Y, and the highest value it's ever seen for Y, and those lowest and highest values become your calibration, so it prints it here, and if it is not REPL only, it does also update it here. It's a super minor thing, I don't know that it matters too much, but one thing we could do, see Grover, is if we rearrange this a bit and put these first, then you could actually do this inside here, and then we don't need a second if statement, slight refactoring, I don't know, it's not, is that right? Did I, maybe not actually, let's see, did I do that wrong? So this thinks it doesn't know pin, but maybe this is just and can, can be undefined. Oh well it can be undefined, but it should only be undefined if this, if not REPL only, which we're also wrapping it in here, so it's not smart enough to realize that we have the same condition here as we do for the setup actually. Where's pin? Yeah, yeah, it can't actually be undefined, I don't think. I mean I guess if it failed to set up or something, but since it's inside the same if statement here, coordinates I guess is probably the same thing. Yeah, no I don't think it can, I think that's just a pie charm being a little aggressive on its offer to help basically, which is fine. Okay, I'll try it out like this, I'll go back and test the actual version of it as well without the changes too. I'm curious though if this, if I ended up breaking it this way. Let's go to our device. Code pie, what do we have right now? Whoops wrong one, code pie. I have a quotes thing. I think I was testing, what was I testing? I don't remember now, I was testing maybe the pie portal, our portal library or the portal base library. I don't remember why I had this. I think something in the network, maybe it was ESP32 spy. See quotes. I will say it's a good example to use when you do want to test like network connectivity and stuff like that. Looks like I changed the URL to make it fail actually. Put a one there, let me undo that actually so I don't, if I do ever go back to it, let me not like spend a while figuring out why it's not working. Just try to save myself on that. Yeah, there we go. You're welcome Tim of the future. We can copy our example here for the REPL. Well, for the serial. So there we go. We got, so I have not, I have visual so it's not on REPL only. So it gives you the print out here, use the stylus to swipe slightly beyond the four edges of the visible display. We're on zero degrees and it will start printing the values whenever I touch. Touch there, you can see the, oh it's actually quite a ways off for right now. So we'll kind of just, we basically just got to get the hit the edges. You know, we kind of just run onto each edge. And as we do each one, it kind of gets better and better. So you can see now the dot is like right on my stylus, whereas before it was obviously way off. Part of that is it may be needed to figure out the size of the screen and some other stuff. So looking pretty good here now though. So I basically like to just run it around a little bit, touch each edge a couple times, you know, one or two times on each one. I'm like that. Whenever your dots lined up with your actual stylus, then you're good to go. Let me take that off. Here's the value that we got for our calibration. So again, those are the basically the minimum and the maximums. Oh, minimum and maximums for that it saw from the analog readings. One second. Here we go. I can stuff off my desk. So now we could basically take these and then put them into our, you know, our application, whatever our actual project is, we could substitute in these calibration values. And then all of a sudden our touchscreen will be working like super nicely. You know, the touches on buttons and small interface things and stuff will be pretty exact. So that's kind of nice. So then, you know, we could take something like those the other, we'll just one simple test to just prints. Orientation. Does it do anything fun? Yeah, you know what we should have is another example that's like, I guess the calibrator is kind of drag and drop, maybe like a basic even without the calibration, just a basic drag and drop. Also, I think it might be good to have a basic paint like it draws a line where you touch. It doesn't need to be super fancy. I think there's a learn guide for a project like that. And it's I'm not intending to kind of take it that far. But as an example of using the touch, it might be nice to go kind of a step above just printing the values, which is what these are. But I will say the calibrator itself, I mean, you can look in the code of the calibrator actually and get a good idea of, you know, how to do more advanced stuff with it even more advanced than the existing ones. So it did seem like everything worked fine. What I will do is I will go back to the version as written, which I think I'll just do get rollback, rollback, current file, good rollback go. Do I do it on the file? There it is. This will put it back to how it is in the repo in the PR. You need to update a different touchscreen to include the rotation argument. Oh, instead of that would be cool. Yeah, actually, that would be really cool. So instead of, so I mean, right now today, the way that you change the orientation is by the order that you pass these pins, and then the order that the calibration values are. But if there was just like orientation by the orientation equals zero, you know, or 90 or 180 or 270, then you could standardize you always pass the pins in the same order, you always pass the calibration in the same order, you put the orientation here and then it handles it internally, actually would be really nice because the code, the like, you know, boiler plate code, the code you have to do for setting up with rotations, which gets copy pasted a lot, is all of this, right? This is like, you know, 40 lines for big ol if statements, you know, it's not a mountain of code or anything, but it's kind of a lot if it did get handled internally, though, then you would basically just have one of these in your user code, which is nice. That would be a pretty nice improvement. STM PE 610 driver, yeah, that's a different kind of touchscreen. So that one does have an orientation, you're saying? STM, do I have it? Nope, STM PE 610, touch flip and rotation, if it's mirrored for some reason. I see, yeah, so this one does have a rotation. And then of course, this is also like I2C or spy, so it's not connecting the four analog pins instead it has the bus. This is just a different, different touch driver. An example over in that one as well. Did you create that one? I assume? Do we not? Yeah, cedar grove, nice, okay. Yeah, the feather wings. Yeah, I have a feather wing, I don't know, like 2.4 inches or something like that. I might have used your script on it the last time I used it as well, truthfully. Okay, so changing the name, I think would be good. We went back, we went back to stock, so let's run stock on our device. Let's also update the library as well, I don't think it should matter, but I also have no idea, like maybe the version of the library on my pi portal is old. We should test it against the current version just to be sure. Whoops, let's use the pi file. You know, let's take a small detour. What is, isn't there, there's a command you can use to build the MPY, right? How does that work? Can I just use that from the command line? Build bundles, file name prefix, repo name. Can I just run this? Repo name. What do we think the repo name is? The full name? No such remote origin. That's probably true. Hmm, did it, I mean it did something, right? What did it make? Make anything? Did they work? Bundles? MPY? Maybe they work anyway. Oh, this I will say is one of the things I don't like too much about the new version. The show in files is now open in and it's an extra context menu. Used to be inside this list. I don't, I don't like the fly out thing for it, if that worked. It looks like it. See if it's, you can add a remote. Yeah, I can add, I don't want one called origin, is the thing. Origin. I rename origin to, I try to make a match the github. The Adafruit, Adafruit, Cedar Grove, Cedar Grove, if I had a foamy guy, it would be foamy guy. I don't like to have one named origin because what I found is when I had one named origin is sometimes origin was Adafruit and sometimes origin was foamy guy and I don't want to get those mixed up. So I could add origin and then that command would probably work, but I don't necessarily want to for other reasons. Maybe I'll go look inside build tools and see if we can make that command not need origin. That would be nice. I could have an extra like optional flag or something. Okay, so we're back to running here and you can use your finger as well, but a stylus will definitely give you like the best results. But one thing you can see is like, you know, we're not, we're out of calibration now, right? Like it's the dots way far away from my finger. Depending on where it's at, it gets closer farther depending on where, but it's definitely not on it. And then what you'll see is like as I do the calibration, it gets better. Like once I hit each edge, we kind of get a better lock in on it right there. There we are. There's our values. And then what we could do is you could actually take these values and you could put them in codepie. Did I save this? Are we still testing my version? And this is definitely the other version, but I might not have saved it. Let's do it one more time to make sure. I think I might have still been testing my modified one, not cedar groves. Is this okay? It's just not updating the preview over there. That's right. Okay, let's run through that one more time here. Calibrate up, down, right, left. Get the old Konami code there, x, y, x, y. And so one thing is if we put these values in the actual calibration script itself, then it would be closer when it very first started, I think. So they're coming to it out here. And we could either, I mean, we're going to be on zero. So I'm actually just going to change zero up there. And so now the dot, if I understand right, the dot will be closer to accurate when we first begin. Oh, well, I guess no, because the min and max are still off. You have to move it to get the min and max set. Yeah, you do, you do have to move it each time. It's always going to be off when you very first start because it's min will be like the min will be zero. I assume and the max will be zero also. So it will just be messed up until you go to the actual edges. Probably if, maybe if you went to the right edge and the bottom edge first, it would get pretty close to accurate, but you can always, you always want to go to all four to get it done. Anyway, it does seem to be working good. I'll take another look over the code and see if there's any other feedback I have. I think the file name is the only thing that I noticed so far. Got copyright, right? Yeah, copyright's good. Don't want to use imports or anything. I think we passed pre-commit, right? Does this tell us if we passed pre-commit? Do we see that here? Do we have a green check? Just we'll check. Yeah, we'll get that open in browser. Oh, I probably just killed the chat. Sorry about that. Is it still, is it working after I moved it? Yeah, okay, it's good now. Don't recommend that you update the calibration code with an old value since old values might fall within the actual screen edges. Oh, like it might be outside of what's capable. Yeah, that's true. And I mean, it makes the most sense to just leave the calibrator default yet. I mean, honestly, it makes a lot more sense to just not fill it in to the calibrator, because then like really where you want to fill that in is your own project, right? Like if I have, you know, button example, something over here or like the tab layout example or something like that. Tab layout, touch test. You know, here in my other, in my actual project, this is where I would really want to put that. I don't know if the touchscreen is in this. Yeah, I think the touchscreen, well, actually, I don't think this has any touch in it. This one's just calling the functions. Touch test is the one with touch in it does initialize the touchscreen. So yeah, this would be kind of like where you're going to put your actual values. I will undo the change doesn't really matter because this one's not in the repo, of course, but rotation. Oh, we could try the other ones. Let's let's do that while we're here try the other ones like rep a lonely true ago. So we get no dot. But you know, everything else works the same. Just moved all four edges, it prints the values, we can still copy paste them out of there. You just don't get to see the the little red box as you go. And yeah, those are pretty close to the same kind of things we were getting before. Looks like it works the same both ways, which is good. Maybe do a portrait one here as well while we got everything set up. Of course, this is now sideways. I'm just going to kind of work it sideways on rotation 90. Got it all set. Then we'd be copying our values from here. Good to me. That one back. We could verify we can double check this right if we put a wrong value, it should raise an exception. Invalid rotation, I guess it doesn't maybe if it raises it caught it prints to the back here. Yeah, it doesn't raise just prints and sets to zero. Seems reasonable that the rotation to the variable and then check the rotation down here. Oh, looking pretty good to me. Centered horizontally with anchor point and anchor position. Mission has its own label. Oh, weird. Doesn't the first one here it thinks it can be undefined, but not the next one. That's weird. Looking pretty good to me. I would say the file name, I think, is the only thing I see to change when I go back to conversation. I wonder how do I do like request change? Maybe there's not a way to do that specifically. Fresh pull request details. Had review comment. Had single comment. Had a review with a comment. Does have inline. I don't see the the specific like request changes as opposed to like I also don't see approve or any of that stuff either. Approve or request changes. Let's entertain that rabbit hole for just a moment. PyCharm, I mean it's going to be like JetBrains, I guess, or IntelligentArm, GitHub, pull request, approve. There's an urge button in there. Thanks for the PR testing and review. Update the name refactor and fix the smelling errors. If I didn't notice any smelling errors. But yeah, you're welcome and thank you again for sure. Only works for GitHub. I don't know. That may be beyond the bounce. The approve and the request changes. The stuff it does have is pretty cool though. Being able to comment from here is like that gets you most of the way there. So that's pretty neat. Okay. It's fun to look at as well. I could see myself using that some of the time. Probably not for everything. Unless we could find those other two like approve and then request changes. If we could find those maybe. Probably would be more cases where I use it. But I could still see some times where I could give Lister help. Help with what? If you need help with CircuitPython, I may be able to help you. But you'll have to definitely be a little more specific. So next thing is I want to work on TileGrid, which this is going to be inside the core. I'm going to jump over to C-Line for the core because I got C-Line loaded up now and have an active license and stuff on it. So I've been using that for my core stuff. Let's go to that view we made display stuff. And we're on main and I updated before so we should be current for main. Maybe I'll make a new branch here. TileGrid contains from no track. Here we go. Branch TileGrid contains. So what I want to do here is display button. Good hub. Good Python. This library has a button that gets drawn on the screen. We could run the example actually. Let's do that. This ties right in with touch screen stuff. Same stuff we were just looking at. Let's go to this one. Extra keyword argument, line 26. We should PR that while we're here. Yeah, we should PR that. Okay, let's do that. Display button. I think I've seen that before and been like I should PR that and then didn't do it. And so now we're going to actually just take a minute. It's only going to take a minute though. It's button or display button. Display button. That's a new thing. I'm not quite used to that pop up yet. Do I have this? Why do I have stuff that's not in main? Right button. We have a PR. Oh, crowd. Are we on the wrong one? This library. This one does this to me. I need to stop using Google, I guess, to get to it. So Lady Aida made this originally and it's goes up higher in the GitHub. It goes up higher in the GitHub results and I go to it and I copy it out of date. But really it's not. We're trying to get the Aida fruit one, not the Lady Aida one. Okay. So it's you can't see it very well. A little bit better, maybe not too much, but it has a button like this. This is our display button. And the current one is not broken, so we don't have anything to PR. The API for this though, the code that you use for this button, well in fact we can look in this example right here. It has button.contains. So the way this works, you get your touch value from your touch screen driver. If the screen is being touched, then we check if button.contains P. P is the touch event that came from our touch screen driver. So if button does contain P, then we can set it to selected, selected true, which will change the color. We can also do whatever else we want, right? So, you know, we can turn on Neopixels or change colors or do whatever our application needs to do whenever the button gets pressed. This contains right here. This is kind of become like the most common touch interactive property for Circuit Python for display. So whenever we have a display widget and it's going to be touchable, you will try to use this contains that way the API is the same as the button. We use the similar API across all the different widgets. That way it's easier to know how to do stuff and a lot of the code is more easily, you know, reusable on the other widgets, right? So what I want is this contains but on tile grid. Circuit Python docs. Tile grid. Tile grid is what you use to show basically everything, any kind of object in display. Most typically like an on-disk bitmap or a regular bitmap, you would use a tile grid to show it on the display, but also things like shapes, the button itself. This button here probably extends tile grid. Nope, group, but it has a tile grid probably. Tile grid or not. Really? What does it make? Label definitely has tile grids. Great body. Rect, round rect. Okay. So these are shapes, but then the shapes, direct and round rect extend tile grid. So like basically everything that you show, every object that you can show in display. Oh, probably uses a tile grid. So if tile grid had a contains, then we could very, very easily make, you know, any kind of like image or sprite or whatever, you could make that into trying to get to just tile grid docs. I am not succeeding here, huh? You could make that thing clickable. So like you could have an on-disk bitmap and you could be able to say like, you know, does the on-disk bitmap contains the touchpoint. So you could just make an arbitrary image, an arbitrary bitmap file become a button. You know, if you want it to react to like change to the pressed state and do different stuff like that, you know, there's more to it obviously if you want that stuff. But if all you want to do is draw some fancy shape, you know, make a blinker or something on the screen and then determine when the user touches it. This would give you a super easy ability to do that. So tile grid, we're almost there finally. Maybe I pass it or all of that. There it is, display a tile grid. So this has a height and a width and it has a tile height and a tile width and it has an x and it has a y. And using all those values, it can determine the rectangle on the screen, which the tile grid occupies, which is essentially what the contains function does. It finds that rectangle, checks it, checks the touchpoint to see if it falls within that rectangle. If it does, it returns true. If it doesn't, it returns false. And that's pretty much how that works. It's very mentioned in a different channel or something. The red one here is gonna, okay, there we go. It keeps catching my eye. And it didn't go away before, but looks like we got it now. So that's what I'm trying to do, make a contains for tile grid. This way you can have touchable anything you want basically. And so that is gonna be starting out in here. Just gonna close like all the rest of the stuff. Oops, close all the stuff. Okay, and so we'll just kind of go through one at a time. So we're gonna be making a, it's not a property, it's a function kind of like, yeah, any of these pretty much that bitmap or get bitmap. I mean those, I guess, are properties. It's not quite the same as any of the others that top left. One thing we'll need to figure out is what type of object that thing is the touch. So I think it gets a tuple, print this one out. Yeah, a tuple with three values. Not sure exactly how to take a tuple in a core function, but we'll have to learn that. Are we gonna be returning, we're gonna be returning a Boolean. So let's copy this one. Tile grid contains, contains. Gonna get self. And it's gonna get, yeah, this is where it gets weird. It's gonna get the tuple, but I don't know, I guess is it gonna be an MP opt t tuple, touch tuple, touch tuple? Are there any core functions I can think of that take a tuple? If anybody knows of a function in the core that accepts an argument that is a tuple, I could find an example of that. I'll be able to look at the code and see how it works. If not, then this will be a little bit trickier, but we'll still try to figure it out. So we made an H for this. We need to make some stuff in here now. I think what I'll do is find this one, but find this one. So one thing that's different, we're not doing property get set. Yeah, I want to find, I guess, a better example. So, you know, I'm still at the stage of like, I can copy paste core code around and mash it up and get it to where I need. But obviously, like I'm not quite to the point where I can just write it out directly, what I'm going to look for is a function, a different function that I can kind of write a copy a little bit more from. Make transparent, maybe? Would that be transparent? This looks like a good one. Let's go right in here. Do one of these def contains self touch tuple. Tuple. Okay, we got a bunch of changes to the name here display. A, O, how great objects, how great object contains self in object t, touch, tuple, how great t. Object pointer self index. This was the input object was the input how it index object. We will not have this, we won't have this exactly either, but we'll want something similar that is validating that we got a tuple, and that it has at least two, let's say, items in it. And then we don't want to just return none either though, we're going to be returning the boolean is transparent. We're just doing something more like this return boolean common how display o, how grid contains touch tuple. We'll have this either, oops, current self pilot index. Yeah, we are calling the common how one, we're getting its result, and then we're returning that as the boolean grid contains grid contains. Okay, so we got this part. Obviously, we still have more to do, we should do the validation here, we need to figure out, I'm sure there's probably something we need to do to like, get this tuple out of this MP object t thing and into a thing that's more like a tuple. We'll cross that bridge in a little bit, let's fill in the shared module as well. And let's just see if we have all the like, piping infrastructure stuff in place correctly update transform and by parents. So do we need to declare one here I would think we do not though see this one does have a bunch of the getters in here and they're not listed here. Not sure what is the thing that makes it so that a function has to be in H versus C. Or maybe both like these ones I suspect are probably in both right. Yeah. I don't know why some functions I need to be an H and other ones don't like get hidden set hidden seems like don't get hidden is kind of more like what we need. Now that it matters where we put it exactly. Let's go up some of this stuff before we get to the first monster function basically on how display the tile grid contains contains self and then here's where we need also this is where it gets tricky. We can make it easier here by having these be ends x and y and we worry about taking it out of the tuple somewhere else. We're going to have to do the tuple thing somewhere. So let's call it still an MP object tuple and let's just return true and see if we even are like anywhere close to on the right track here. I'm going to leave it out of H for now. We have it here tile grids common how display a tile grid contains is what we called it here somewhere I think right hold it here passing in touch tuple. Okay so I think we have this stuff needed to at least get a build and I think return true from that function no matter what we pass it but where are we at here. Okay let's see if you did any of that correct. We actually get a build and then we do get a build if it actually has a new function that we can call and if it actually returns true then we are like got the easy part out of the way. Still trying to think of a thing in the core that would accept a tuple. Is there something in vector IO that takes a tuple? There's points in polygon that's a list which is kind of like a tuple. Okay we did actually get a build. Let's go to bootloader mode copy that in. Um let's get even simpler example code I think for now. Camera died again. I don't know why the camera is all crazy but it stays up for us. I don't know gotta get a new camera apparently this one's on the fritz so this has a tile grid that doesn't do as much just tile grid here and it's display sized so let's do printer tile grid and a zero zero and see what that gets us no contains. Okay so we probably forgot at least one thing I think um yeah down here there's more right down here there's like yeah this contains declared I'm probably not maybe though 504 contains object the tile grid contains object undeclared here not in a function display objects display a tile grid object contains should this be contains object grid object get transpose y this one shouldn't be palette okay come back to bootloader didn't print anything but I think that means that it didn't crash uh probably just printed before TO connected so we didn't get to see it we redo nice so now we have contains inside of dirt dirt tile grid and we have contains true here so it did return true to us so we successfully added a function that always returns true uh which doesn't seem like a lot but actually obviously as you saw it's a fair amount of boilerplate code to get that in so now our tuple um yeah we were looking at the docks and find something that takes a tuple this one takes x y is two different values it does take points which is a list of tuples let's roll through here a little bit and see if we find any two stuff in box uh this is Blinka I do this I don't know the docs confuse me sometimes I get lost in here see this is Blinka but it's I think the doc should do a better job of separating okay so set item on tile grid actually can take a tuple of int uh x y maybe we can find the code for that of x y value yeah subscript self in here we go comes in as np object t so I don't think we care about slicing in our use case this is because it's a subscript thing which is the square brackets and of course in the square brackets it could have the colon for a slice for our function it's not square brackets it's a function so I don't think we care about slice in the same way I think we can get by without that this part I think is relevant to us though so it's making an int x zero int y zero it's checking if index is a small int i.e if it is a single number and not a tuple if that is the case then it sets x y based on dividing and modulating the value that came in else right here this is what it does if it is not an int which in this case means that it is a tuple I'm pretty sure so here it goes items it goes get array fixed in and then it's able to get those items out of there so this is pretty much what we want to be able to do kind of close enough that I think we'll be able to reuse it so let's grab that let's go back to our contains so we're basically gonna put this stuff here do we want to call it items yeah let's just keep it called items well let's change it touch tuple items let's be super I'm always like sometimes I'm very verbose but I rather be verbose than vague touch tuple items I'd rather this have its own name so this is here and we actually have three coming in from the touchscreen but we the third one is pressure like how hard you're pressing and we don't use it for anything so I think I'm inclined to just keep this on two and see if it raises an error so our items was this touch tuple was this okay so then x and y these are our x and y here so let's print them I don't remember how to do then I gotta use I gotta use the core more I'm too good enough in here to remember the way print works I think I think is I would have ended up removing prints from a bunch of those is there a guide we should have this in a guide I don't know be would it be it's not building circuit um it's so simple and I just don't remember it and I don't know a good place to look it up anybody happens to know the way that you print inside the core definitely be super appreciated we don't want to break point like mp mp print something you gotta give it arg I don't I don't know the right stuff kind of a lot of stuff just to be able to print mp print f something like this print f print mp yeah print f mp print f thank you yeah what is optin args though I see this is where this came from maybe but I think we go just here maybe x I'm just gonna print two of course I also don't know need new lines like this thank you Isaac by the way x y like this see we actually have it close to right no no return statement definitely gonna need that c is not quite as forgiving about no semicolons as python python doesn't need semicolons what is this now balance earlier why undeclared uh yeah so we need to get x and y them like this okay fingers crossed nope already died okay items though we just changed that out probably uh here items this one yep getting closer can feel it well accidentally pressed r hopefully doesn't bother the build if you press r while it's going okay we actually got a build means we're at least like half to a third of the way there I would say copy that to our device mp print f mp print f I need to just like sit down one day and do a bunch of just adding prints to the core in various places to explore things and just like a day of practicing I bet you will get me to remember the the function so again here it's not doesn't show right away I think is it prints before to connects but if we control c control d we do have contains we have contains true we have some like extra new lines which unfortunately I think this is where our x and y should be and they are not there obviously so we did something we did something wrong I think it's can't be added to a string like this or something I don't know these are not showing up um right without the new line see if it's gonna get it any better we're definitely gonna want to format it into a string just using this wrong ah come on sent d and the value after it oh what oh fun house the wrong terminal comma so picky c code there's a comma here or there no semicolon oh sorry okay back to bootloader copy it on and we check again disconnected connected breakout d there we go zero zero and then what did we pass it did we pass it zero zero not the right file portal boot we did so if we pass it something else and let's give it a third uh I don't know something goodness gracious so I guess we go three then even though we're not going to use the third one and we just get zero and one and we don't do anything with two percent d and then comma and the variable so and I guess this is like d for decimal or something did digital digit number I think this is for number I don't know what the d actually stands for but I think if we had like a float maybe we would do something different or you know if we wanted to be hex or something there's another way we could do this as well we need more practice with it okay that was our old crash boom there we go we have contains we called it we got 1010 out of it uh let's make sure it works if we give it two different numbers and 70 good to go we ignored the third value um let's let's initialize the touchscreen well as the touchscreen and then um pass it p like pass it the thing we got from the touchscreen here like touch point this thing initialize this this is where we could put our calibration if we had it from the other one size uh I'm gonna do display display dot width display dot height oh you know what uh if we use this code before this would have been different because I think that's the pipe portal regular not the uh titano size anyway we're changing it now touchscreen so inside our main loop we're going to do this here and then we can say if p tile grid dot contains p so it's still just returning true we haven't actually filled in the functionality yet but what no it's not oh we didn't import it we didn't import it right that makes sense it's like we just used it okay yeah here we go 1070 and then if I touch though I touch oh but I don't did I didn't print anything did I a little print inside I guess print in the core yeah that's working so this is printing you can turn this off the x and y though those are from the core there's our x and y values in the core they're matching where our touches are at on the screen like zero zero is up here 480 320 is down here something like that or 360 I don't know the I don't know the right size something like that is down there though so that is working we passed at our touch event it's getting the first two values we're getting pretty close here so next let's do let's see so we want to we basically we were gonna we should validate that validate something right we should validate that we have the right number of arguments inside our tuple um because if we give it zero ends up with a type error how do we can we catch a type error in c code I guess this comes from here probably oh actually I passed a I passed two values instead of one tuple expected to be length three but it got length two you know what's funny is how this is like almost the exact opposite of what it said here and really the problem was just missing the extra parentheses um value error yeah we should really try to catch this on the c side um no idea how to do that though the array fixed in as these are clickable I can just open them up maybe it's it's because of this so let's look bitmap tools in it that inside of here yeah shared bindings I haven't even tried to catch here imp raise value error oh actually maybe extract tuple and that seems actually kind of like what we want object is object raise the value error I'll stew this stuff third bindings bitmap 159 can we see inside of this where does this one come from though here hi obj I see like how what is it what does it rate or like does it have the actual code in here that raises the exception we saw no oh yeah the list has wrong length it's calling get array hmm does anybody know how we uh accept an error from c code the possible to accept an error basically I want to probably accept the error that ended up getting raised this one here I think I want to accept this in c and change the message to say needs to have three values in the tuple touch tuple must contain three values although maybe it's better to just let it use the generic one because then it's not an extra string to translate maybe we just leave it bindings SSL SSL socket or it must be greater than zero times I see where it uses it it's not doing any checking maybe that's okay I mean I guess that's the same error that you would get from any of the rest of those places that we looked at right um if you passed in a thing that had not two to this it would give you the same error as what we're seeing I think same thing here if you passed in a three tuple or a four tuple or something okay but yeah let's go forward with it for now and somebody does know better they can leave you know a note on the review kind of pointed me towards the right way to handle it um do we have our x and y what we want to do is not just print them although printing them is helpful to make sure they are coming through and actually correct and stuff I think maybe we'll change this to x and y so x y here instead of passing it through as a tuple there we'll just pass it through as the numbers and that way um we don't have to worry about converting it on this side we'll have a uint 16 t x and a uint 16 t y okay so we have our x and y inside of here we're gonna return whatever this return so here we just need the actual logic basically um and so our logic is pretty much a bunch of ifs and ands and things with the x that came in is greater than self x and the x that came in okay actually let's make some other variables maybe event 16 t let's call this right edge right edge this is gonna be self dot no self arrow x uh plus parentheses self width which is in tiles times self tile width which is in pixels multiply the width and tiles times the width of each tile in pixels that gives you the entire width add that to the x that gives you the pixel value of the right edge bottom edge bottom edge and of course the left and the top those are the same as self x and self y those are actually easy bottom edge we go y plus height height okay so if x is greater than or equal to the left edge and x is less than or equal to the right edge right edge and y is greater than or equal to self dot y and y less than or equal to bottom edge return true else return false yes i know we could probably just return this uh expression instead of an if else i'm gonna do it this way for now though okay uh does it build probably not too many arguments ah we must not have changed it everywhere third bindings tile grid c third bindings tile grid h actually have x and y like this now all right how about now nope uh okay uh unused variable seeming colons that get you every time tile grid has no member height you sure pretty sure it does python land it does this where's the tile grid but has no member height does that mean it found width to go in order unknown type yeah probably huh right i guess i did okay maybe that fixes it you know it was actually the problem same thing has no member width does that mean it does have tile width and tile height width and tiles needs to be width and tiles okay didn't crush yet go into bootloader mode i'm not gonna jinx it oh look at that that's right right there copy it on right there uh yeah so it's still failing because we have that code giving it the wrong size thing this one that back uh we're not printing this we're gonna print this so 1070 it said yes contains true which is accurate in this case because uh well so in this case the height and width in tiles are both one it's a one by one tile grid but then the tile width and the tile height are basically the size of the bitmap which in this case also match the size of the display so it's 480 by 320 or 360 maybe i don't remember off the top of my head it's the size of the display though so anything over zero and less than that 480 360 320 whatever it is that should be contains true for this one and then anything outside of that would be contains false so let's see if it prints true when we touch it that's kind of like moment of truth here the the whole screen should be true so it's not that interesting but fingers crossed nice okay we got a lot of trues and i think we don't have a super easy way to get a false we could make one like this print tile grid contains negative one negative one something i think you could give it not an interior probably would be okay even nope oh tuple yeah there you go so that one came false because it's outside for the zero one it would still be false and if it was zero zero it would be true so let's make a slightly more practical example um on this bitmap this is on this bitmap is really more like how i envision this being useful um basically it means we can have on this bitmap become a button essentially this bitmap future method we should come back and get rid of the non future method here throw that on the list of stuff to do and keep the touch screen as an initialization initialization display also yeah probably crashes because we don't have purple i guess yeah purple is a picture of flowers which is the size of the screen on the regular pipe portal i think it's actually smaller than the size of the screen on the titano though how's it going johnny thanks for hanging out today yeah see smaller than the actual screen so now do we get our correct answers from this uh let's go p equals ts touchpoint if p if a old grid tile grid contains whoa oh the uh oh come on what are we doing so the code completion doesn't know about it because it's not in the stubs that i currently have if it contains p print uh touching flowers else else outside all right i think we got it i think we got bugs i'm gonna touch inside first okay okay but we got one outside at the very end there which is interesting surprised by that actually let's print this too i don't know maybe my finger touched it like down on the corner or something we're gonna touch outside outside look at that side outside outside outside outside outside boom touching look at that it's pretty nice down here outside touching good i'm pretty good to me but let's move this in a bit and make sure that if we're less than it it'll work uh yeah thank you Isaac uh let's go x x let's just say like 50 we should have room for that i think that too yeah inside i'm touching touching up boom outside nice left side there uh okay clean this up run pre-commit and see if anybody has thoughts on like what kind of validation should be occurring here if anything and basically i think get rid of all this stuff for now so i'm gonna change a bunch of studies that changed a lot of stuff i'm gonna do that that's my format i don't really want to want to change any code that's not part of what i'm adding specifically so tains this should probably have some text like returns true if first two values in touch tuple represent and x y coordinate coordinate inside the tile grid rectangle bounds so i try to stop running pre-commit all because it changes a bunch of other files although i think dan said make a pr with those maybe we should do that this weekend um i think i did pre-commit install though pre-commit install so it should run when i try to make the commit so if we go commit yeah see here's all the stuff i need to clone a new copy again get back to not having changes that aren't in main so here's the actual three files i changed everything else is all other stuff that pre-commit changed a while ago at the hiccups now i didn't do any of this stuff my three files are there new section here for contains maybe got too much spacing at the bottom of it i see here we go just one line and then right into the comment for the next one let's cut some of that back down looks pretty good looks good there as well we got the one line spacing above and below this one we gave it a new line but i think that's fine that's like flip and transpose kind of our one common idea and this one is not part of that idea so you kind of like the new line there to just draw difference between those other functions uh okay tile grid that contains failed and then i but then this will say the pre-commit the formatting failed but the formatting will run the format and change it and so i think we can actually just try again and it should succeed the second time at least on formatting yeah so this time we got successful it could fail for another reason something other than form formatting um but at least it should not fail for formatting the second time if it did the first time but that committed so we can go push i'm gonna go yep two foamy guy tile grid contains this is our actual commit with our actual changes the rest of the stuff is all just stuff that hasn't been updated on my my fork since last time i used it basically the push two foamy guy tile grid contains yep push it i'm gonna make the pr for it and then we'll probably wrap it up there uh like that's a pretty good natural place to wrap it up we got our whole function in it works it functions correctly it seems like uh ready to get feedback on it if there's anything we can do better like on the shared binding side or anywhere really um the functionality is there this is pretty much what i had imagined this is what i was aiming for i'm pretty happy with it oh oh that was probably loud sorry suddenly bonk the microphone we'll make the pr for it and then i'll wrap up after that if anybody has questions or comments or anything else you'd like to say or share uh or ask before i get going for the evening now is the time you can uh put those in the discord chat or the youtube chat uh sorry if there's folks watching on twitch i'm not actually i don't have the twitch chat pulled up so if you are over there and you mentioned something i apologize i didn't see it you want to join us on discord or in the youtube chat for now i'll be able to see that message a grid contains function yeah for sure uh good night paul hope you're uh hope you're getting to be feeling better except uh a touch tuple yeah for sure thanks for watching anthony uh let's see function that accepts a touch tuple from ate a fruit touch screen library or similar or false based on whether the touch point is inside the rectangular rectangular bounds of this childhood pretty good to me uh herald herald herald finch are you herald finch your name will play on herald finch thanks for watching either way and hanging out in the chat here your name is herald finch though maybe on to you you have no idea what i'm talking about then i'm not on to you thanks it was pretty cool yeah i appreciate it isik thanks for hanging out uh seagrover excellent change good to have contains in there for consistency yeah i think it'll be nice close enough fins okay probably no probably then not you're probably not named after the reference that i'm thinking of there's a character in a television show uh called herald finch and that's what i was thinking maybe you might be named after but it sounds like probably not fins okay fins like the fish fins okay i got you herald fins thanks for hanging out i don't recall seeing your name in the chat before you may have been by and i could have forgotten about it if so i apologize but either way thanks for hanging out today it was nice to have you i will create this one create it right there and yeah i think we'll wrap it up here so for folks that don't know i also stream on saturday mornings um so that's uh in about oh i always do the math every week i should bookmark a page that counts down or something ten a.m central time uh on saturday morning which is um what six hours to midnight and then 10 hours after that so about 16 hours from now is that right six hours to midnight and then 10 hours after that yeah about 16 hours from now a little bit less 10 minutes less than 16 hours from now i'll be back streaming again and um you can watch me i'll be on my own twitch account not the we're on the ate a fruit one here if you're interested in watching what you can do is either follow me on twitch foamy guy underscore twitch is my name there to get notifications or if you join the discord in the live broadcast chat the one that's right below me in the stream here i will uh on saturday mornings i always put my links uh in that chat right when i'm getting started so if you watch that chat on saturday mornings um at least it's morning in my time zone again 10 a.m central time then the links will show up in there and you can uh follow along there as well i don't know exactly what we'll be working on tomorrow but i will find something and then we'll be doing that in the morning so thank you again to everybody um i'll mention again you know what we've been working on is circuit python if you're interested in getting involved uh head over to the discord join us there you are interested in supporting the project um without getting involved in development what you can do is purchase hardware from ate a fruit again that's ate a fruit dot com they are the ones that are paying myself and all the folks who work on the circuit python project uh as as a job to get paid for it so um huge thanks to ate a fruit and huge thanks to everyone who purchases hardware there i will see you all tomorrow back from my stream uh and uh otherwise i'll catch you next time whenever it may be thanks for watching