 All right. Hello everyone. We are back for the deep dive and it is ready to go I think Looks like I do see sound inside OBS So I think we're probably good on that, but if anybody is there already on the twitch or YouTube I don't mind. Please give me a quick sound check in the chat if you would Let's What we're doing that let's pause this preview How's it going Tammy and Dexter? Thank you Let me pause this one enable disabled. Let's do that and let me put the chats in front here All good on the sound. Thank you. Appreciate the heads up there Okay, so Yes, welcome welcome back to me. I was off last week. Thank you again to Scott for filling in on a deep dive I am back now though and getting back into the swing of things As an introduction for folks that might be new. My name is Tim and I go by Fumiguy on GitHub and discord This is the deep dive stream that occurs every Friday evening or at least most Friday evenings at this time We are taking a deep dive into circuit Python We're either going to be working with circuit Python core or circuit Python projects or libraries relatively advanced, you know level stuff It's not necessarily a beginner tutorial or anything like that. We're really You know as they say diving deep getting into the weeds Playing around with some of the more advanced stuff If you're interested in circuit Python check out circuit python org This is the website where you can learn more if you don't know what I'm talking about I'm a very very, you know brief high-level Overview version is we have this version of circuit Python. It runs on microcontrollers Which are basically just these tiny computers. There's a bunch of pictures of them here on the downloads page We're running Python code on these devices that can interact with other Components connected to them. So some of them have lights some of them have, you know Keyboard switches some of them just have a bunch of pins for you to connect whatever you want We're writing Python code that runs on these devices and interacts with all those pins and all the hardware that is connected up with it In circuit Python org is where you can learn more and Lastly, I will say thank you to Adafruit and if anybody wants to help Support the circuit Python project one of the ways you can do that is by purchasing hardware from Adafruit So Adafruit is a hardware and software company based out of New York They are the ones that are paying the folks who work on the project full-time and some folks like me who work on the project part-time They're paying us to work on circuit Python in the libraries and the documentation and the projects and all these things around it So thank you to them and thank you to anyone who wants to purchase hardware from them for helping support Them and those of us that work on the project So getting into today a brief housekeeping note I'll be a little bit shorter than normal today. Usually we go around two hours sometimes a little bit longer than two hours Today, I'll be cutting it off a little bit short probably about one hour 40 or one hour 45 something like that Got a head out to Dinner with my wife and family this evening. So I'll be doing that will be cutting out just a little bit earlier than normal for that So that's just a heads up to let you know that we'll be ending a little bit earlier than Sometimes we have in the past In terms of what we are actually working on today I want to play around with some stuff that I've been tinkering with lately. That's around memory Measurement I have this project here. This one has a version of one of the things I've been working on This one will Well, what this one does is it it clones a library a circuit python library It will clone it it will build the MPY files and then it will print out the size of the MPY files As well as the size of the strings contained within those files So let me run it here right now. We have it pointed at this BLE I barbecue Get this is the repo for this particular library. So I'll run it pointed at that one just to give you a look at what this does So and it does all this when you run it So it's going to clone that project It is going to build the bundles for it which bundles meaning the library bundles the MPY bundles It's going to you know compile it to MPY It's going to spit out this stuff into a zip file or I think it's actually just a folder that has a zip in the name I don't think it gets zipped yet it Bundles checking s3 I don't know what this one is doing. This is something inside of Circuit python build tools, I guess Um, it's looking at the s3 for this Oh, okay. Okay for getting MPY cross. I see this is downloading MPY cross. I guess Um Says it zips it. I don't know if it actually does or not. I'm getting folders that aren't zipped It well, yeah, I guess maybe it is zipping it But I'm just using the ones that aren't somewhere down here towards the very end after all the rest of the stuff is done Right here. We have the bits that I added to this which are MPY file size. It prints this out in bytes It prints out strings output size. So it runs the unix string commands, which I think it was dan Maybe danh Who brought that up during the a recent circuit python weekly meeting when we were talking about memory size of libraries in the weeds So I was not familiar with this command, but this is a unix command. You can just run it on a file and it will tell you Um, well, it will output all the strings that are in The binary file. So like let's go to the terminal. I'll show you what this does Uh, we can come back out of here Okay, we can go back into there We can go into, uh This one inside there also Inside there Okay, we got that mpy file We can say strings on this mpy file And it outputs all of these so these are all of the I don't know utf 8 or or ascii or something these are all the strings I guess that are in this binary File some of the data in this file is not like legible strings But some of the stuff in this file is legible strings In our case, this is things like variable names like actual literal strings in the code It looks like comments and stuff like this. Like I think there's a comment that has the repo url So we're seeing that there All sorts of names of different stuff just like all these different strings are in there So that's the command that this other one is running. It gets all these strings It writes those out to a file tells you how big that file of all the strings are and then it gives you the percentage So in this case, it's saying In this ibbq mpy file It's 1899 bytes total. There's 995 of strings And that's a 52.4 percent You know, the strings occupy 52.4 percent of the mpy file So I don't know what numbers are good. What numbers are high low bad good any of that stuff yet But eventually this will hopefully help us say, you know, like, hey Maybe this percentage is too high for this library Maybe we need to make a pass through and try to like minimize some of the variable names if we can Avoid repetition of the library name inside the variable strings You know, maybe other things to try to reduce the amount of string content in that file because these This essentially will consume memory when it gets imported on the device So ultimately that is what we are trying to measure here is how much memory is a given library going to use on the device So You know, this is kind of a proxy for it. This is the mpy file size, which is not exactly the amount of memory it's going to use Um, but it's a good start. It's it's it's letting us know something that's going to be generally kind of Tied to the memory size Um, how's it going paul? Happy friday to you as well. Thank you Uh, thank you see grover and dexter um On the note about the sound that echoey, I don't know if I can Anything like about that. Let me just double check that we have the right microphone Uh, and I do have this one is muted that's on Just be condenser. I think I got the right microphone hooked up if it's unbearable. Let me know I can try to tinker with some more stuff But if not, we'll try to power through Um, so that's what I've done so far is you basically can just choose whatever library you want It will do all that building and and it will kind of run this little report on The memory size so we could switch it up to this one run it again and it will output the stats for This si what is this 11 45? This one comes in a little bit smaller. It's only 46 percent of strings on this one 76 6 bytes um The next step Is to move this into actions, which I have actually done already on I have my own copy of this repo Uh, and I set up a new actions, um branch on that repo that adds essentially this This process to the actions so that we'll get printed in the output Um, so let me pull up that and then we will look at what I want to do next. So what I'm going to work on on this Stream So here is actually the output from one of the branches. Uh, so this is in my fork I think it's on a specific branch. I set up a new action called check sizes And it basically runs that little utility that I just showed you it does all the same stuff Although in this case under build assets, it's actually already building the np y files So my stuff doesn't have to to do it in that case. It's already actually built We can just run the check on it here. Uh, and so that prints out this information right here Um next thing I want to do though, which is going to be a much harder bridge to cross is I want to do some On device testing I want to like import this library on the device And see how much Memory it takes up by using gc dot mem, you know mem alloc or mem free Before and after we import it and then get the difference to find out How many bytes of memory that it actually consumed on a real device when it got imported You know, ultimately I want to try to figure out a way to get that information into actions Which is certainly a complicated problem, right because we need a device somewhere plugged into a computer that actions can kind of send this You know job out to to say hey, uh, here's this np y file. Please load it on the device Check how much memory it used and then return that value back to me. Um You know, that's a bit of a magic black box component that I don't have a super clear idea of the whole way to do that I have a couple of starting ideas. Um Brainstorming like ways it might work, but you know, that's kind of the the next piece to this is like Maybe we figure out a way to do on-device testing inside the actions Um, you know utilizing devices plugged into volunteers computers So uh in my mind the way this works is you would plug, you know If you want to be helping us in this way You would plug in a device to your computer to a computer that you just can leave running Either a pc or a raspberry pi or something like that You plug in a device to that computer and then you run a script that will kind of like listen for New jobs to come in from the central server It'll send out a job to to those client devices. The job will say, you know, try out the simpy y file Tell me the size that you got back Your local computer that raspberry pi or whatever it is it will do that check It'll send the size back to the central server Central server will then send the size back to action. So um, this is kind of a complex thing but that's the the You know far off goal, that's the the the end goal I want to try to get to is like Start us working on on-device testing in an automated way as part of the action. So First step for that is let's do the memory test specifically because I don't have the code for that yet So that's what I'm going to work on right now. I have this code that's building the mp y's and measuring the mp y size The next thing I want to do is Just load an mp y on a device and Run some commands in the repl figure out how much memory it takes up on the device and then print that out Uh, so this will be on device ram check Yep, we could go ahead and add that Uh So we need serial because we need to connect to the repl python serial example Okay Why don't we let's go to a search engine that actually Works introduction pi serial Open the first serial port real port They're very old does this matter Yeah, this is pretty good So first thing is let's just get some repl action going here We need to be able to talk from this script into the repl on the device. I have a device plugged in I don't know my camera setup today. It was giving me trouble earlier Um, so there's nothing really to see anyway. I'm just going to be interacting with the device over the uh You know through the serial terminal anyway, so you can see my terminal. There's really nothing to see on the device Uh for today, so we will be uh, a cm zero probably ls slash dev tty a star Oh such file dead of dead of let's do dev like that cm zero So right now this will just go in a string eventually we'll figure out how to target it how to make sure it's a circuit python device all that stuff Um for now, this should be good though Connect to it, uh print the name. I yeah, we can do that. It doesn't really matter. We need to figure out how to send, uh control c Python serial Send control c there should be like a code or something that we can send, um like an escape sequence or Kind of binary representation or key event representation. How do we do that? Let's see let's send Yes, something like this This equals control c for some reason. Oh my goodness really We do that and then uh, we want to write afterwards. I mean read serial dot read Uh Read line maybe See while true Serial dot let's uh say red equals Serial dot read line If red is not none uh print red So Control c we probably will need like enter um We'll probably need enter Is it gonna be like slash r slash n both? Character three perhaps Yeah, could be I'm not familiar with what this code This is ascii or I don't know how that works exactly with what this relates to. I remember doing this from android though I knew this code existed because I sent it from an android app before um So let's try pressing control c twice because I like to spam Control c twice when I go into repl I think Second one does something I I think it just asks you to press any key or something the second one Does that something like that? I'm not sure the exact way it works, but Uh, let's also just write uh print Hello world See if we get that far And then we're gonna read so We should read those lines back out Um, I don't know this might print the device, you know version or whatever a bunch of that boot info I don't know how exactly that's gonna work, but let's give it a try Unicode streams are not kind of supported. Please encode the bytes Do you think this means something more than this or uh, no, okay? Yeah, uh Yeah, okay, uh, we got this I don't these didn't I don't think these worked, right? Maybe we don't need those Let's do space We didn't get the print hello world I noticed Um So we also I guess what we should do is like try accept keyboard Interrupt this close Actually pass Close out here that make a difference I feel like this catches more cases, but I'm not positive. Ah, okay, but the thing is we're still in We're still in uh I mean if that worked last time then we're still in the repel We never went back. So we actually need to find control d also I guess is maybe four instead of three Ascii value for control c is zero x three Control a is one b is two and so on. Okay, so it is probably four for d So maybe we should actually do uh control d first Then control c That way it'll work even if you're already in the repel Stop and rerun Oh, we still didn't get it though. Hmm Let's put also Print closing. Let's make sure this is actually working Okay, that does work. We are not getting any There let's take a look with uh to and see what's going on Yeah, okay. We're just still in the repel So our control d didn't work Um Yeah Disconnect so Okay, that time it worked Got a bunch of this stuff And then uh, we did get We did get into repel We printed this Hmm. I wonder if uh, we need to read Maybe we need to read after we do this. Maybe we're like if we write things over and over it's like Not executing the next one. So I think this doesn't return might be our next problem Yes, if there's nothing to read this doesn't work Has data or something we need a way to know We need a way to know if there's actual data It goes by a timeout probably like this Timeout uh, is this seconds milliseconds? 1,000 maybe 500 maybe 0.5 Now this prints too much. We don't want these Read with oh, you can also read with timeout Is it in read line two or only when you initialize? Oh, I can't click this. I think it didn't send cheer up, sir. I'm pretty cheerful um Check the input buffer for content make sure to read in binary I don't know how to check the input buffer for content Um I think are we not sending You think do we think the writes have the new line? Automatically it sure doesn't seem like it right because we're not getting hello world to be printed but But these we didn't well, but you don't have to push enter with these right you just press control c or control d There is no enter. Okay, so we do probably need I guess at least Maybe new line or do we possibly need new line and courage return We got something different. Um Oh the space. I think the space screwed us this one here. We probably don't even want this. Do we There we go. Okay Okay Remember growing you set the timeout nice. Okay Okay So we we do have binary strings. We could convert these back if we wanted I think the bees are fine for now um So now we don't want to print we want to Do an import dynamically Um So I think I've tried this the other day I don't remember what it was. I think it's like Is it like uh, it's like Uh module equals import And then string name here Uh, so we would say like Adafruit si 1145 No module. Did I just call it wrong? Maybe or it's not installed on my device It's not installed on my device. So let's do mpr one two one for right now mpr one two one Yes, okay, so now What this In here We want to Put this as one of these We want to go actually import gc. We want to go Before equals gc dot mim I don't remember is it underscore? MIM alloc this Then do the import then go print If My this is like super meta. I don't want to do that. Let's just do uh I was thinking I was gonna replace this Let's do this module name This one is an f string inside the script isn't it? So the thing is here where I'm like writing python code in a string inside a python Script and I don't think we're gonna have some like inception code problems of String Substitutions inside string substitutions. I don't think that will give us trouble this way though. We should be all right So we go like this Uh diff is gonna be before No, it's gonna be um the new one after No, it's gonna be before before minus gc.mim alloc Go get the before value import the module Print the before value minus the after value Check serial in waiting to see if there's anything to read Serial in waiting. Oops wrong one. I don't know why I keep clicking back to this I'll keep this eventually. I'll make a check here for just an empty line and skip printing it if it's an empty line I guess maybe this will work for that. I'm not sure I'll do that more explicitly later on though If we are getting those empty lines getting printed Okay So we don't really want to run hello hello world instead. We want to go serial dot right Yes, we should call this b it's string And then We go core memory test script replace Remember we need to do this With the actual module name which right now I'm just gonna hard code, but eventually we're gonna base it on something uh man line argument, uh I don't know input variable of some kind. So for right now though, we'll just Put this one in And so one thing I don't know is like writing it with the multi line thing. Is that gonna work? I don't actually know We'll find out Um See what it does I do need to disconnect this It's like the object That didn't work I guess because these aren't bytes There we go. Okay Ah, yeah, no, it doesn't look like That worked right Looks like we got all that on one line I guess we will actually need Like this Theoretically this is already there right dash in because we're on the the next line. Maybe we just need these Once we have actual literal new lines But not on this one this one we would I think But that's not the right spot for it There we go. Is that a reasonable amount? I don't actually know it's negative which seems odd to me I do that wrong actually. So memory alloc. Ah, yeah, okay. I was thinking memory free Memory alloc. So really we we do want after We we either need to use memory free or we need to do this this way minus before There we go 66 40 So is that a reasonable Answer does that seem The ballpark of correct Let's go back here. Let's go back to rebel. Let's go import gc Before equals gc mem alloc, and I'll do the import the regular way That's the other thing. I don't know if that weird way we're doing the import like this as a string I don't know if that I don't know if that's uh problematic or not Although We don't really need to do that. Do we we can just use import? Yeah, yeah, we can just do that. So we're because we're already substituting into this We don't need it to be more dynamic. Okay, let's keep trusting it though. So import And then 6576 pretty close. It wasn't the exact same, but I think it's like Not a simple science. I think there's a lot going on That can change the amount 64 but it's pretty close 6576 we're within you know 60 bytes something like that Realistically probably the way you do the import could matter too, right because like That variable name module was in ram, I guess too Maybe some other stuff for being able to assign it Let's Kind of weird, but let's print json that way our Our next level script here the script we're writing that way it's going to be able to Read it in a structured way without Us just having to like parse it and Look for our own random Thing in there. So let's go I guess I guess well, no, okay. Yeah, we import these first then we get our before. Yeah Port size ram size Oh wait, no, that's right How did it not print? What the number you get include the imports done in the program uh It would except for that we are checking Memory allocated After we've already done this And then subtracting it after we only do the one thing. So this should give us the difference between whatever Essentially these are consuming memory, but we're not counting them since we are importing them first Then taking our first reading after they're in memory and then subtracting the final value From our first reading I think we're I think we're filtering them out because we're not getting our before value until after we do them But I could be wrong too But I think that's the way it's working Um, I don't know what these ellipses are These are definitely weird. It's like it tried to print something but For some reason the thing it printed is ellipsis I'm missing a parentheses missing a parentheses Okay, there we go. Now when we read Let's say print read try data Output output equals json.loads Read except Uh Value I don't know what it throws. That's probably it, right? Just don't do anything if RAM size in output Print output RAM size There we go. So now we have this as a number Inside of our outer script here as a variable inside our pc python script We generated that number on the device, but we now have it as a int number inside of this python script running on my pc um So now we would send that back to the central server the central server would send that over to get hub actions get hub actions would be able to say This branch of the code uses up this much ram When you import it on a device In this one case at least because as we saw it's not Not exactly the same from time to time and there's lots of stuff that could be making a difference But this gives us at least a baseline to start measuring something that we can't or don't currently measure today Which is really what we're trying to do Probably close this um So really we don't need to print a whole lot of this stuff. Um Oh, we can't do that. Can we? Now we are gonna like Functionize this so we're gonna say def Get ram size module name device path So I think we should probably make this actually a little bit more If it's verbose it will still print so we could still use it to read other stuff and see what's going on In the final version though, we don't really need to print anything In fact, we don't even really want to Probably print this we'd say like if verbose print that Either way Return output Ram size and then if not any of this return I guess return none will happen by default, right? So do we actually need to read here? Can we just Not do that instead or Of course, we're only we're like halfway through rewriting it. Maybe I also have Other bugs. Yeah Oh, uh, this is still a while true So we we would not while true instead. I guess Let's go once I don't know if that's gonna work if we can This weren't We're required rather No, but those ones back to commented What's driver verbose true here? I expected in den That's weird Oh That doesn't sound right 016 that's way smaller than what we saw before though Hmm That's pretty close Is any of this stuff In any way asynchronous should we be sprinkling like Time.sleeps or anything or like should we try gc to collect Before the first measurement I'm making a difference 560 And I don't know about Those weird ones 4001 and the negative one. I don't know What could have caused that Hmm something is not getting returned right Yeah This needs to return actually not just break We also don't really need to print it if we're gonna return it because we'll print it afterwards There we go Okay Don't know about the negative or the 4001 those ones are definitely strange But I think we got it now for this bit of it so Now we have a thing where Some other program can Import this function pass it a library name Pass it a device It will then get the ram size back as long as this device is connected. I'm sure it will either Loop infinite or do something bad if this device wasn't connected. We'll fix that up later on Put some kind of time out where like it'll try for a couple seconds if it doesn't see a real device It'll just give up maybe Um Oh no, we got another one of those So weird We call collect before we do the next one maybe as well They're actually gonna matter It would be uh after this I guess The other thing I'm wondering is like is this asynchronous at all should we be Like is there any chance we should put just like timed out sleep, you know one tenth of a second Just to make sure it's like done doing whatever it does. I don't know if that's Happening sequentially this one. We got the 4 000 again though Oh, we always get the 4 000 now. Uh-oh Oh, I don't know about that All right different library That's like an exact power too, isn't it? That's awfully awfully suspicious Is it I don't know maybe that makes sense All right different library NTP That's definitely a little bit too coincidental I think Maybe it's getting rounded to the next like Next lowest page size or whatever That's so weird Let's just sprinkle a few of these in See if it is anything like Just weird asynchronous. It's not done yet or something A different number, but now it's still consistent from time to time, but it's different number It is odd That kind of makes it seem like time is taking up some or Maybe this code or something um, I mean, I guess it's possible that collect here is Like freeing it or something right? I don't know This seems like this one is kind of the culprit though Gets more consistent with Sleeps put into it Hmm Inconsistency is a good thing. I guess as long as we're getting the right answer Good to get the same answer over and over Do we think it's like different for different ones of these? Strange Oh, no Oh, no We're not using this Oh, that was pretty silly Uh, good night to shibu. Thanks for hanging out for a bit. How long has this been broken? That's interesting. Go back and forth back and forth each time. Okay Gotta actually do different libraries if you want to see different results turns out That does make some sense though. So here Let's try another one like logging That is weird how it's it's back and forth back and forth now. It's like every other run Consumes an extra What is the difference? Do you think the difference is the same no matter what file we use or what import I mean? So four five one two Six three five two if I just keep running it we'll get those same things over and over again X three five two minus four one five two 2200 NTP 1872 And 56 Very different that is not 2200 That part's for sure So now I'm back to wondering do we actually want these because I was Not actually testing what I thought I was testing When we had these Not consistent every time We did get pretty consistent when we had this though Although I also think like each line of code we write also Probably consume some RAM as well inside the REPL Actually know how that works There we go. Okay. Now we get a consistent number every time. I do think the sleeps help and then if we switch these Do actually get different values for different libraries well four nine six Ooh that one was still different from time to time Interesting only the first time Okay Seems like we're actually consistent now wait until we see another if we see another difference. I'll tweak it some more, but uh, so Next couple things we want are I want to start building At least test infrastructure that's gonna do this like receive a A job that says Check the RAM of this library It will do it. It will return it back and I think that I'm gonna try to do that through web sockets Because I think that makes the most sense in the architecture that I'm imagining which again is GitHub actions is basically going to send a request to a central server Central server is going to have a bunch of web socket clients connected to it Those are volunteers on a pc or a single board computer with a device plugged in via usb Those are the web socket clients When the central server wants one of the clients to check a size for it It'll send a job through the web socket to say hey, please do this check for me If the client is there and it gets the the job. Okay, it will try it It will do it It will get the number and it'll send that number back through the web socket Central server then has that number and it can actually return it back to that actions Instance essentially that actions task or whatever so To start with I am going to build a very basic version of the server and the client I don't know if these will actually end up being the ones that get used at all But these are going to be the ones i'm going to start testing this idea with to even like See if it's a viable thing to do so Let's not put test in the name that like makes it get treated differently. So let's call this um Job server And then job client And for this i'm going to try using this thing Because it's pretty easy Yes, we should probably install it We need the client side of the docs They do have actually an HTTP example, which is kind of cool How do we run a client? And all of these are servers So this will start up a server listen on port 8,000 Whenever a new message comes in it'll just send the message back to the client that sent it So we should be able to send hello world get hello world back If this is running seems like that worked maybe let's make sure it worked by saying let's modify it to say You sent Self that data That way we make sure we're not just like printing whatever Send rather than I see yeah Oh, but I didn't rerun it. Okay. That is working. Okay perfect so Our server Let's try let's look at this one actually because this has clients. Where does clients come from? connected Whenever a new thing connects loop over clients Call send message blah blah connected And then append I guess the client that connected to clients Whenever it closes we go remove it from there We send all these a message that says disconnected Okay, and then whenever they send a message we just say This user sent this message Okay, okay, so we got connected We didn't ever get this It didn't seem like But this only sends two existing clients Of which we did not have any when we started Therefore, nobody got it So we need to run multiple instances of this Not allowed to run in parallel Ah if I run one from here it's connected Hey, well, okay, so one thing is we wouldn't want to just receive right away. I guess what we would do is like Okay, so after we send our first thing we just Start listening and printing whatever comes in Server should be able to stay running. I think Hopefully got one client running. We haven't seen anything get printed yet We connect a second client Yes, okay, so we got a message in the first client. This is job client here So in the first client that's connected We got the message that says hey another another client connected. We now have two And The second client sent this message right here, which now the first client received in fact They both sent the message. It's just that there was no one around to hear it When the first one sent it they basically joined the chat room sent a message before anybody else was in the chat room So, you know, it's there it went into the ether, but nobody saw it That's how I think a website at least as these like chat rooms essentially um So the way we want this to work is We need a basically just like The most basic version is we just want to wait until we receive a job Going to bed. Thanks to him. Nice weekend To y'all. Yeah, for sure. Good night. Paul. Thanks for hanging out um So let's not Let's not do this Instead, let's just listen If data we're gonna say try json.loads data object data accept value error pass Try to load it as json if that succeeds job in data print data object This should look for An object inside the message that came in You check the object for a job field That has one we print the object. I'm gonna turn off this print We're only gonna print things that are jobs if they come in I'm gonna save that It should be so helpful for pr reviews the uh The memory managing thing or the web socket thing I mean ultimately I I'm hoping to integrate it into the actions so that it will Be used by the pr reviews. We'll be able to say like Memory management. Okay. Yeah. Yeah, that's my goal is like to make this all automated so inside actions that can Print the value and we can assess like, you know, here's what it was before. Here's what it is after um The changes inside this branch so we can see if it's jumping You know too large at any given change or something um So let's stop this client. Let's also stop this client Let's run this client again And then we need another thing called job sender Which is pretty much like the old version of client except You don't really need to listen at all sender is just gonna send and then close and that's it And the thing we're gonna send Object job This will be an object. This will have stuff, right? I don't know what all this will have, you know, uuid blah blah blah Uh, it will have, um module name Adafruit npr one two one It'll have, um npy file htps Blah blah dot com slash You know Something right this is gonna get filled in Okay, so that's good for now. Let's try that We have our client running. We have our server running We should be able to run our sender It finishes immediately on our client. If everything worked, we'll get a printout here Everything did not work though See what we got We run client We run sender. It's connected. Oh disconnected. That was the uh, yeah That was the sender The client inside the sender connected And disconnected Why did this not work? Didn't load right Extra data line one I write my JSON bad I mean, I call dumps though Hmm line one column six One two three four five six That's valid Valid run sender That looks fine. I came from here Extra data line one column six Why don't we get the trace back? Import trace back trace back dot print exec Inside the exception Extra data One thing I noticed is we got three of these a little bit surprised by Oh, no, that's correct. Actually because we got one Connected thing we got one disconnected thing and then in the middle we got The actual job object For some reason we are not decoding Job object correctly And interestingly we see extra data line one column six character five On every single one of these Which is weird if they're different data I mean, is this not valid json? Is it not a string or something? No three of them are strings Extra data What you have two records? hmm, so Before we send it Oh, I am being silly. I am being so silly so so silly for getting this stuff in front of it, of course um Job server handle this should just send the data by itself Else we run the server We run the client We run the sender Okay, now we have a bunch of extra prints Don't need Side client We want this one really need this stuff or this stuff Or this This one i'll keep we run client We run sender Boom, okay now every time we run sender The client will notice that it's a job object and it will print it out for us. So at this point we could You know do our Import check on it. So inside client We could say inside of here. We got a job How's it going near doc? I am working on memory measuring So the first thing I did was build this on device ram check This is a python function That allows you to pass a module name and a device path like dev tty ACM zero It will basically Import this module on the device and return back to you the amount of ram That it consumed. So we could run it here right now. It's using the simpr 121 And I have a device connected to my pc. I don't have the camera set up But it is there and it's connected over usb That device told us that we imported this library. We used 6608 bytes of memory were allocated for that import So that's the first bit of it is like check a check a A library check a module on a device to see how much ram it consumes when you import it And then the next layer of this is we're going to try to do that check inside of this web socket client Which is connected to this web socket server That allows jobs to be sent to it So something can send a job to the server The server is then going to afford that job to a client The client's going to execute the memory checks and the result back The server is then going to be able to ultimately respond back to the Thing that requested it which is hopefully going to be get hub actions. So like Once everything is all working together an action is going to fire to a central server Central server is going to send those jobs through the web socket One of the clients is going to carry out the job get the measurement send it back to the central server Central server is going to send it back to get hub actions So that it can include that in the output of the actions And then my idea is like volunteers can keep devices plugged into their pc Even like a raspberry pi I think would work for this You keep it plugged in and you just keep it running 24 seven connected to the internet And you run this job client script So it'll basically connect to the central server and just listen for incoming jobs Whenever it receives an incoming job, it will execute it figure out the amount of memory Send it back to the central server will then forward it along to actions and everything else So that is like The grand vision for what i'm working on right now specifically During the stream I did this bit which does the memory check on the device and I've now created the A placeholder a very basic version of the web socket server the web socket client And then something to send a test job And so now what i'm going to do is have it try to run this RAM check When it receives The job module name How's it going dax So the end goal is to have the server with devices hooked up or to emulate server with devices hooked up Well, it's too hot right there's a central server which is out on the internet And then there's a script which runs on your local pc or raspberry pi that connects to that central server And your pc or raspberry pi also has a microcontroller plugged in with usb So your pc or raspberry pi is essentially allowing that Central server to be able to use your microcontroller To test the memory size How's it going dj devin? But yeah, not not emulated the real devices But they're plugged into pcs which are running this client job Running thingy bopper whatever it ends up being called Um, so get the ram size. We don't need to really print the data object. Let's say if ram size Send back json dumps Sounds interesting. It'll automatically track ram use for code running on a device. No, not quite It will track ram use for a specific library that you tell it to import And that's it. So it's not like a long running thing that measures your project Or any given project. It's just a module a single import module at a time The the idea being We would run this check anytime a change is made to a library. So we'd have a Before the change amount of ram that the library consumes and then we have an after the change amount of ram that the library consumes and both of those values get printed Somewhere inside the pull request that way we can see like here's how much ram this library uses Today and then here's how much ram it will use if we accept these changes If that makes sense, but yeah, we're always testing one specific module not You know the an entire project altogether Job client one thing is I don't know if we're gonna see this printed anywhere I think let's just add a print ink data Self that data So we just can see it on the server if we actually send back this result correctly Okay, so the server's running the client's running We'll send our job We'll look in the client Ah, yeah We need to turn this to bytes. How do you convert a string to a byte string? in code Bites What's the one liner pipe bytes string dot encode string dot encode We run the client We run the sender Boom. Okay. So client got its job client Got the amount of ram and client sent it back to the server and server received it So at this point the server would return that value Back to actions, um, which would have initially been Essentially the actions task would have been this job sender The actions task will send the send the job to the central server Uh, probably with an HTTP request not a web socket thing like this right now This is connecting to the web socket sending the job that way eventually this will probably be like a post I think Um, you know, you post the job to the server and the server then sends it through web socket to the other thing Um, I will never have time to do it and it's likely above my abilities But I want to look into the wakui emulator and uh run it making memory snapshots So we can see everything like that thing scott did a while ago with the debugger that would be awesome I agree with that definitely In code decode. Yep. Thank you MicroPython has a unicorn emulator on their website that this reminds me of interesting unicorn emulator. I'll have to check that out I'm not familiar with it Okay So I think I'm gonna probably be wrapping it up pretty soon So for folks that weren't here at the beginning I let everybody know when I started that it was gonna be a little bit shorter of a stream than normal I'm headed out to dinner with my wife and family um And so yeah, I'm gonna be wrapping up here in just a minute I'm pretty happy with what we got done today though, right? We have this ability to Check the memory usage on an actual live device and we have the very beginnings of a very rudimentary version of a server and a client that will allow us to Request these readings to get taken And then send that reading back to the server that way We have the beginnings of a couple of these different components that will then allow us to Integrate all of this with actions And so then essentially we can be doing automated tests automated tests on live devices and another thing I'll say to like This is just the beginning of this. This is kind of the first thing I want to do with this With this infrastructure that allows this on device testing in the automated fashion like theoretically We could be running actual test cases and actual like assert things and stuff as well Um In this one. We're not actually really executing any code except for just import and figure out the size But like in the end once we have this infrastructure These job runners they could run different kinds of jobs. We could have one that will actually run a test suite Um, you know check some assertions and then give you back the response, you know the results of those tests Um, so that's kind of like pie in the sky, you know even more what we could do with this infrastructure If we do get it set up And the the last thing I'll say is like, you know, it relies on the volunteers, right? This whole thing only works if enough people are willing to plug in a device to a computer that's running all the time Um, so like I can volunteer a computer to do that, but at the end of the day, we probably will need more volunteers that are willing to Have their pc run this client script and connect their device up to it. So I don't know for sure how much uh buy-in will get from the community on that But that's one thing that this does hinge upon even if we make all this infrastructure We need the actual devices to get plugged in and to run the client script to actually do the tests for us So my hope is that if I can set up the infrastructure and make it super duper duper easy for you to just plug in your device and let it Do this my hope is that we'll have a handful of folks in the community who are willing to Just let that run 24 7, you know tucked away on a raspberry pi or whatever Um, just kind of set it and forget it let it run its tests in the background there and do its thing. So Um, we'll have to see if we once we get everything all set up Then we'll have to uh See if we can get folks to do it Um, is there a link to the Adafruit discord? You see it now. Yep. No problem And it is down there. I'll say it allowed to for anybody who is listening but not watching adafru.it Slash discord. Um, that is the link to go to the Adafruit discord. I would plug in a few selfishly. So it would be uh Selfishly it would be so helpful. Yeah I'm glad to hear that raspberry pi with a huge usb hub. Yeah, you could have multiple devices even On one thing. That's another another thing. We could do it, you know Eventually we can start having the devices like report back what they are, you know, esp 32 s2 You know, it's going to run the test on that or whatever versus a samd 51 or something Um, you know, there's a bunch of different different ways we can do this. I kind of am Facing this idea off of some of the stuff that is available out there for mobile Automated testing. There's similar things like this for mobile automated testing out there I think scott even talked to somebody he's mentioned it a few times Uh, a startup that was trying to do that. So that's kind of what I modeled this idea on is is those, you know, cloud based Mobile phone automated testing services. That's kind of the same idea. I want here is a cloud based microcontroller automated testing service Um, but we are not going to use it as a service that people pay for probably at least not at the beginning We're going to use it as github actions does it so that we can make more informed decisions about pull requests in our libraries I would run at no p would be cool to have rammy valves on my gps project because gps runs 24 seven. Yeah, that's a whole That is also like a whole another layer is like accurately measuring an entire project that's running This is really isolating down to the individual ones But yeah 24 seven stuff That's when honestly the memory is the most important because you got to make sure you're not growing over time Or you got to make sure to have automated reboots. Otherwise you run out of ram eventually So that is definitely one of the challenges of those like always on iot 24 seven type things Um, but yeah, that's where we're at. That's the progress we got done today. We got the very beginnings of this We can we can do the measurement We have a basic server a basic client. We're able to send jobs Um, so that's where rat will keep we'll keep hammering away at it We'll try to get this built up eventually. We'll switch it into a web server so that It can take a post request to get the job sent in and We'll just take it from there So thank you everybody for watching. That's the thing I dream of too having a hub with 20 boards since I have Since I have many I don't use and I automatically test cp builds every now and then With a suite of tests that can be done in the ci. Yeah, that's awesome I'm glad to hear there's a couple folks It sounds like that are interested in this and that brings up another good point as well is is builds, right? I've been taking the the library angle of approach to this talking about like library prs and Measuring the the ram usage of those library updates Um, but we could totally have this hooked up to the core p the core repo as well to where like When a pr gets submitted to the core This central server can make the build and send the uf2 down And this web socket client could like install that uf2 on the device even Um, obviously that's a lot trickier, but we could be testing on that level as well the core um So library will be easier. That's what I'll start with but Down the down the road we could certainly expand this to more and more stuff Um, thank you. Uh, thank you everybody the who's watching this is amazing idea and project Looking forward to seeing this one progress in tandem with web for workflow. Yeah Thank you appreciate it. Um, thanks again to everybody watching Um, I will be back tomorrow morning. I'm pretty sure tomorrow morning. I'll be back at the normal time 10 a.m Central time for my Saturday stream. So I'll be there Check me out. Uh, you can follow me on twitch if you want foamy guy underscore twitch That'll give you the notifications when I start that stream I'll post the links and stuff in the discord for folks that are interested Um, thanks everybody for watching. I don't necessarily I got to get running So I'm not going to scroll through and thank everybody by name But I do appreciate all of you that are watching everybody who watched and participated. Thanks so much for that You know, it's kind of one of the highlights of my week to come here and stream for you all and interact with you So, uh, thank you for that and I do appreciate it