1 00:00:02,260 --> 00:00:03,820 Welcome to the CircuitPython Show. 2 00:00:04,120 --> 00:00:05,180 I'm your host, Paul Cutler. 3 00:00:05,680 --> 00:00:08,980 This episode, I'm joined by returning guests, Tod Kurt, and Jan Guilsby 4 00:00:09,100 --> 00:00:11,900 to talk about CircuitPython's community bundle of libraries. 5 00:00:12,860 --> 00:00:14,340 Tod and Jan, welcome back to the show. 6 00:00:15,020 --> 00:00:15,460 Hello, Paul. 7 00:00:15,780 --> 00:00:16,379 Hi, thanks for having me. 8 00:00:16,540 --> 00:00:16,920 Hey, Tod. 9 00:00:17,420 --> 00:00:18,000 Hey, hey, Jen. 10 00:00:18,960 --> 00:00:21,360 So we're here today to talk about the community libraries 11 00:00:22,020 --> 00:00:24,040 that are available on CircuitPython.org. 12 00:00:24,680 --> 00:00:26,760 There's over 500 different libraries split 13 00:00:26,940 --> 00:00:29,860 between the official Adafruit Library bundle and the community bundle. 14 00:00:30,300 --> 00:00:34,860 chances are if you're listening to this podcast, you're familiar with the official Ata Fruit Library bundle. 15 00:00:35,500 --> 00:00:40,400 But let's talk about the community bundle, which has over 150 bundles created by community members. 16 00:00:41,180 --> 00:00:42,900 How do you define the community bundle? 17 00:00:43,580 --> 00:00:48,260 Well, I've been using the community bundle for probably about two and a half, three years now. 18 00:00:49,040 --> 00:00:51,600 And it was my first exposure. 19 00:00:51,780 --> 00:00:52,540 I'm not a programmer. 20 00:00:52,720 --> 00:00:56,780 So it was my first exposure to different kinds of coding styles. 21 00:00:57,540 --> 00:00:59,880 And it helped me pick up and learn a lot of. 22 00:00:59,900 --> 00:01:05,580 about CircuitPython, but it also gave me some utilities and things that I could use to kind of 23 00:01:05,740 --> 00:01:12,720 enhance my code. So CircuitPython had both those features for me initially. It also provided 24 00:01:13,140 --> 00:01:18,720 that community sharing that I thought was important, especially in my own growth. Yeah, yeah, 25 00:01:18,760 --> 00:01:23,180 that's for me. I've been using the bundle since it existed, and it's where I've been learning most 26 00:01:23,260 --> 00:01:27,800 of my Python from, honestly. That's interesting. I would have never thought of that as a learning 27 00:01:28,460 --> 00:01:33,140 tool. Yeah. Yeah, just like, how does this class work? Well, let's just look at the source code 28 00:01:33,280 --> 00:01:37,120 because you can just download the bundle and zip it all and look at it. It's really handy. 29 00:01:37,720 --> 00:01:42,460 Well, and it's wonderful for getting that kind of information because you don't have to waste 30 00:01:42,800 --> 00:01:48,240 some experts' time in your process of learning when you're really low on the scale and trying 31 00:01:48,300 --> 00:01:52,580 to figure out, you know, how do you get a four next loop kind of thing to work in a while until 32 00:01:54,280 --> 00:01:57,780 and you can do that without having to face anyone and being very much. And being very much. 33 00:01:57,800 --> 00:02:00,120 by how poorly your code looks. 34 00:02:02,040 --> 00:02:05,020 So how do you know when your code is ready to be submitted to the bundle? 35 00:02:05,660 --> 00:02:12,440 I would say if you've gone to the trouble of making a Python class to solve a problem, 36 00:02:13,120 --> 00:02:15,860 there's probably a good chance that it could be useful for other people. 37 00:02:16,540 --> 00:02:19,280 And so that's where a lot of my libraries have come from. 38 00:02:19,380 --> 00:02:23,920 I spent the, I spent the, whatever it was, hour to get it working. 39 00:02:24,260 --> 00:02:26,240 And I'm like, well, I've got a class now. 40 00:02:26,640 --> 00:02:30,440 How much longer could it take to add the rest of it to be publishable? 41 00:02:30,780 --> 00:02:34,620 And depending on your predilections, it could be another hour or it could be like a week. 42 00:02:36,980 --> 00:02:42,020 That's kind of my threshold, too, is if it can stand as a class, a class object, 43 00:02:42,940 --> 00:02:50,020 then it's something that might be useful to someone else because that's how they can insert it into their code as another object that they need. 44 00:02:50,340 --> 00:02:50,560 Yep. 45 00:02:50,960 --> 00:02:53,820 So let's talk about the process to create a library a little bit. 46 00:02:54,360 --> 00:02:59,320 Adifurts tried to make it easy to contribute by using cookie cutter in open source project template package. 47 00:03:00,000 --> 00:03:03,040 What kind of information does cookie cutter walk you through that it needs? 48 00:03:04,760 --> 00:03:09,700 Well, I mean, like there's the obvious things like the what is the name of the repo that it lives at? 49 00:03:09,800 --> 00:03:12,800 What is the name of your class of the library itself? 50 00:03:13,340 --> 00:03:14,940 Well, it does ask a lot of questions. 51 00:03:15,420 --> 00:03:16,920 And it says, where's your documentation? 52 00:03:17,980 --> 00:03:20,440 And, you know, is this a driver or is this a helper? 53 00:03:20,980 --> 00:03:23,940 Some confusing questions like that, too, that. 54 00:03:24,220 --> 00:03:27,640 yeah, it is more geared towards ATA Fruit employees, it seems. 55 00:03:28,000 --> 00:03:31,720 And so, like, some of the questions that asks are things that you can just say nothing to 56 00:03:31,900 --> 00:03:33,380 because it's not applicable to you. 57 00:03:34,360 --> 00:03:37,460 Yeah, and matter of fact, it's okay to skip over some of those things. 58 00:03:37,580 --> 00:03:42,780 If your documentation's not ready yet, or like me, I don't want to create an account 59 00:03:43,500 --> 00:03:50,100 out for Sphinx or for Read the Docs, some of the things that would be good to do if I was 60 00:03:50,160 --> 00:03:52,180 a full-time programmer, but I'm a hard-work guy. 61 00:03:53,100 --> 00:03:55,200 And I only do one or two a year. 62 00:03:55,400 --> 00:03:56,660 So I skip those steps. 63 00:03:56,820 --> 00:04:00,620 And I try to provide as much documentation in the code as possible, of course. 64 00:04:01,360 --> 00:04:07,240 But there, so you can kind of look at cookie cutter as this thing that, that'll shape the cookie for you. 65 00:04:07,380 --> 00:04:10,400 But you can put all the sprinkles on it or take them off or whatever. 66 00:04:11,220 --> 00:04:22,900 If you were to go full on with what cookie cutter provides, what you would be making is not only your Python code, your class, but you also are required to create some examples, at least one example, create some. 67 00:04:22,920 --> 00:04:30,060 documentation in the read-the-docs format, make sure that it passes the PyLint and Ruff, 68 00:04:30,540 --> 00:04:37,560 RU-F-F, Linter, or whatever, and also release it on Pi-Pi, the Python package repository in 69 00:04:37,680 --> 00:04:38,580 addition to this thing. 70 00:04:39,140 --> 00:04:44,020 Most of those things are optional, which I didn't realize, and it was looking at some 71 00:04:44,080 --> 00:04:49,080 of JAN's libraries that I realized, oh, look, you can just not choose to do the Pi-Pi stuff, 72 00:04:49,260 --> 00:04:52,200 not choose to do the read-the-doc stuff. 73 00:04:52,320 --> 00:04:53,460 that makes it a lot easier. 74 00:04:54,040 --> 00:04:55,080 You just don't do it. 75 00:04:57,640 --> 00:05:00,600 But I'm not trying to be too flippant about that. 76 00:05:01,100 --> 00:05:04,160 It's really that I don't have a lot of those skills yet. 77 00:05:04,440 --> 00:05:09,280 And I'm trying to develop those skills as I write these libraries and other code. 78 00:05:09,860 --> 00:05:17,680 And I know that all those things are very valuable, especially in a professional environment where if you're trying to share too and maintain these things. 79 00:05:18,620 --> 00:05:22,180 So like I said, I'm not trying to be too antisocial. 80 00:05:22,340 --> 00:05:23,620 about doing this stuff. 81 00:05:24,540 --> 00:05:26,300 But it kind of distracts 82 00:05:26,360 --> 00:05:27,840 from my primary objective 83 00:05:28,080 --> 00:05:28,900 and that is, 84 00:05:29,400 --> 00:05:30,740 let's get something out there to share. 85 00:05:31,760 --> 00:05:33,360 Yeah, I think that's a really good, 86 00:05:33,540 --> 00:05:35,240 a good way to do it as sort of the tiered 87 00:05:35,400 --> 00:05:36,180 or the staggered, 88 00:05:36,580 --> 00:05:37,820 or not staggered, staged, staged approach 89 00:05:38,080 --> 00:05:40,200 where I just want to get my library up 90 00:05:40,540 --> 00:05:42,520 and into the bundle so I can have my buddy 91 00:05:42,940 --> 00:05:45,040 try using it and see if it works for them. 92 00:05:45,560 --> 00:05:48,280 And you don't have to have all those extra bits working 93 00:05:49,200 --> 00:05:49,820 just to get it out there. 94 00:05:50,020 --> 00:05:52,180 Yeah, the probationary phase. 95 00:05:52,200 --> 00:05:57,200 bays is my code. I go through a lot of probation with my code. 96 00:05:59,120 --> 00:06:04,700 The bundle also uses pre-commit. How does pre-commit help you get your library ready to be published? 97 00:06:05,540 --> 00:06:22,160 Yeah, that was really fascinating to me. I'd never really experienced that. When you change your code and you say Git commit and you use it, say which files to commit, it'll just commit it and push it up to GitHub or whatever. But with pre-commit, it will run some code. 98 00:06:22,180 --> 00:06:27,500 And the cookie cutter setup has it run a bunch of different tests, a bunch of different linters. 99 00:06:27,740 --> 00:06:30,560 Like it used to be, it would run both Pylent and Black. 100 00:06:31,100 --> 00:06:34,280 I think now it runs something else called Ruff, RUFF. 101 00:06:35,280 --> 00:06:37,340 I don't know if they still use Black, but it was really strict. 102 00:06:38,340 --> 00:06:42,840 And it had thoughts about how Python should be formatted that didn't, I didn't agree with. 103 00:06:42,900 --> 00:06:50,160 And so I really dove down into figuring out what are some of the things you can tune on Black to make it a little less persnickety. 104 00:06:51,220 --> 00:07:03,640 Because the whole point of the way that pre-commit was set up is that you can't push your commit unless it passes the black or the lint checks, which is really important if you're working in the team, which we all are with the community bundle. 105 00:07:04,580 --> 00:07:06,480 Yeah, Ruff Replace Black. 106 00:07:06,620 --> 00:07:09,740 Ruff is a linter written in Rust, and it's super fast. 107 00:07:09,900 --> 00:07:10,900 I've used it in C Python. 108 00:07:11,100 --> 00:07:15,120 I haven't had a chance to write my own library and actually go through this process. 109 00:07:16,400 --> 00:07:22,020 You know, I think those steps for me were pretty important and kind of in my learning process. 110 00:07:22,720 --> 00:07:27,320 Lenting and the case of most of my libraries going through the black formatter, 111 00:07:28,120 --> 00:07:34,160 those taught me a lot about how to communicate my code to other people 112 00:07:35,000 --> 00:07:38,120 and how to put it in a format where they could recognize what I was trying to do 113 00:07:38,300 --> 00:07:39,100 and what I was trying to say. 114 00:07:39,180 --> 00:07:43,140 In other words, it helped with the ongoing maintenance of it as well. 115 00:07:43,940 --> 00:07:47,540 Initially, I was kind of confused by most of the Lent messages I got. 116 00:07:48,180 --> 00:07:49,800 And thank goodness for people like Kattni. 117 00:07:51,300 --> 00:07:53,400 She really, she got a lot of calls for me. 118 00:07:53,820 --> 00:07:58,219 And she helped me out and helped me learn a lot about that as I went through that process. 119 00:07:59,520 --> 00:08:05,320 Yeah, yeah, Black was really particular about making sure you document all the methods of your class, 120 00:08:05,860 --> 00:08:13,860 which, you know, to you, in the depths of all, you're like, well, of course it makes sense that this method called Frobbnitz, it's clear what it does. 121 00:08:13,880 --> 00:08:20,020 But even me two weeks from now, I won't know what the method Frobbnitz does. 122 00:08:21,780 --> 00:08:28,740 But thankfully, Black would have made me write a little like one or two line description as to what this stupid method does. 123 00:08:30,080 --> 00:08:36,840 Yeah, I had a couple of libraries I submitted where the documentation exceeded the length of the code. 124 00:08:37,700 --> 00:08:43,820 So when you look at that, and I don't know what the measure of success is there, if you have, 125 00:08:43,860 --> 00:08:51,160 80% more documentation and 20% of that is code. I don't know what the, but I had at least 50 or 60% of 126 00:08:51,260 --> 00:08:57,360 the documentation was explaining what my algorithms were and the algorithms were about the remainder. 127 00:08:58,400 --> 00:09:03,760 Yep. That's about the size of things usually. One of the things I really like about the process 128 00:09:03,920 --> 00:09:07,720 is that Adafruit does require you to write documentation, which we just touched on a couple 129 00:09:07,780 --> 00:09:14,340 minutes ago as well, including the read me and read the docs. Do you think community libraries 130 00:09:14,560 --> 00:09:18,900 should be held to a similar standard as official libraries from Aida Fruit when it comes to documentation? 131 00:09:20,240 --> 00:09:26,220 Well, I do have an opinion on that being, you know, like I keep touting the fact that I'm not a 132 00:09:26,620 --> 00:09:30,820 programmer as if that's going to be some sort of a shield that I can hold up here to say, 133 00:09:31,160 --> 00:09:36,520 I'm not going to do the documentation and I'm not going to, well, anyway, I think I'm someone who 134 00:09:36,540 --> 00:09:44,480 really documents a lot. My code has, just by my own nature, I try to, well, I try to talk to the future 135 00:09:44,620 --> 00:09:51,940 Jan who says, I don't remember why I did this. And so I'm probably way more verbose than I need to be 136 00:09:52,100 --> 00:09:59,680 in a lot of cases. But I do think that there is some limit there that holding everybody to the same 137 00:09:59,760 --> 00:10:07,020 standard of a high level of detail in their documentation may actually kind of thwart their 138 00:10:07,480 --> 00:10:12,420 creativity or make them feel a little bit insecure about submitting their code if they don't 139 00:10:12,480 --> 00:10:18,400 really know what to expect in terms of the level of detail. So there's probably some middle 140 00:10:18,560 --> 00:10:23,280 road there. I'm not articulating this very well, but there's some middle road there, I think, 141 00:10:24,020 --> 00:10:29,640 where perhaps we allow a little bit more leeway in terms of the quality. 142 00:10:29,700 --> 00:10:35,560 the documentation and then just provide a lot of comments and helpful provide a more helpful 143 00:10:35,900 --> 00:10:37,100 approach to that. 144 00:10:37,600 --> 00:10:37,720 Yeah. 145 00:10:38,200 --> 00:10:42,720 I've been really, really liking some of your documentation because like the read the docs 146 00:10:43,660 --> 00:10:47,500 formatting, whatever it's called, the language makes it hard to do some things that are 147 00:10:48,080 --> 00:10:49,580 easier to do in other types of documentation. 148 00:10:49,880 --> 00:10:54,740 And your documentation has had like little animations and stuff and various graphs and 149 00:10:54,880 --> 00:10:56,420 diagrams to explain what's going on. 150 00:10:56,840 --> 00:10:59,420 And that's to me harder to do in the read the doc stuff. 151 00:10:59,860 --> 00:11:04,840 But at the same time, I find a little bit of comfort when a library has a read-the-docs page. 152 00:11:05,240 --> 00:11:10,600 And so that's why I've been striving for my life is trying to make even just the minimal read-the-docs things. 153 00:11:10,700 --> 00:11:13,080 Like, oh, it looks like all the other libraries that I've seen. 154 00:11:15,180 --> 00:11:18,820 So you've written documentation, you've written your library, run it through cookie cutter. 155 00:11:19,500 --> 00:11:22,660 What are the next step to actually submit it to the community bundle? 156 00:11:23,740 --> 00:11:29,420 I believe the main thing is you just go to the community bundle. 157 00:11:29,460 --> 00:11:36,000 repo and edit, I think, just one file that is the list of the modules. And I think it's a 158 00:11:36,120 --> 00:11:41,620 markdown file, and you just add a link to your repo and add a link to your documentation 159 00:11:41,900 --> 00:11:47,000 page if you have it. Oh, no, that's right. You edit another file that is the get submodule for 160 00:11:47,180 --> 00:11:53,860 your library. So you edit two files. The markdown documentation that links to your repo and 161 00:11:53,880 --> 00:11:58,280 then a Git submodule that links to you the repo of the code. 162 00:11:59,320 --> 00:12:00,980 And then you submitted that as a PR. 163 00:12:01,620 --> 00:12:03,560 The PR gets accepted and maybe a day or two. 164 00:12:03,880 --> 00:12:08,980 And then the next build of the bundle, which happens, I think maybe weekly, will have your 165 00:12:10,000 --> 00:12:15,020 And if I look at my list of things that I forget to do when I'm submitting, one of 166 00:12:15,120 --> 00:12:22,500 them is be sure to release the code in your own repository before you try submitting it. 167 00:12:22,540 --> 00:12:28,160 because the automated process will just ignore the fact that you've got something there unless it has a current release. 168 00:12:29,060 --> 00:12:31,860 That's one local step that you have to do in your own repository. 169 00:12:32,880 --> 00:12:42,920 Yeah, and that's one of the nice things because the bundle build process requires certain files to exist in your repo's release thing. 170 00:12:43,340 --> 00:12:50,540 And the cookie cutter template has an action, release action that will build some of those files for you. 171 00:12:50,660 --> 00:12:52,320 so you don't have to do it yourself. 172 00:12:52,740 --> 00:12:53,580 I'm pretty sure. 173 00:12:54,260 --> 00:12:57,940 One of the problems is that while there is a documentation on creating and sharing a circuit 174 00:12:58,140 --> 00:13:01,760 Python library, some of it's a little out of date because things have evolved. 175 00:13:01,860 --> 00:13:04,580 Like it was originally, I'm looking at the page right now. 176 00:13:04,880 --> 00:13:11,640 It was originally created in 2017, and it was last edited January 22nd of this year, 2025, 177 00:13:12,400 --> 00:13:14,940 and the last major update was January 11th of 2022. 178 00:13:15,180 --> 00:13:16,360 So, you know, things change. 179 00:13:18,220 --> 00:13:19,580 You have to kind of steal your toes. 180 00:13:20,640 --> 00:13:27,980 more than once I've popped into the Circut Python Dev Discord channel with the big question marks of what the heck is going on? 181 00:13:28,060 --> 00:13:31,020 I'm trying to make this library and it's like give me weird errors. 182 00:13:31,120 --> 00:13:33,880 And people are like, oh, right, we just did this change to the template. 183 00:13:35,260 --> 00:13:39,020 I got used to the fact that the requirements would change occasionally. 184 00:13:39,500 --> 00:13:41,720 Either that or I forgot what the requirements were. 185 00:13:42,220 --> 00:13:43,820 Yeah, both. 186 00:13:44,480 --> 00:13:49,660 It's not a simple process for someone who doesn't do it for a living, I think. 187 00:13:49,900 --> 00:13:55,820 And although I value the steps in the process for what they produce, I don't remember them from one submittal to the next. 188 00:13:56,620 --> 00:14:04,320 And so having the learn guide handy out there and my list of things that I forget when I'm doing this, those get me through it each and every time. 189 00:14:05,240 --> 00:14:07,860 Yeah, I've got my own little script that I run. 190 00:14:08,560 --> 00:14:13,380 It's called something like Adafruit CircuitPython library development.t.com. 191 00:14:13,440 --> 00:14:14,180 That's in my home directory. 192 00:14:15,640 --> 00:14:17,840 Just a list of things to make sure to do. 193 00:14:18,380 --> 00:14:19,520 Now, there's a good idea. 194 00:14:22,040 --> 00:14:26,380 Once the bundle's been built weekly, the new library will be available in Circup. 195 00:14:26,560 --> 00:14:27,060 Is that correct? 196 00:14:27,700 --> 00:14:27,980 Yes. 197 00:14:28,900 --> 00:14:33,100 And Circup is such a handy tool for the community libraries. 198 00:14:33,520 --> 00:14:37,540 I think if there's no other benefit to putting something in the community bundle, 199 00:14:38,700 --> 00:14:40,460 Circup will pave the way. 200 00:14:40,720 --> 00:14:45,820 In other words, you can share your library very quickly because Circup makes that simple. 201 00:14:46,380 --> 00:14:49,540 I think the case where you've produced a library and you've produced a library and you 202 00:14:49,560 --> 00:14:50,900 want some friends to test it. 203 00:14:51,500 --> 00:14:53,460 Circup is the best way to distribute that. 204 00:14:54,200 --> 00:14:54,320 Yeah. 205 00:14:54,540 --> 00:14:56,000 And if you're listening to this and you've not, 206 00:14:56,420 --> 00:14:59,000 and if you use CircuitPython and you haven't tried out Circup yet, 207 00:14:59,480 --> 00:15:00,420 please use it. 208 00:15:00,680 --> 00:15:02,580 You can just download the library bundles, 209 00:15:02,620 --> 00:15:03,660 a zip file, it, unzip it, 210 00:15:03,720 --> 00:15:05,320 and pull out the various files you need. 211 00:15:05,760 --> 00:15:07,740 But Circup makes it so much faster to do all that. 212 00:15:08,340 --> 00:15:11,440 I really wish there was a more web-based way 213 00:15:11,580 --> 00:15:14,020 to discover the libraries that are in the bundle. 214 00:15:14,200 --> 00:15:15,820 Like right now, you can just go to the repo 215 00:15:16,100 --> 00:15:19,160 and just look at all the various modules in the list as a big, 216 00:15:19,440 --> 00:15:20,580 you know, markdown file or whatever. 217 00:15:21,320 --> 00:15:26,860 But it'd be nice if there was some sort of like online Circup browser almost where you could 218 00:15:26,980 --> 00:15:30,340 type in a search term and it would like give you the libraries that might match or something. 219 00:15:30,500 --> 00:15:35,680 Kind of like the way Pi Pi does it because Circup is a lot like PIP, but for Sircup Python. 220 00:15:37,900 --> 00:15:41,240 What advice would you have for someone considering sharing their first library? 221 00:15:41,900 --> 00:15:49,380 Well, I think probably the best advice I would have would be, we talked about this a little bit ago, 222 00:15:49,400 --> 00:15:56,380 about if you have a class object that does something useful, useful to you, it's probably 223 00:15:56,640 --> 00:15:57,800 useful to someone else. 224 00:15:58,360 --> 00:16:00,520 We talked a little bit about that litmus test. 225 00:16:01,020 --> 00:16:04,440 The other thing is you may have something that you've done that's pretty unique. 226 00:16:05,000 --> 00:16:10,440 And there are libraries that I submitted out there because they were kind of unique in my 227 00:16:10,720 --> 00:16:12,000 development as a programmer. 228 00:16:12,600 --> 00:16:19,060 And one was a light sensor that I wanted to be able to use just a simple phototransistor. 229 00:16:19,620 --> 00:16:24,200 to detect a motion across the front of a pie portal 230 00:16:24,800 --> 00:16:29,040 and detect a shadow so that it could see that I waved at it. 231 00:16:29,240 --> 00:16:33,040 Using a phototransistor to do that is a difficult thing to do 232 00:16:33,760 --> 00:16:36,980 because you get the LED lights that were using overhead. 233 00:16:37,620 --> 00:16:39,580 They produce a lot of noise, actually, 234 00:16:39,820 --> 00:16:41,340 that kind of looks like gestures. 235 00:16:42,380 --> 00:16:43,600 To make a long story short, 236 00:16:43,860 --> 00:16:46,920 I had to put some algorithms in there to filter out the light 237 00:16:47,100 --> 00:16:49,060 and make it so that it would, 238 00:16:49,300 --> 00:16:52,380 work with any photo transistor and work with any lighting condition. 239 00:16:53,520 --> 00:16:58,480 So it was a very unique library to submit because of the work that I put into that 240 00:16:59,100 --> 00:17:00,940 to make it useful for me, for my project. 241 00:17:01,220 --> 00:17:05,860 And that gave me the indicator that I thought, okay, there's some value to this that 242 00:17:06,020 --> 00:17:06,920 somebody else could use. 243 00:17:07,439 --> 00:17:08,180 That's really fascinating. 244 00:17:08,680 --> 00:17:09,500 I didn't know you made that library. 245 00:17:09,819 --> 00:17:11,600 I remember seeing it in some project. 246 00:17:11,880 --> 00:17:13,300 Maybe it was your project that I saw it in. 247 00:17:14,220 --> 00:17:17,760 But this to me makes me think of another reason why you should put something in the 248 00:17:18,020 --> 00:17:22,319 community bundle as an archival action for your code. 249 00:17:23,520 --> 00:17:26,640 You know, it's like, like, I've written so much code that I'm like, where did I put it? 250 00:17:26,760 --> 00:17:31,200 You know, it's in some repo somewhere for some project that I did five years ago. 251 00:17:31,640 --> 00:17:32,420 But it was in the bundle. 252 00:17:32,460 --> 00:17:33,760 They were like, oh, maybe, you know, is that. 253 00:17:34,440 --> 00:17:34,800 Oh, yeah. 254 00:17:35,040 --> 00:17:35,180 Yeah. 255 00:17:35,640 --> 00:17:41,380 I often wipe my brow, wipe the sweat off my brow after worrying about finding something 256 00:17:41,940 --> 00:17:43,980 and just being able to bring it in from Circa. 257 00:17:44,600 --> 00:17:44,700 Yeah. 258 00:17:45,200 --> 00:17:47,620 So have the other thing I like, oh, sorry, go ahead. 259 00:17:48,100 --> 00:17:59,400 No, I was just going to say, having it out in the community bundle is saving me a lot of labor, too, because there are libraries that I use that are mine and others that come from the community bundle, and I use them often. 260 00:18:00,180 --> 00:18:07,580 And it really makes it convenient, even just for me. It's not just about sharing. It's about making it available for your own use. 261 00:18:08,220 --> 00:18:17,620 Yeah. Yeah. One of the things I really like about the process of making a library for the bundle is it makes my libraries better because I actually sweat. 262 00:18:17,640 --> 00:18:24,200 some of the edge cases or different possible ways the library could be used that end up benefiting 263 00:18:24,380 --> 00:18:27,440 me because at the time I didn't really know I needed it that way. 264 00:18:27,540 --> 00:18:31,000 But then like a week from now, I then find out I do need it that way and I've already written 265 00:18:31,080 --> 00:18:32,460 it and published as a library. 266 00:18:32,540 --> 00:18:35,960 So it makes me more serious about the code, I guess, that I'm writing. 267 00:18:36,300 --> 00:18:37,660 And you receive comments. 268 00:18:37,900 --> 00:18:39,420 Believe me, you will receive comments. 269 00:18:40,180 --> 00:18:42,140 And it's very useful. 270 00:18:42,500 --> 00:18:47,560 I don't think I've ever received a comment that didn't have some use either. 271 00:18:47,620 --> 00:18:53,240 in the current version to fix something or for some features I hadn't even thought of for the 272 00:18:53,480 --> 00:18:53,840 future version. 273 00:18:54,340 --> 00:18:59,140 So are users leaving comments or bug reports in the GitHub repository that you created for the library? 274 00:19:00,060 --> 00:19:01,400 That's where I receive them, yeah. 275 00:19:01,980 --> 00:19:02,280 Interesting. 276 00:19:03,100 --> 00:19:07,380 Is there a way or a path for a community library to be officially adopted by Adafruit? 277 00:19:08,200 --> 00:19:14,160 I think of the three of us, I may be the only one here that it's had a library go from the 278 00:19:14,300 --> 00:19:17,580 community bundle into the regular CircuitPython library bundle. 279 00:19:18,340 --> 00:19:20,140 And there was no clear path for that. 280 00:19:20,720 --> 00:19:26,800 It was something that I created a couple of years before Adafruit had a product that was similar. 281 00:19:26,860 --> 00:19:28,000 It was a driver that I wrote. 282 00:19:29,360 --> 00:19:29,560 Okay. 283 00:19:29,700 --> 00:19:32,560 So they produced a board that would kind of match the board that I made. 284 00:19:33,340 --> 00:19:38,660 And the library that I had for that was one that I was, I said, you can just have this. 285 00:19:38,740 --> 00:19:42,140 I talked directly to Lady Ada and said, you can have this. 286 00:19:42,480 --> 00:19:45,140 I'll give this to you with no strings attached. 287 00:19:45,300 --> 00:19:47,120 You don't even have put my name on it. 288 00:19:47,280 --> 00:19:51,280 is something that the community can use and you can get your product up and running right 289 00:19:51,360 --> 00:19:55,140 away on CircuitPython. They had an Arduino driver for it, but they didn't have CircuitPython. 290 00:19:56,080 --> 00:20:00,720 The process was fairly difficult to go through because they hadn't done that before. 291 00:20:01,360 --> 00:20:06,920 And I can understand that you're trying to protect your own investments and you want to make sure 292 00:20:07,040 --> 00:20:11,200 that the code is going to be supportable and that you have somebody in place who's knowledgeable 293 00:20:11,500 --> 00:20:15,740 about it that can support it. And I think it was new for them to do something like that. 294 00:20:16,180 --> 00:20:20,740 But as a result, I still don't think that there's any documented process for doing that. 295 00:20:21,380 --> 00:20:25,420 And it would be a great thing to do because there's some really inventive stuff out there. 296 00:20:26,040 --> 00:20:26,160 Yeah. 297 00:20:26,300 --> 00:20:36,200 The example that brought this kind of concept up to me was there's these round LCDs that we were all playing with right during the pandemic, the GC9A01. 298 00:20:37,080 --> 00:20:42,680 Someone wrote a library for it that I quickly created a bunch of demos for because I was really in transfer these round LCDs. 299 00:20:43,380 --> 00:20:52,620 And then lately, just like I think maybe two weeks ago, Aidafruit is now selling a cool round LCD using the same chip. 300 00:20:53,080 --> 00:21:01,240 And they have now their own library for CircuitPython that is the exact library that's in the community bundle, which is copied over, I believe, with the author's permission. 301 00:21:02,200 --> 00:21:03,020 And I understand why they do that. 302 00:21:03,080 --> 00:21:03,880 They're selling this product. 303 00:21:04,020 --> 00:21:07,940 They want it to make sure they have a consistent code base for their demos and stuff. 304 00:21:08,360 --> 00:21:15,280 But I really wish that it would have moved to the Circa Python org in GitHub rather than the Adafruit org. 305 00:21:16,080 --> 00:21:17,480 Because there is a CircuitPython org. 306 00:21:17,740 --> 00:21:20,160 It's not where the CircuitPython source code lives yet. 307 00:21:20,580 --> 00:21:22,900 But to me, that's where it should go eventually. 308 00:21:24,260 --> 00:21:31,840 And having this process for graduating libraries to a third bundle, because currently there's the Adafruit bundle and there's the community bundle. 309 00:21:32,300 --> 00:21:37,940 But what if there was a third bundle that's like the official Circut Python community where maybe there's a problem? 310 00:21:38,020 --> 00:21:46,500 whereby the libraries are vetted for actual functionality, for continuing to work with when 311 00:21:46,620 --> 00:21:49,060 the versions of the CircuitPython changes. 312 00:21:49,340 --> 00:21:54,040 And like, you know, things that, as CircuitPython involves, the APIs, underline APIs for 313 00:21:54,260 --> 00:21:54,960 certain things change. 314 00:21:55,020 --> 00:21:57,860 And so some of these libraries that are in the bundle might not work anymore. 315 00:21:58,500 --> 00:22:02,340 And who currently goes through and makes sure of that in the community bundle, no one. 316 00:22:03,260 --> 00:22:05,780 It's like each person owns their own library, you know. 317 00:22:06,000 --> 00:22:20,900 But if there was a third entity, a third bundle that's sort of like these are vetted by the larger CircuitPython community, that would require organization and some organization body, not person body, to handle all that. 318 00:22:21,040 --> 00:22:23,480 And we don't have that yet, but we could. 319 00:22:24,120 --> 00:22:26,140 That's a fascinating idea. 320 00:22:27,260 --> 00:22:35,880 Thinking about CircuitPython as a community of its own, not just the aspects of it that are sponsored by 8 or 4. 321 00:22:35,920 --> 00:22:43,260 fruit. And it might also mean we could get t-shirts. Definitely. More CircuitPython merch, 322 00:22:43,420 --> 00:22:50,640 please. Yeah. Do you both use the MIT license for your libraries? I know that most of the 323 00:22:50,820 --> 00:22:55,180 Adafruit stuff is licensed under an MIT, which is very permissive, which would, you know, 324 00:22:55,360 --> 00:23:00,640 like you're saying, Tod, allow them to take a community library and just copy and paste it over to 325 00:23:00,740 --> 00:23:05,860 their own. Yeah, for me, I don't know. I think so. Like, I've, I have some 326 00:23:05,880 --> 00:23:07,920 issues. I'm a real open source 327 00:23:08,420 --> 00:23:09,780 sort of zealot sometimes. And so I've 328 00:23:09,900 --> 00:23:11,860 issues with the MIT license because it means that 329 00:23:12,080 --> 00:23:13,360 anybody could use your library for anything. 330 00:23:14,120 --> 00:23:15,780 And so, like, there are some libraries I've 331 00:23:15,880 --> 00:23:17,860 written, I think, that I have under different licensing because 332 00:23:18,060 --> 00:23:19,760 they're based on code or algorithms 333 00:23:20,760 --> 00:23:22,040 from someone 334 00:23:22,360 --> 00:23:23,840 else. And so I kind of try to 335 00:23:24,220 --> 00:23:25,800 carry forward that original license. 336 00:23:26,280 --> 00:23:27,860 But I'm looking at a couple of mine right now, and they 337 00:23:27,960 --> 00:23:29,740 have MIT license. So I think maybe I just 338 00:23:30,140 --> 00:23:31,900 that's what cookie cutter puts down by default 339 00:23:32,060 --> 00:23:33,340 and I just have to accept it to the default. 340 00:23:33,920 --> 00:23:35,840 And I usually use the MIT license to 341 00:23:35,860 --> 00:23:41,560 who my former career before I retired was working at a research laboratory where we protected 342 00:23:41,860 --> 00:23:44,740 intellectual property through all sorts of mechanisms. 343 00:23:45,340 --> 00:23:50,200 And when I came into the CircuitPython realm and looked at the licensing of that, 344 00:23:50,320 --> 00:23:52,500 wait, this is way too liberal for me. 345 00:23:52,720 --> 00:23:53,680 There's no way I can do this. 346 00:23:54,600 --> 00:24:01,180 After a couple of years of being instructed by a lot of folks in the open source community, 347 00:24:01,840 --> 00:24:05,120 I went completely the other way and now I'm very open source about things. 348 00:24:05,260 --> 00:24:08,080 MIT looks like a pretty good fit for the things that I'm doing. 349 00:24:08,700 --> 00:24:08,820 Yeah. 350 00:24:10,000 --> 00:24:12,540 Let's chat about some of the libraries you've both written. 351 00:24:13,300 --> 00:24:14,280 Jan, we'll start with you. 352 00:24:14,540 --> 00:24:16,900 PaletteFader is one I've recommended to a number of folks. 353 00:24:17,400 --> 00:24:18,660 What does Pallet Fader do? 354 00:24:19,520 --> 00:24:26,080 Well, Pallet Fader is the first element of a family of pallet tools that I put together. 355 00:24:26,480 --> 00:24:29,460 And Pallet tools, the palette is associated with graphics. 356 00:24:30,120 --> 00:24:32,420 So you have a graphics image you want to put on the screen, 357 00:24:33,040 --> 00:24:35,220 or you want to put it on a Matrix Portal or something. 358 00:24:35,580 --> 00:24:38,620 that's an RGB LED array. 359 00:24:39,620 --> 00:24:43,840 Pallet fader allows you to change the brightness of the palette. 360 00:24:44,300 --> 00:24:49,300 And that's suitable for, obviously I was talking before about having a photo transistor 361 00:24:49,420 --> 00:24:50,660 detect light in the room. 362 00:24:51,100 --> 00:24:56,380 I'm very sensitive about making sure that displays, the brightness of displays are controlled 363 00:24:57,200 --> 00:25:01,360 so that they match the ambient lighting in the area that you're working. 364 00:25:02,380 --> 00:25:08,200 So a pallet fader was first put together because you couldn't dim a matrix portal. 365 00:25:09,420 --> 00:25:13,020 The RGB LEDs there ran it, you had two brightnesses. 366 00:25:13,200 --> 00:25:14,900 They were either on or they were off. 367 00:25:15,320 --> 00:25:21,320 Or you had to code each LED color separately to control its brightness. 368 00:25:21,920 --> 00:25:26,620 So pallet fader was something that I put together that dealt with the palette of colors, 369 00:25:26,880 --> 00:25:31,980 all the colors on the display, and would scale them up and down based on the brightness level that I wanted. 370 00:25:32,060 --> 00:25:34,060 And it would do other things too. 371 00:25:34,520 --> 00:25:41,860 But the primary function was to make sure that you could control brightness on devices that didn't have a brightness control. 372 00:25:41,960 --> 00:25:43,280 Yeah, thank you so much for that. 373 00:25:43,440 --> 00:25:48,660 Because I fielded so many questions on like the Discord or Reddit or whatever, people asking, 374 00:25:49,080 --> 00:25:52,320 how do I dim this LED thing when I've got to set up as a matrix? 375 00:25:52,560 --> 00:25:56,160 And it's like, well, you go through each pixel and you change the color by hand. 376 00:25:56,780 --> 00:25:58,680 Or you use Palletator. 377 00:26:00,140 --> 00:26:01,980 The Palletator took me down a variety. 378 00:26:02,020 --> 00:26:06,960 rabbit hole that was kind of fun too dealing with other pallet issues because, you know, 379 00:26:07,540 --> 00:26:12,620 the palette that's associated with the bitmap image is something that you can manipulate. 380 00:26:13,380 --> 00:26:14,560 You can treat it like a list. 381 00:26:15,260 --> 00:26:18,320 So you can go in there and change the values of that list pretty easily. 382 00:26:18,820 --> 00:26:21,500 It lacked a couple of things that you could do with lists. 383 00:26:21,660 --> 00:26:28,040 One was slicing where you could just update a few values in the list and not all the values 384 00:26:28,140 --> 00:26:29,660 in the list by replacing the palette. 385 00:26:30,120 --> 00:26:35,340 So I built something called pallet slicer that came out of the pallet fader experience. 386 00:26:36,020 --> 00:26:40,800 And the last one I did in the palette zone was the palette filter. 387 00:26:41,380 --> 00:26:50,820 And palette filter looks for a color or colors that are close to that color and substitutes a new color for that one. 388 00:26:51,380 --> 00:26:52,100 So you can use that. 389 00:26:52,300 --> 00:26:54,960 It works great for green screen kinds of things. 390 00:26:55,480 --> 00:27:00,020 I use it in a weather display to slightly change the color. 391 00:27:00,040 --> 00:27:03,160 of the, it's a Star Trek L-Cars display. 392 00:27:03,960 --> 00:27:10,080 It slightly changes the color of it so that it's blue at night and it's yellow like on 393 00:27:10,360 --> 00:27:11,240 the next generation. 394 00:27:11,680 --> 00:27:17,540 The yellow screens that they used to have, without having to change the background graphics 395 00:27:17,660 --> 00:27:19,460 itself, I just went in and changed the palette. 396 00:27:20,160 --> 00:27:21,300 It was much simpler. 397 00:27:21,700 --> 00:27:26,140 So Palafator, yeah, that was, man, Palafator is the one that got me into the community 398 00:27:26,240 --> 00:27:26,920 library too. 399 00:27:27,320 --> 00:27:28,600 That was one of your first submissions? 400 00:27:29,000 --> 00:27:29,960 That was one of the first ones. 401 00:27:30,120 --> 00:27:35,180 I had another one called Range Slicer that was my absolute first, but PaletteFader was a close second. 402 00:27:36,100 --> 00:27:38,940 Tod, one of your libraries has my favorite name of a library. 403 00:27:39,140 --> 00:27:42,860 It's RU.Row Rotary I.O. Say that three times fast. 404 00:27:44,980 --> 00:27:45,940 What does that one do? 405 00:27:47,120 --> 00:27:59,980 So if you use rotary encoders in CircuitPython, you will most likely use the built-in library called Rotary I.O., which takes two pins, and those are the two pins that go to your rotary encoder, and it can determine whether. 406 00:28:00,000 --> 00:28:01,460 whether you're turning it left or right. 407 00:28:02,140 --> 00:28:10,000 The problem is on RP2040, to make rotary I.O efficient, it uses the PIO part of the RP20-chip, 408 00:28:10,680 --> 00:28:16,180 which requires the two pins to be next to each other, like GPO9 and GPIO10. 409 00:28:17,140 --> 00:28:27,720 But on some boards, like I think the QDPRPRP2040, there can be situations where two pins that are physically next to each other are actually not logically next to each other. 410 00:28:27,860 --> 00:28:31,400 So it's like there'll be GPI.O. 19 and GPO. 21 or something. 411 00:28:32,040 --> 00:28:35,480 And so you think you should be able to use Rotary I.O. for these two pins, but you cannot. 412 00:28:36,220 --> 00:28:42,180 And so Ro Rotary is a way of sort of faking like Rotary I.O. 413 00:28:42,500 --> 00:28:45,720 using the keypad functionality built into CircuitPython. 414 00:28:46,040 --> 00:28:56,000 So like, let's treat the two Rotary I.O. pins as fake buttons and then do some logic with that and pretend to be a rotary encoder to the user. 415 00:28:56,720 --> 00:28:58,720 So it's like, uh-oh, I can't use rotoreo. 416 00:29:01,260 --> 00:29:01,860 That's brilliant. 417 00:29:02,280 --> 00:29:06,820 And does it do with the debouncing and stuff for what the roterio would have normally? 418 00:29:07,620 --> 00:29:11,880 This is the benefit of using keypad is keypad does all the debouncing for you. 419 00:29:12,360 --> 00:29:15,900 So you just look at keypad events and turn those into like counterclockwise rotation 420 00:29:16,040 --> 00:29:17,800 or clockwise rotation events instead. 421 00:29:18,800 --> 00:29:19,380 That's super. 422 00:29:21,820 --> 00:29:24,840 Is there a hidden gem in the community bundle that you want to share with folks? 423 00:29:25,140 --> 00:29:29,500 Is there something that you use regularly that most people might not know about? 424 00:29:29,980 --> 00:29:31,140 Is there anything that comes to mind? 425 00:29:31,800 --> 00:29:33,200 I've got a few. 426 00:29:33,420 --> 00:29:36,680 And, you know, I would count some of mine in there that I use a lot. 427 00:29:37,280 --> 00:29:41,880 And some of those are things like temperature tools and where I do temperature conversions. 428 00:29:43,080 --> 00:29:53,480 And another one is daylight saving time adjuster so that it will automatically change daylight saving time based on the date that arrives with the time. 429 00:29:54,240 --> 00:29:59,660 But the one that changed my perspective was one that Jepler put together. 430 00:29:59,860 --> 00:30:07,000 It was called, let's see, Jepler's CircuitPython micro decimal or U-Decimal. 431 00:30:07,700 --> 00:30:13,820 And the micro-decimal is a, it's a CircuitPython library that is used, 432 00:30:14,380 --> 00:30:17,400 just like you would use a Python decimal library. 433 00:30:18,520 --> 00:30:23,500 And that library was incredibly important when I was working on a calculator. 434 00:30:24,240 --> 00:30:26,820 I was trying to emulate an HP35 calculator. 435 00:30:27,640 --> 00:30:31,300 And when you're dealing with floating point on a microprocessor 436 00:30:31,560 --> 00:30:32,780 and you're trying to get accuracy, 437 00:30:33,680 --> 00:30:36,660 when you're out to 20 digits or so, it's just not there. 438 00:30:37,420 --> 00:30:42,360 And emulating the HP35 that has 15 to 20 digits of accuracy 439 00:30:42,920 --> 00:30:45,620 was something I just couldn't do at a floating point. 440 00:30:45,780 --> 00:30:48,460 And using this microdecimal that Jepler put together, 441 00:30:49,140 --> 00:30:50,280 just saved the day. 442 00:30:50,620 --> 00:30:52,720 But the other advantage to that was, 443 00:30:53,280 --> 00:30:58,200 I found myself using it whenever I needed to do kind of pseudo-scientific work. 444 00:30:58,780 --> 00:31:03,140 So if I'm measuring something, I'm measuring the speed of a motor or something like that, 445 00:31:03,240 --> 00:31:08,960 or I'm looking for a period based on a frequency that I've measured, 446 00:31:09,540 --> 00:31:11,560 and I need X number of digits of accuracy, 447 00:31:11,720 --> 00:31:16,340 and I don't want to worry about floating points, binary rollover and roll under 448 00:31:16,680 --> 00:31:18,580 and averaging whatever happens there. 449 00:31:19,280 --> 00:31:23,120 U-Decimal really changed the game for me and thinking about those things. 450 00:31:23,120 --> 00:31:26,360 And I think that's something that I go to often. 451 00:31:27,080 --> 00:31:28,820 Well, let's just say I go to that often. 452 00:31:29,700 --> 00:31:36,320 For me, I think all of your palette tools, Jan, are super handy because one of the fun things 453 00:31:36,360 --> 00:31:41,640 like to do with CircuitPython displays is just muck about with the palette, which really 454 00:31:41,780 --> 00:31:47,000 brings me back to sort of the old way that, like, say, the Atari's and stuff used to do some 455 00:31:47,040 --> 00:31:47,640 of their animations. 456 00:31:47,940 --> 00:31:53,100 They just would have cleverly arranged palettes, and they would kind of move the colors within 457 00:31:53,140 --> 00:31:57,960 palette, and it would cause these like waterfall effects or cool banded color effects. 458 00:31:58,780 --> 00:32:03,740 And by having things that let you operate on pallets inside your CircuitPython code, you can do 459 00:32:04,020 --> 00:32:05,220 kind of fun stuff with that. 460 00:32:06,420 --> 00:32:12,440 But some of the other ones that I am a fan of is, of course, the GC9A01 round LCD, 461 00:32:13,160 --> 00:32:15,220 which is just so handy for the round LCDs. 462 00:32:16,120 --> 00:32:21,300 There's a one by, I forget it is real name, but it handles like L. Peckinan. 463 00:32:21,580 --> 00:32:24,940 but the Tommel library that lets you read and write Tommel files, 464 00:32:25,540 --> 00:32:29,240 which Tommel is yet another little configuration language 465 00:32:29,520 --> 00:32:34,380 that CircuitPython uses for storing things like the Wi-Fi password and SSID name. 466 00:32:35,300 --> 00:32:38,140 There used to be, it wasn't in the bundle, 467 00:32:38,280 --> 00:32:42,020 but there was this non-blocking HTTP server library. 468 00:32:42,180 --> 00:32:45,640 I used a lot called Ampule that this was like four years ago, 469 00:32:45,860 --> 00:32:49,520 but now there's one in the library called Byplane that seems to be fairly similar. 470 00:32:50,620 --> 00:32:56,200 I've stopped using Ampul because the ATA Fruit HD-HDP server has gotten non-blocking 471 00:32:56,300 --> 00:32:57,700 and has gotten better over time. 472 00:32:58,160 --> 00:32:59,900 Dan H put a lot of work into it a couple years ago. 473 00:33:01,100 --> 00:33:05,140 But yeah, I used to use a non-Ata-Fruit HTTP library all the time. 474 00:33:05,280 --> 00:33:08,720 Oh, wait, wait, wait, wait, wait, wait, wait, wait, wait, wait, one more. 475 00:33:09,320 --> 00:33:11,760 Also, Jan's punk console emulator. 476 00:33:12,720 --> 00:33:14,380 I was wondering if that would come up. 477 00:33:17,200 --> 00:33:20,280 All right, so they're in sort of hacky, 478 00:33:20,420 --> 00:33:25,180 music world, there's this thing called the Atari Punk Console, which is like two 555 chips that have been 479 00:33:25,500 --> 00:33:29,920 turned into little oscillators that interact with each other. And for some reason, it's called the 480 00:33:30,000 --> 00:33:34,480 Atari Punk console. I don't know why. But hundreds of them, thousands of them have been made, 481 00:33:34,900 --> 00:33:40,240 and Jan made a little Circa Python library that sort of emulates that using the PWM functionality 482 00:33:40,760 --> 00:33:44,900 of Circut Python. And it can work in stereo. 483 00:33:46,060 --> 00:33:47,820 Oh. Yeah, so think about that. 484 00:33:49,720 --> 00:33:59,220 Yeah, coming from a hardware background, the Atari Punk console was something I made many of with any 555s and 556s. 485 00:34:00,080 --> 00:34:04,300 And it was always on my list of things to do. 486 00:34:04,580 --> 00:34:06,240 It's got to be able to emulate this. 487 00:34:06,940 --> 00:34:09,500 And I had a grand time putting that together. 488 00:34:09,639 --> 00:34:10,440 It was a lot of fun. 489 00:34:11,840 --> 00:34:12,020 Excellent. 490 00:34:12,460 --> 00:34:12,879 So thank you. 491 00:34:12,960 --> 00:34:14,300 I'm glad you appreciated that. 492 00:34:14,860 --> 00:34:16,179 Thanks for the comment. 493 00:34:17,620 --> 00:34:18,659 Those are all great choices. 494 00:34:18,740 --> 00:34:21,000 and I hope folks who are listening try some of them out. 495 00:34:22,020 --> 00:34:24,320 Jan and Tod, thanks so much for making time and coming on the show. 496 00:34:24,760 --> 00:34:25,800 Oh, you're welcome. Thanks. 497 00:34:27,040 --> 00:34:28,960 Thank you for listening to the CircuitPython Show. 498 00:34:29,500 --> 00:34:32,460 For show notes and transcripts, visit www.circuitpythonshow.com. 499 00:34:34,080 --> 00:34:37,560 Thank you to both Jan and Tod for coming back on the show to share their experiences 500 00:34:37,820 --> 00:34:39,879 writing code for CircuitPython's community bundle. 501 00:34:40,580 --> 00:34:43,040 Check out the show notes for links to their GitHub repositories. 502 00:34:43,700 --> 00:34:45,560 Until next time, stay positive.