<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jake Fenton</title>
    <description>The latest articles on DEV Community by Jake Fenton (@bocajnotnef).</description>
    <link>https://dev.to/bocajnotnef</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F48407%2Fe6a63707-2222-41d3-9114-1dc07f63aa2d.png</url>
      <title>DEV Community: Jake Fenton</title>
      <link>https://dev.to/bocajnotnef</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bocajnotnef"/>
    <language>en</language>
    <item>
      <title>Codemash 2019 Reading List</title>
      <dc:creator>Jake Fenton</dc:creator>
      <pubDate>Tue, 15 Jan 2019 13:39:52 +0000</pubDate>
      <link>https://dev.to/bocajnotnef/codemash-2019-reading-list-32jh</link>
      <guid>https://dev.to/bocajnotnef/codemash-2019-reading-list-32jh</guid>
      <description>

&lt;p&gt;Last updated: 2019-01-14 4pm EST&lt;/p&gt;

&lt;p&gt;Hello! This is a compiled list of all the books mentioned during talks given at Codemash 2019.&lt;/p&gt;

&lt;p&gt;This list has been compiled from slide decks linked from &lt;a href="https://docs.google.com/spreadsheets/d/1omYTaGvLAbkJ-AGphM-WO90iE5O5s5-1dG2srKbNFYo/edit#gid=0"&gt;this google sheet&lt;/a&gt; and from my own notes on given talks.&lt;/p&gt;

&lt;p&gt;I apologize if I missed books from your talk or made an error in copying them down--Please let me know and I'll update the list or make corrections!&lt;/p&gt;

&lt;p&gt;The list should be in alphabetical order by talk title. Nearly all the links are for purchasing the books off of Amazon, unless they weren't available or were free through other sources.&lt;/p&gt;

&lt;p&gt;I did not link additional resources--papers, news articles, YouTube videos, etc.&lt;/p&gt;

&lt;p&gt;Also, fair warning, a couple of the books in talks I went to were mentioned in jest. I tried to note where this was the case, but I didn't attend other talks, so it's possible the same happened elsewhere.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Better Faster Pipeline for Software Delivery
&lt;/h2&gt;

&lt;h3&gt;
  
  
  "Lean Thinking" - James P. Womack, Daniel T. Jones &lt;a href="https://www.amazon.com/Lean-Thinking-Corporation-Revised-Updated/dp/0743249275"&gt;amazon link&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Expanded, updated, and more relevant than ever, this bestselling business classic by two internationally renowned management analysts describes a business system for the twenty-first century that supersedes the mass production system of Ford, the financial control system of Sloan, and the strategic system of Welch and GE. It is based on the Toyota (lean) model, which combines operational excellence with value-based strategies to produce steady growth through a wide range of economic conditions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  "The Phoenix Project: A Novel about IT, DevOps, and Helping your Business Win" - Gene Kim, Kevin Behr, George Spafford &lt;a href="https://www.amazon.com/Phoenix-Project-DevOps-Helping-Business/dp/0988262592"&gt;amazon link&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Note:&lt;/strong&gt; fiction, but a good example of how to turn a team (or company) onto  using lean principles&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Avoiding Landmines: A Tech LEader's guide for the Critical Decisions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  "Thinking Fast and Slow" -- Daniel Kahneman &lt;a href="https://www.amazon.com/Thinking-Fast-Slow-Daniel-Kahneman/dp/0374533555/"&gt;amazon link&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;"...a groundbreaking tour of the mind and explains the two systems that drive the way we think. System 1 is fast, intuitive, and emotional; System 2 is slower, more deliberative, and more logical."&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  "Drive: The Surprising Truth About What Motivates Us" - Daniel H. Pink &lt;a href="https://www.amazon.com/Drive-Surprising-Truth-About-Motivates/dp/1594484805"&gt;amazon link&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;"...the secret to high performance and satisfaction-at work, at school, and at home—is the deeply human need to direct our own lives, to learn and create new things, and to do better by ourselves and our world."&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  "Cultues and Organizations: Software of the Mind" - Geert Hofstede, Gert Jan Hofstede, Michael Minkov &lt;a href="https://www.amazon.com/Cultures-Organizations-Software-Mind-Third/dp/0071664181"&gt;amazon link&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;"...&lt;em&gt;Cultures and Organizations&lt;/em&gt; examines what drives people apart―when cooperation is so clearly in everyone’s interest. "&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  "The Advantage: Why Organizational Health Trumps Everything Else in Business" - Patric M. Lencioni &lt;a href=""&gt;amazon link&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;"...Patrick Lencioni, argues that the seminal difference between successful companies and mediocre ones has little to do with what they know and how smart they are and more to do with how healthy they are."&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Better Names for Better Code
&lt;/h2&gt;

&lt;h3&gt;
  
  
  "Clean Code: A Handbook of Agile Software Craftsmanship" -- Robert C. Martin &lt;a href="https://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882"&gt;amazon link&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Even bad code can function. But if code isn’t clean, it can bring a development organization to its knees. Every year, countless hours and significant resources are lost because of poorly written code. But it doesn’t have to be that way.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  "Structure and Interpretation of Computer Programs" - Harold Abelson, Gerald Jay Sussman, Julie Sussman &lt;a href="https://www.amazon.com/Structure-Interpretation-Computer-Programs-Engineering/dp/0262510871"&gt;amazon link&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;This long-awaited revision contains changes throughout the text. There are new implementations of most of the major programming systems in the book, including the interpreters and compilers, and the authors have incorporated many small changes that reflect their experience teaching the course at MIT since the first edition was published. A new theme has been introduced that emphasizes the central role played by different approaches to dealing with time in computational models: objects with state, concurrent programming, functional programming and lazy evaluation, and nondeterministic programming. &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Code Reviews?! That's a great idea!
&lt;/h2&gt;

&lt;h3&gt;
  
  
  "Code Complete: A practical handbook of Software Construction" -- Steve McConnel &lt;a href="https://www.amazon.com/Code-Complete-Practical-Handbook-Construction/dp/0735619670"&gt;amazon link&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;quoted in a talk:&lt;/strong&gt;* "effectiveness of code review for determining faults in software is between 30% and 35% more effective than standard unit testing"&lt;/li&gt;
&lt;li&gt;"Widely considered one of the best practical guides to programming, Steve McConnell’s original CODE COMPLETE has been helping developers write better software for more than a decade. Now this classic book has been fully updated and revised with leading-edge practices—and hundreds of new code samples—illustrating the art and science of software construction."&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Don't Rewrite, React!
&lt;/h2&gt;

&lt;h3&gt;
  
  
  "Learning React" -- Kirupa Chinnathambi &lt;a href="https://www.amazon.com/Learning-React-Kirupa-Chinnathambi/dp/0134546318"&gt;amazon link&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;"A hands-on guide to building maintainable, high-performing web application user interfaces using the React JavaScript library"&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  "React and React Native" -- Adam Boduch &lt;a href="https://www.amazon.com/React-Native-Adam-Boduch/dp/1786465655"&gt;amazon link&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;"Build React and React Native applications using familiar component concepts"&lt;/li&gt;
&lt;li&gt;"Dive deep into each platform, from routing in React to creating native mobile applications that can run offline"&lt;/li&gt;
&lt;li&gt;"Use Facebook's Relay, React and GraphQL technologies, to create a unified architecture that powers both web and native applications"&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Embrace your Legacy... Code!
&lt;/h2&gt;

&lt;h3&gt;
  
  
  "Working Effectively with Legacy Code" -- Michael C. Feathers &lt;a href="https://www.amazon.com/Working-Effectively-Legacy-Michael-Feathers/dp/0131177052"&gt;amazon link&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;"In this book, Michael Feathers offers start-to-finish strategies for working more effectively with large, untested legacy code bases. This book draws on material Michael created for his own renowned Object Mentor seminars: techniques Michael has used in mentoring to help hundreds of developers, technical managers, and testers bring their legacy systems under control.
This book also includes a catalog of twenty-four dependency-breaking techniques that help you work with program elements in isolation and make safer changes."&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  "Refactoring: Improving the Design of Existing Code" -- Martin Fowler, Kent Beck, John Brant, William Opdyke, Don Roberts, Erich Gamma &lt;a href="https://www.amazon.com/Refactoring-Improving-Design-Existing-Code/dp/0201485672"&gt;amazon link&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;For several years, expert-level object programmers have employed a growing collection of techniques to improve the structural integrity and performance of such existing software programs. Referred to as refactoring, these practices have remained in the domain of experts because no attempt has been made to transcribe the lore into a form that all developers could use. . .until now. In Refactoring: Improving the Design of Existing Software, renowned object technology mentor Martin Fowler breaks new ground, demystifying these master practices and demonstrating how software practitioners can realize the significant benefits of this new process.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Getting Unstuck
&lt;/h2&gt;

&lt;h3&gt;
  
  
  "Creativity: Flow and the Psychology of Discovery and Intervention" - Mihaly Csikszentmihalyi &lt;a href="https://www.amazon.com/Creativity-Flow-Psychology-Discovery-Invention/dp/0062283251"&gt;amazon link&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;"Drawing on nearly one hundred interviews with exceptional people, from biologists and physicists, to politicians and business leaders, to poets and artists, as well as his thirty years of research on the subject, Csikszentmihalyi uses his famous flow theory to explore the creative process."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Note:&lt;/strong&gt; At least three talks have referenced this book&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  "The Art of Thought" -- Grahm Wallas &lt;a href="https://www.amazon.com/Art-Thought-Graham-Wallas/dp/1910146056"&gt;amazon link&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Amazon Note:&lt;/strong&gt; Available at a lower price from other sellers that may not offer free Prime shipping. &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Keeping Up With Technology
&lt;/h2&gt;

&lt;h3&gt;
  
  
  "Thinking in Systems" -- Donella H. Meadows &lt;a href="https://www.amazon.com/Thinking-Systems-Donella-H-Meadows/dp/1603580557"&gt;amazon link&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Thinking in Systems, is a concise and crucial book offering insight for problem solving on scales ranging from the personal to the global. Edited by the Sustainability Institute’s Diana Wright, this essential primer brings systems thinking out of the realm of computers and equations and into the tangible world, showing readers how to develop the systems-thinking skills that thought leaders across the globe consider critical for 21st-century life.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  "Win Friends and Influence People" -- Dale Carnegie &lt;a href="https://www.amazon.com/How-Win-Friends-Influence-People/dp/0671027034"&gt;amazon link&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Amazon Note:&lt;/strong&gt; Available at a lower price from other sellers that may not offer free Prime shipping. &lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Dale Carnegie’s rock-solid, time-tested advice has carried countless people up the ladder of success in their business and personal lives. One of the most groundbreaking and timeless bestsellers of all time, How to Win Friends &amp;amp; Influence People will teach you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Six ways to make people like you&lt;/li&gt;
&lt;li&gt;Twelve ways to win people to your way of thinking&lt;/li&gt;
&lt;li&gt;Nine ways to change people without arousing resentment &lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  "How to Have Confidence and Power in Dealing With People" -- Les Giblin &lt;a href="https://www.amazon.com/Have-Confidence-Power-Dealing-People-ebook/dp/B01CXHESLE"&gt;amazon link&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Les Giblin, a recognized expert in the field of human relations, has devised a method for dealing with people that can be used when relating with anyone – parents, teachers, bosses, employees, friends, acquaintances, even strangers. Giblin shows step by step how to get what you want at any time and in ways that leave you feeling good about yourself. Moreover, the people who have given you want you want wind up feeling good about themselves, too. The result? Nobody gets shortchanged. It’s a win-win situation.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  "Crucial Conversations: Tools for talking when the stakes are high" -- Kerry Patterson, Joseph Grenny, Ron McMillan, Al Switzler &lt;a href="https://www.amazon.com/Crucial-Conversations-Talking-Stakes-Second-dp-0071771328/dp/0071771328/"&gt;amazon link&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The first edition of Crucial Conversations exploded onto the scene and revolutionized the way millions of people communicate when stakes are high. This new edition gives you the tools to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Prepare for high-stakes situations&lt;/li&gt;
&lt;li&gt;Transform anger and hurt feelings into powerful dialogue&lt;/li&gt;
&lt;li&gt;Make it safe to talk about almost anything&lt;/li&gt;
&lt;li&gt;Be persuasive, not abrasive&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Leadership Guide for the Reluctant Leader
&lt;/h2&gt;

&lt;h3&gt;
  
  
  "The Ideal Team Player: How to Recognize and Cultivate the Three Essential Virtues" -- Patrick M Lencioni &lt;a href="https://www.amazon.com/Ideal-Team-Player-Recognize-Cultivate-ebook/dp/B01B6AEJJ0"&gt;amazon link&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;In his classic book, The Five Dysfunctions of a Team, Patrick Lencioni laid out a groundbreaking approach for tackling the perilous group behaviors that destroy teamwork. Here he turns his focus to the individual, revealing the three indispensable virtues of an ideal team player.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  "StrengthsFinder 2.0" -- Tom Rath &lt;a href="https://www.amazon.com/StrengthsFinder-2-0-Tom-Rath/dp/159562015X"&gt;amazon link&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;In its latest national bestseller, StrengthsFinder 2.0, Gallup unveils the new and improved version of its popular assessment, language of 34 themes, and much more (see below for details). While you can read this book in one sitting, you'll use it as a reference for decades. &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Learning the Three Types of Microservices
&lt;/h2&gt;

&lt;h3&gt;
  
  
  "Release It: Design and Deploy Production Ready Software" - Michael T. Nygard &lt;a href="https://www.amazon.com/Release-Production-Ready-Software-Pragmatic-Programmers-ebook/dp/B00A32NXZO"&gt;amazon link&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt; If you're a developer and don't want to be on call for 3AM for the rest of your life, this book will help. In Release It!, Michael T. Nygard shows you how to design and architect your application for the harsh realities it will face. You'll learn how to design your application for maximum uptime, performance, and return on investment.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Management 101
&lt;/h2&gt;

&lt;h3&gt;
  
  
  "Rules of the Red Rubber Ball" -- Kevin Carroll &lt;a href="https://www.amazon.com/Rules-Red-Rubber-Ball-Sustain/dp/1933060026"&gt;amazon link&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;With simple but delightful storytelling, Kevin Carroll channels his childhood passion for sport and play into a universally appealing blueprint for life. Drawing wisdom from the playgrounds of his youth, where he spent hour upon hour sharpening his body and his mind, Carroll shares with readers his Rules of the Red Rubber Ball - how to achieve maximum human potential through the power of passion and creativity. Finding your own -red rubber ball+ and chasing it to your heart+s content, he argues, is the surest route to peace, prosperity, and happiness. Over the years as an athletic trainer and public speaker, Carroll has transformed his philosophy into seven simple rules that any successful leader will endorse: 
1) Commit to it 
2) Seek out encouragers 
3) Work out your creative muscle 
4)  Prepare to shine 
5)  Speak up 
6) Expect the unexpected 
7) Maximize the day With an award-winning design and color photos throughout&lt;/li&gt;
&lt;li&gt;Rules of the Red Rubber Ball will inspire the child in everyone for generations to come.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Modern Identity Management
&lt;/h2&gt;

&lt;h3&gt;
  
  
  "JWT Handbook" -- Sebastian Peyrott &lt;a href="https://auth0.com/resources/ebooks/jwt-handbook"&gt;free ebook link&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Ever wondered how JWT came to be and what problems it was designed to tackle?
Are you curious about the plethora of algorithms available for signing and encrypting JWTs? Or are you interested in getting up-to-speed with JWTs as soon as possible? Then this handbook is for you.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Agile DBA
&lt;/h2&gt;

&lt;h3&gt;
  
  
  "The Dev Ops Handbook" -- Gene Kim, John Willis, Jez Humble, John Allspaw &lt;a href="https://www.amazon.com/DevOps-Handbook-World-Class-Reliability-Organizations/dp/1942788002"&gt;amazon link&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Following in the footsteps of The Phoenix Project, The DevOps Handbook shows leaders how to replicate these incredible outcomes, by showing how to integrate Product Management, Development, QA, IT Operations, and Information Security to elevate your company and win in the marketplace.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  "The Phoenix Project: A Novel about IT, DevOps, and Helping your Business Win" - Gene Kim, Kevin Behr, George Spafford &lt;a href="https://www.amazon.com/Phoenix-Project-DevOps-Helping-Business/dp/0988262592"&gt;amazon link&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Note:&lt;/strong&gt; fiction, but a good example of how to turn a team (or company) onto  using lean principles
## The Two Question Programming Interview&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  "How would you move mount fuji?" -- William Poundstone &lt;a href="https://www.amazon.com/How-Would-Move-Mount-Fuji/dp/0316778494"&gt;amazon link&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;note:&lt;/strong&gt; this book was a tongue-in-cheek mention for ways to &lt;em&gt;not&lt;/em&gt; ask programming questions. Direct quote: "[the problems from this book] are great for dinner parties, but not really for programming interviews. Instead of teaching to think outside-the-box, they teach you to think inside of a slightly-larger-but-very-specific box."&lt;/li&gt;
&lt;li&gt;"William Poundstone reveals the toughest questions used at Microsoft and other Fortune 500 companies -- and supplies the answers."&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  "Never Split the Difference: Negotiating As If Your Life Depended On It" - Chris Voss &lt;a href="https://www.amazon.com/Never-Split-Difference-Negotiating-Depended-ebook/dp/B014DUR7L2"&gt;amazon link&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;" Reaching the pinnacle of his profession, he became the FBI’s lead international kidnapping negotiator. Never Split the Difference takes you inside the world of high-stakes negotiations and into Voss’s head, revealing the skills that helped him and his colleagues succeed where it mattered most: saving lives. In this practical guide, he shares the nine effective principles—counterintuitive tactics and strategies—you too can use to become more persuasive in both your professional and personal life."&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  "Smart and Gets Things Done: Joel Spolsky's concise Guide to Finding The Best Technical Talent" -- Avram Joel Spolsky &lt;a href="https://www.amazon.com/Smart-Gets-Things-Done-Technical/dp/1590598385"&gt;amazon link&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;"The secret to success for any software company then is to hire the good programmers. But how to do that? In Joel on Hiring, Joel Spolsky draws from his experience both at Microsoft and running his own successful software company based in New York City. He writes humorously, but seriously about his methods for sorting resumes, for finding great candidates, and for interviewing, in person and by phone."&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  User-story driven thread modeling
&lt;/h2&gt;

&lt;h3&gt;
  
  
  "Threat Modeling: Designing for Security" -- Adam Shostack &lt;a href="https://www.amazon.com/Threat-Modeling-Designing-Adam-Shostack/dp/1118809998"&gt;amazon link&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Adam Shostack is responsible for security development lifecycle threat modeling at Microsoft and is one of a handful of threat modeling experts in the world. Now, he is sharing his considerable expertise into this unique book. With pages of specific actionable advice, he details how to build better security into the design of systems, software, or services from the outset. You'll explore various threat modeling approaches, find out how to test your designs against threats, and learn effective ways to address threats that have been validated at Microsoft and other top companies.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  "Securing Systems: Applied Architecture and Threat Models" -- Brook S.E. Schoenfield &lt;a href="https://www.amazon.com/Securing-Systems-Applied-Security-Architecture/dp/1482233975"&gt;amazon link&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Internet attack on computer systems is pervasive. It can take from less than a minute to as much as eight hours for an unprotected machine connected to the Internet to be completely compromised. It is the information security architect’s job to prevent attacks by securing computer systems. This book describes both the process and the practice of assessing a computer system’s existing information security posture. Detailing the time-tested practices of experienced security architects, it explains how to deliver the right security at the right time in the implementation lifecycle.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  "Risk Centric Threat Modeling: Process for Attack Simulation and Threat Analysis" -- Marco Morana and Tony UcadeVelez &lt;a href="https://www.amazon.com/Risk-Centric-Threat-Modeling-Simulation/dp/0470500964"&gt;amazon link&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;This book introduces the Process for Attack Simulation &amp;amp; Threat Analysis (PASTA) threat modeling methodology. It provides an introduction to various types of application threat modeling and introduces a risk-centric methodology aimed at applying security countermeasures that are commensurate to the possible impact that could be sustained from defined threat models, vulnerabilities, weaknesses, and attack patterns.
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  "Measuring and managing Information Risk: A FAIR Approach" -- Jack Jones and Jack Freund &lt;a href="https://www.amazon.com/Measuring-Managing-Information-Risk-Approach/dp/0124202314"&gt;amazon link&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Using the factor analysis of information risk (FAIR) methodology developed over ten years and adopted by corporations worldwide, Measuring and Managing Information Risk provides a proven and credible framework for understanding, measuring, and analyzing information risk of any size or complexity. Intended for organizations that need to either build a risk management program from the ground up or strengthen an existing one, this book provides a unique and fresh perspective on how to do a basic quantitative risk analysis. Covering such key areas as risk theory, risk calculation, scenario modeling, and communicating risk within the organization, Measuring and Managing Information Risk helps managers make better business decisions by understanding their organizational risk.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What are Observables and why should I care?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  "Build Reactive Websites with RxJS" -- Randall Koutnik &lt;a href="https://pragprog.com/book/rkrxjs/build-reactive-websites-with-rxjs"&gt;the pragmatic bookshelf link&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Upgrade your skill set, succeed at work, and above all, avoid the many headaches that come with modern front-end development. Simplify your codebase with hands-on examples pulled from real-life applications. Master the mysteries of asynchronous state management, detangle puzzling race conditions, and send spaceships soaring through the cosmos. When you finish this book, you’ll be able to tame the wild codebeasts before they ever get a chance to wreck your day.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What Every Beginning Developer Should Know
&lt;/h2&gt;

&lt;h3&gt;
  
  
  "Code Complete: A practical handbook of Software Construction" -- Steve McConnel &lt;a href="https://www.amazon.com/Code-Complete-Practical-Handbook-Construction/dp/0735619670"&gt;amazon link&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;quoted in a talk:&lt;/strong&gt;* "effectiveness of code review for determining faults in software is between 30% and 35% more effective than standard unit testing"&lt;/li&gt;
&lt;li&gt;"Widely considered one of the best practical guides to programming, Steve McConnell’s original CODE COMPLETE has been helping developers write better software for more than a decade. Now this classic book has been fully updated and revised with leading-edge practices—and hundreds of new code samples—illustrating the art and science of software construction."&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  "The Pragmatic Programmer" -- Andrew Hunt, David Thomas &lt;a href="https://www.amazon.com/Pragmatic-Programmer-Journeyman-Master/dp/020161622X"&gt;amazon link&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The Pragmatic Programmer cuts through the increasing specialization and technicalities of modern software development to examine the core process--taking a requirement and producing working, maintainable code that delights its users. It covers topics ranging from personal responsibility and career development to architectural techniques for keeping your code flexible and easy to adapt and reuse.&lt;/li&gt;
&lt;/ul&gt;


</description>
      <category>books</category>
      <category>readinglist</category>
      <category>codemash</category>
      <category>conferences</category>
    </item>
    <item>
      <title>Receiving data from ESP8266 sensors</title>
      <dc:creator>Jake Fenton</dc:creator>
      <pubDate>Wed, 25 Apr 2018 05:00:00 +0000</pubDate>
      <link>https://dev.to/bocajnotnef/receiving-data-from-esp8266-sensors-3n5e</link>
      <guid>https://dev.to/bocajnotnef/receiving-data-from-esp8266-sensors-3n5e</guid>
      <description>&lt;p&gt;Right, so &lt;a href="https://dev.to/bocajnotnef/intro-to-working-with-with-esp8266-2cf-temp-slug-5490487"&gt;last time&lt;/a&gt; I walked through how I have programmed and wired some ESP8266 microcontrollers to collect temperature, humidity and soil moisture data and beam that data to a specified address on the network.&lt;/p&gt;

&lt;p&gt;In this post, I'll walk through the code to run a server on something like a laptop or a raspberry pi to collect the incoming data and write it to a sqlite3 database for later analysis.&lt;/p&gt;

&lt;p&gt;This post will cover topics like threading, more advanced socket management, and interfacing with a database from Python.&lt;/p&gt;

&lt;p&gt;The full, versioned code is available &lt;a href="https://github.com/bocajnotnef/microcontrollers/blob/14747f88963147118de87178cdc213282cf47450/greenhouse/server.py"&gt;on Github&lt;/a&gt;. Note that link is fixed and will not update as I improve--for that, go &lt;a href="https://github.com/bocajnotnef/microcontrollers"&gt;Here&lt;/a&gt; and check out the Greenhouses project.&lt;/p&gt;

&lt;p&gt;I'll be pulling snippets from that code into this post, but to see it all in context you should look at the link.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quick Rehash
&lt;/h2&gt;

&lt;p&gt;So, remember, my goal for this project is to have a fleet of environmental sensors deployed throughout a greenhouse to sample data and send it to a central location where I'll make control decisions (e.g., turn on the heater, open a vent, water tray A, etc). We need our server architecture to support multiple sensors simultaneously, as well as collating the every-two-second readings into an average over a minute or so.&lt;/p&gt;

&lt;h1&gt;
  
  
  Step One: Get The Data Off the Network
&lt;/h1&gt;

&lt;p&gt;For a moment, let's pretend we're only expecting a single client sensor to talk to us. We'll get to dealing with multiple sensors later, but then we have to deal with threads and locking and it's a gigantic mess.&lt;/p&gt;

&lt;p&gt;So for now, one sensor.&lt;/p&gt;

&lt;h2&gt;
  
  
  Aside: Server socket programming
&lt;/h2&gt;

&lt;p&gt;When you're a server, you generally have one socket/port open to listen for incoming clients--like a web server, listening on port 80 for new clients. The tricky thing is you don't want to do your primary communication with your clients on that socket, or you won't be able to use it to listen for more incoming clients.&lt;/p&gt;

&lt;p&gt;Imagine a system named Bob goes to Google and asks to download some gigantic file, and Google responds with that file on the same socket it uses to accept new client connections. Then you go to Google, but can't get through because the 'line is busy' as Google offloads the file onto Bob, which takes forever--and that entire time, you can't talk to Google.&lt;/p&gt;

&lt;p&gt;So, you need one socket on the 'public' port to initialize the connection, and then another socket to actually handle the communication on--kind of like an operator at a business taking incoming calls and then routing them to different lines. Kind of.&lt;/p&gt;

&lt;h2&gt;
  
  
  Back to the network...
&lt;/h2&gt;

&lt;p&gt;So, we have a bunch of ESP8226s trying to open connections to a fixed IP and port--I'm going to say, arbitrarily, it's IP 192.168.1.5 and port 5555. It doesn't really matter, so long as the server and the microcontrollers agree and the port number is somewhere between 2048 and 60666 or so. (I'm guessing on those numbers, you may want to look them up).&lt;/p&gt;

&lt;p&gt;Your server needs to listen on that address--the IP/port combination--for incoming connections. This is fairly easy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;serversocket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AF_INET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SOCK_STREAM&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;serversocket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="s"&gt;"192.168.1.5"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5555&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;serversocket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Walking through this:&lt;/p&gt;

&lt;p&gt;First we're creating a socket with some attributes. This is a socket of the &lt;code&gt;AF_INET&lt;/code&gt; family, which basically just means it's going to talk to the Internet (instead of another process on your system or some weird other networking protocol). This mostly just determines how the socket works under the hood, as well as the type of address we're going to give it.&lt;/p&gt;

&lt;p&gt;This is also a socket of the &lt;code&gt;SOCK_STREAM&lt;/code&gt; type, which really just means the socket will have an internal buffer so we can 'stream' the data at a useful rate to ourselves.&lt;/p&gt;

&lt;p&gt;Then, we bind the socket to an address. &lt;strong&gt;Note:&lt;/strong&gt; If you run into difficulty with that line, make sure the IP you have there matches the IP of the system you're using. If they mismatch, you'll get an exception here (since you're trying to bind to an address you don't actually have).&lt;/p&gt;

&lt;p&gt;After that, we set the socket to 'listen' mode.&lt;/p&gt;

&lt;p&gt;With me so far?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clientsocket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;serversocket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;accept&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alright--so now, we're saying "Hey, socket, listen for a new connection and when you get one, hand me a socket to talk to that new connection and let me know what the address is." This is a &lt;em&gt;blocking call&lt;/em&gt;, which means our program will now stop until the new connection comes in. Obviously, this makes it rather complicated to do any sort of data processing while we just sit here and wait--but we'll fix that later.&lt;/p&gt;

&lt;p&gt;If you're playing with this alongside a running microcontroller what you should see is the program launch and then hang as it waits for the incoming socket connection--if you're using my ESP8266 code it'll blink steadily as it acquires the wifi connection, then it'll blink more angrily as it makes the socket connection and then it should be solid blue with an intermittent blink as it writes to the socket.&lt;/p&gt;

&lt;p&gt;Of course, we aren't actually reading any data from the socket yet! Let's fix that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nb"&gt;buffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;

&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;clientsocket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;recv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;datastr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;buffer&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'utf-8'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;split&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datastr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;buffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, the workhouse here is the &lt;code&gt;clientsocket.recv(128)&lt;/code&gt; call. That asks for 128 bytes of data from the socket--this is also a blocking call, meaning execution will halt until we get the 128 bytes of data. When we get the data, we decode it from just a bunch of bytes into a string and slap it onto a buffer.&lt;/p&gt;

&lt;p&gt;The buffer is necessary because 128 bytes might not be exactly the length of a single 'record' sent from the ESP8266--you may have all of record A and half of record B. In our 'protocol', newlines are used as boundaries between records, which means we have an easy way of telling when we have an entire record.&lt;/p&gt;

&lt;p&gt;So, we add the data we've received to the buffer (in case we just got the second half of record B) and then we split the buffer on newlines, to separate the records. We put the last record from the split, which may be a partial, and shove it back in the buffer. Then we print the rest of the records (excluding the last one).&lt;/p&gt;

&lt;p&gt;With this, you should be able to see the incoming data from a single ESP8266 sensor! Woo!&lt;/p&gt;

&lt;p&gt;Now we need to work on scaling to multiple connections.&lt;/p&gt;

&lt;h1&gt;
  
  
  Step Two: Threading the Connections
&lt;/h1&gt;

&lt;p&gt;As I've mentioned a couple times we're making use of some calls that block execution, making our program halt until some outside thing happens. That makes it hard to scale to large numbers of sensors, so we're going to have to introduce some threading.&lt;/p&gt;

&lt;p&gt;If you aren't familiar, threading is a way for a single program to do lots of things at the same time--multiple 'threads of execution.' A single &lt;em&gt;process&lt;/em&gt; can have multiple &lt;em&gt;threads&lt;/em&gt; where the threads all share the same memory, which makes them faster than if you had multiple processes just trying to talk to each other. (It also makes it a lot easier to write.)&lt;/p&gt;

&lt;p&gt;The tricky thing about threads is you can have &lt;strong&gt;race conditions&lt;/strong&gt; , where two threads are trying to access the same resource simultaneously. This typically leads to strange--and difficult to reproduce--behavior, so you have to be very, very careful to manage your access to shared resources when using threads to prevent this, or debugging it will be a living hell.&lt;/p&gt;

&lt;p&gt;The general architecure we're going to build will look like most simple server models. We'll have a server thread that'll listen on port 5555 and accept incoming connections. Those connections will get moved to a different socket on a different port on a different thread, so the server thread can continue waiting for things.&lt;/p&gt;

&lt;p&gt;Python provides a helpful threading library, thankfully. There's a couple ways you can write threads--You can either make a new &lt;code&gt;Thread.Thread&lt;/code&gt; object and pass in the function that thread will run as an argument, or you can make a class that derives from &lt;code&gt;Thread.Thread&lt;/code&gt; and just override the &lt;code&gt;run&lt;/code&gt; method. I chose the latter, since I wanted to have some saved state and that seemed a good way to do it. You can do whatever you like.&lt;/p&gt;

&lt;h2&gt;
  
  
  Accepting incoming connections
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Overseer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;threading&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;threads&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Overseer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Starting overseer thread..."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;global&lt;/span&gt; &lt;span class="n"&gt;threads_run&lt;/span&gt;
        &lt;span class="k"&gt;global&lt;/span&gt; &lt;span class="n"&gt;threads&lt;/span&gt;

        &lt;span class="n"&gt;serversocket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AF_INET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SOCK_STREAM&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;serversocket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="s"&gt;"192.168.1.149"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5555&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="n"&gt;serversocket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;threads_run&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clientsocket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;serversocket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;accept&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Listener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clientsocket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;threads&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="n"&gt;serversocket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Most of this should look familiar, really. The important things here are the &lt;code&gt;global threads_run&lt;/code&gt; variable and the &lt;code&gt;l = Listener(clientsocket, address)&lt;/code&gt; with &lt;code&gt;l.start()&lt;/code&gt; at the bottom.&lt;/p&gt;

&lt;p&gt;The Listener class is another thread class I made, which we'll get to in a moment.&lt;/p&gt;

&lt;p&gt;Walking through:&lt;/p&gt;

&lt;p&gt;The init method should be much what you expect. One catch, you &lt;strong&gt;must&lt;/strong&gt; make sure to call the superclass init, or you'll get an exception when you try to &lt;code&gt;.start()&lt;/code&gt; the thread.&lt;/p&gt;

&lt;p&gt;The while loop is keyed off of a variable shared between all the threads--and only modified in the original main thread. This makes it possible for us to cleanly stop all the threads from the original one and clean up our resources when we're done.&lt;/p&gt;

&lt;p&gt;With the Overseer in it's own thread we can constantly block and wait for incoming connections without preventing our program from doing other things. This is the main idea and main value of threading.&lt;/p&gt;

&lt;p&gt;Now, one flaw in this design is that if we toggle &lt;code&gt;threads_run&lt;/code&gt; &lt;em&gt;while&lt;/em&gt; we're waiting for an incoming connection, we could just be waiting forever. I've been meaning to write an interrupt for that, but... later.&lt;/p&gt;

&lt;p&gt;Also note how we're appending the new Listener thread to a global &lt;code&gt;threads&lt;/code&gt; list--We'll come to that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Listening to those incoming connections
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Listener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;threading&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;clientsocket&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Listener&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Starting listener thread..."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;socket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;clientsocket&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;buffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;global&lt;/span&gt; &lt;span class="n"&gt;lock&lt;/span&gt;
        &lt;span class="k"&gt;global&lt;/span&gt; &lt;span class="n"&gt;shared_list&lt;/span&gt;
        &lt;span class="k"&gt;global&lt;/span&gt; &lt;span class="n"&gt;threads_run&lt;/span&gt;

        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;threads_run&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;recv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;datastr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;buffer&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'utf-8'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;buffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;
            &lt;span class="n"&gt;split&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datastr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;buffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="n"&gt;split&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

            &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;shared_list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;notify&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is where things start to get a little more complicated, but it's still pretty close to what we had before. Remember that the Listener threads get built and started in the Overseer thread, where they get their socket and their address.&lt;/p&gt;

&lt;p&gt;Within the listener thread, while the global &lt;code&gt;threads_run&lt;/code&gt; is true, we constantly block and receive data from the socket. Again, since this is occuring in its own thread, the blocking here &lt;em&gt;does not&lt;/em&gt; prevent us from executing in other threads.&lt;/p&gt;

&lt;p&gt;We do the same processing on the received data that we did before... and then we have this weird &lt;code&gt;with lock&lt;/code&gt; thing.&lt;/p&gt;

&lt;p&gt;So, remember how I was talking about how you have to be super careful when accessing shared resources when you're working with threading? This is one of those instances. Here, &lt;code&gt;shared_list&lt;/code&gt; is shared between all the running threads, and it's where they write the data they obtain from the network. To avoid collisions and weird behavior we use this &lt;code&gt;lock&lt;/code&gt; thing, which is a &lt;code&gt;threading.Condition&lt;/code&gt; class. In essence, the lock is a way for threads to ensure only one of them gets to touch a thing at a time. A thread has to acquire a lock, which only one thread can have at a time, and then it can do things, and then it has to release the lock for other threads, which block when &lt;em&gt;they&lt;/em&gt; try to acquire the lock. This is handled nicely with the &lt;code&gt;with&lt;/code&gt; syntax in Python; when you &lt;code&gt;with&lt;/code&gt; with a lock, Python handles the acquiring and releasing of the lock. Do note that you have to manually call &lt;code&gt;lock.notify()&lt;/code&gt; though, to let other threads know that the lock is available. Note also that I only acquire the lock when I'm about to interact with the shared data, and I release it immediately after I'm done messing with the shared data--There's no point in making other threads wait for me while I process strings that they don't share, they could be doing something useful in that time, so I try to hold onto the lock for as short a time as possible.&lt;/p&gt;

&lt;p&gt;Now, this is a super high level view of locks. Locks can get very complicated, especially if you end up with circular waits (where thread A is waiting on thread B, but thread B is waiting on thread A). Threading is a super complicated concept that I'm not going to go into in this post, but rest assured there's plenty of other reading on it if you're so interested.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Anyway,&lt;/em&gt; once you have the lock, you add stuff to the list and then release the lock, ensuring nothing weird happens with shared access. Cool? Cool.&lt;/p&gt;

&lt;h2&gt;
  
  
  Interacting with a Database
&lt;/h2&gt;

&lt;p&gt;If you haven't used them before, databases are systems designed for the easy storage and retrieval of--you guessed it--data. They're used in virtually every aspect of software, from managing the users of blogs to the content of twitter to the access logs of sensitive physical areas. They're fairly complex structures that often require a server in their own right to run on.&lt;/p&gt;

&lt;p&gt;For our purposes, we can make do with sqlite, a super lightweight database engine that just stores all the data in a file near your program. It's trivially easy to set up and interface with in Python.&lt;/p&gt;

&lt;p&gt;Now, I'll explain what I'm doing with the SQL commands I use here, but this isn't really a database usage tutorial so much as it is an interfacing-with-them tutorial.&lt;/p&gt;

&lt;p&gt;Cool? Cool. Onwards!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DBWriter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;threading&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DBWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Starting DB writer thread..."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;global&lt;/span&gt; &lt;span class="n"&gt;threads_run&lt;/span&gt;
        &lt;span class="k"&gt;global&lt;/span&gt; &lt;span class="n"&gt;lock&lt;/span&gt;
        &lt;span class="k"&gt;global&lt;/span&gt; &lt;span class="n"&gt;shared_list&lt;/span&gt;

        &lt;span class="n"&gt;connection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sqlite3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"greenhouse.db"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"CREATE TABLE if not exists readings "&lt;/span&gt;
                           &lt;span class="s"&gt;"(source text, "&lt;/span&gt;
                           &lt;span class="s"&gt;"airtemp real, "&lt;/span&gt;
                           &lt;span class="s"&gt;"humidity real, "&lt;/span&gt;
                           &lt;span class="s"&gt;"soil_moisture int, "&lt;/span&gt;
                           &lt;span class="s"&gt;"timestamp text);"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;threads_run&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="n"&gt;to_load_into_database&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
            &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shared_list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="n"&gt;to_load_into_database&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shared_list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="n"&gt;shared_list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clear&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

            &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;"Condensing &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;to_load_into_database&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; records..."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;by_source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;defaultdict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;namedtuple&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'SensorRecord'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'air_temp'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'air_hum'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'soil_moisture'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;to_load_into_database&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;';'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;mac&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;" "&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                &lt;span class="n"&gt;by_source&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;mac&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                        &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;" "&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
                        &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;" "&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
                        &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;" "&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
                    &lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;by_source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;list_len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;by_source&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;

                &lt;span class="n"&gt;avg_temp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
                &lt;span class="n"&gt;avg_hum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
                &lt;span class="n"&gt;avg_soil&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

                &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;by_source&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
                    &lt;span class="n"&gt;avg_temp&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;air_temp&lt;/span&gt;
                    &lt;span class="n"&gt;avg_hum&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;air_hum&lt;/span&gt;
                    &lt;span class="n"&gt;avg_soil&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;soil_moisture&lt;/span&gt;

                &lt;span class="n"&gt;avg_temp&lt;/span&gt; &lt;span class="o"&gt;/=&lt;/span&gt; &lt;span class="n"&gt;list_len&lt;/span&gt;
                &lt;span class="n"&gt;avg_hum&lt;/span&gt; &lt;span class="o"&gt;/=&lt;/span&gt; &lt;span class="n"&gt;list_len&lt;/span&gt;
                &lt;span class="n"&gt;avg_soil&lt;/span&gt; &lt;span class="o"&gt;/=&lt;/span&gt; &lt;span class="n"&gt;list_len&lt;/span&gt;
                &lt;span class="n"&gt;timestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;utcnow&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;strftime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%Y-%m-%d %H:%M:%S"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

                &lt;span class="n"&gt;values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;" ('&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;', &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;avg_temp&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;avg_hum&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;avg_soil&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, '&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;timestamp&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;')"&lt;/span&gt;
                &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;"Writing &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; to DB"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;"INSERT INTO readings VALUES &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Sleeping..."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DB writer thread exiting."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;"Aaah! That's a lot of code! What the hell, Jake, it was going so smoothly?!"&lt;/p&gt;

&lt;p&gt;It's fine! I promise! Really!&lt;/p&gt;

&lt;p&gt;We'll break it down into pieces. Let's look at the setup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DBWriter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;threading&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DBWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Starting DB writer thread..."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;global&lt;/span&gt; &lt;span class="n"&gt;threads_run&lt;/span&gt;
        &lt;span class="k"&gt;global&lt;/span&gt; &lt;span class="n"&gt;lock&lt;/span&gt;
        &lt;span class="k"&gt;global&lt;/span&gt; &lt;span class="n"&gt;shared_list&lt;/span&gt;

        &lt;span class="n"&gt;connection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sqlite3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"greenhouse.db"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"CREATE TABLE if not exists readings "&lt;/span&gt;
                           &lt;span class="s"&gt;"(source text, "&lt;/span&gt;
                           &lt;span class="s"&gt;"airtemp real, "&lt;/span&gt;
                           &lt;span class="s"&gt;"humidity real, "&lt;/span&gt;
                           &lt;span class="s"&gt;"soil_moisture int, "&lt;/span&gt;
                           &lt;span class="s"&gt;"timestamp text);"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;threads_run&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, the &lt;code&gt;__init__&lt;/code&gt; does... pretty much nothing useful.&lt;/p&gt;

&lt;p&gt;At the start of run, we global some things that we share, and we open a connection to the database, giving it the filename we want the database to live in.&lt;/p&gt;

&lt;p&gt;"Wait, Jake," you say. "Why wouldn't you move that connection up into &lt;code&gt;__init__&lt;/code&gt;? Isn't it... You know... Initialization?"&lt;/p&gt;

&lt;p&gt;You would be very correct! And I tried that. Turns out, &lt;code&gt;sqlite3&lt;/code&gt; objects can only be used in the thread they're created in, and, technically speaking, the &lt;code&gt;__init__&lt;/code&gt; function is executed from a different thread than the &lt;code&gt;run&lt;/code&gt; function is, since &lt;code&gt;__init__&lt;/code&gt; is called when the thread object is built, but &lt;code&gt;run&lt;/code&gt; is only called after you &lt;code&gt;.start()&lt;/code&gt; the thread. So, you have to make the object after the threads have diverged.&lt;/p&gt;

&lt;p&gt;Once we have the connection to the database we make sure the table we're going to use exists. If we don't have the &lt;code&gt;if not exists&lt;/code&gt; phrase there, we'll get a SQL error when we try to create an already-existing table. We then provide the name and type pairs of all the columns we want in the database:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;source, text: this will be the MAC address of the sending sensor. I'll use this later to figure out which sensor is where in the greenhouse so I can actually understand the incoming data, and not have to guess where it's coming from.&lt;/li&gt;
&lt;li&gt;airtemp, real: temperature is a continuous value, not an integer. Especially once we average it over the period a sensor has been sending, and since the temps will be in celcius, an integral value is so very wide and imprecise compared to a real one.&lt;/li&gt;
&lt;li&gt;humidity, real: See previous&lt;/li&gt;
&lt;li&gt;soil_moisture: So this is a bit strange, since it's a percentage. Technically, the average could also be a real, but I got lazy and made this an int. Sue me.&lt;/li&gt;
&lt;li&gt;timestamp, text: We're going to timestamp all the data, otherwise we won't know when a reading was taken, but there isn't really a consensus on how timestamps should be stored in databases. I'm doing text since it's the most flexible format.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With all that set up, we can actually enter our while loop. This thread naps for a while, since we need to wait for the data we're going to aggregate to come in.&lt;/p&gt;

&lt;p&gt;Now for the meat of the aggregation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;            &lt;span class="n"&gt;to_load_into_database&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
            &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shared_list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="n"&gt;to_load_into_database&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shared_list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="n"&gt;shared_list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clear&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

            &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;"Condensing &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;to_load_into_database&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; records..."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;by_source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;defaultdict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;namedtuple&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'SensorRecord'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'air_temp'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'air_hum'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'soil_moisture'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;to_load_into_database&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;';'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;mac&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;" "&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                &lt;span class="n"&gt;by_source&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;mac&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                        &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;" "&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
                        &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;" "&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
                        &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;" "&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
                    &lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So we make an empty list that we'll copy the shared data into, then we grab the lock and empty the shared list into our local one. Then we release the lock so the other threads can write to the shared lit.&lt;/p&gt;

&lt;p&gt;Once that's done, we start pulling the data out of the string and loading it into a namedtupe, which is really just a super efficient (and immutable) dictionary. We also group the data by the sensor that sent it.&lt;/p&gt;

&lt;p&gt;Now we have data, grouped by sending sensor, that we need to aggregate.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;by_source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;list_len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;by_source&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;

                &lt;span class="n"&gt;avg_temp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
                &lt;span class="n"&gt;avg_hum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
                &lt;span class="n"&gt;avg_soil&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

                &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;by_source&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
                    &lt;span class="n"&gt;avg_temp&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;air_temp&lt;/span&gt;
                    &lt;span class="n"&gt;avg_hum&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;air_hum&lt;/span&gt;
                    &lt;span class="n"&gt;avg_soil&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;soil_moisture&lt;/span&gt;

                &lt;span class="n"&gt;avg_temp&lt;/span&gt; &lt;span class="o"&gt;/=&lt;/span&gt; &lt;span class="n"&gt;list_len&lt;/span&gt;
                &lt;span class="n"&gt;avg_hum&lt;/span&gt; &lt;span class="o"&gt;/=&lt;/span&gt; &lt;span class="n"&gt;list_len&lt;/span&gt;
                &lt;span class="n"&gt;avg_soil&lt;/span&gt; &lt;span class="o"&gt;/=&lt;/span&gt; &lt;span class="n"&gt;list_len&lt;/span&gt;
                &lt;span class="n"&gt;timestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;utcnow&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;strftime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%Y-%m-%d %H:%M:%S"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

                &lt;span class="n"&gt;values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;" ('&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;', &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;avg_temp&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;avg_hum&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;avg_soil&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, '&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;timestamp&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;')"&lt;/span&gt;
                &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;"Writing &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; to DB"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;"INSERT INTO readings VALUES &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is pretty much just math. We aggregate all the readings by the sensor that sent them and build a timestamp in what's essentially ISO format, but without milliseconds.&lt;/p&gt;

&lt;p&gt;Once that's done, I build a string that the 'values' component of an SQL insert, using Python's wonderful format string syntax ( in Python 3.6 and above, yay!). Then we execute the insert statement and commit the change to the database.&lt;/p&gt;

&lt;p&gt;Make sure, once the &lt;code&gt;while&lt;/code&gt; in the &lt;code&gt;run&lt;/code&gt; of the DatabaseWriter exits, that you close the connection! Weird things can happen if you don't.&lt;/p&gt;

&lt;h2&gt;
  
  
  That's great, but what does the main look like?
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;global&lt;/span&gt; &lt;span class="n"&gt;threads_run&lt;/span&gt;
    &lt;span class="k"&gt;global&lt;/span&gt; &lt;span class="n"&gt;shared_list&lt;/span&gt;
    &lt;span class="k"&gt;global&lt;/span&gt; &lt;span class="n"&gt;threads&lt;/span&gt;
    &lt;span class="n"&gt;threads&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

    &lt;span class="n"&gt;threads_run&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;

    &lt;span class="n"&gt;threads&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Overseer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;threads_run&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;threads&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DBWriter&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="n"&gt;threads&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;threads&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;threads_run&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

        &lt;span class="n"&gt;instr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;instr&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s"&gt;"stop"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;instr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"enter 'stop' to stop: "&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;threads_run&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Waiting for threads..."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;thread&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;threads&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We start the Overseer and the DBWriter, and we make sure those are appended to the threads list. Then we start both of them. The Overseer starts accepting connections and spawning Listeners, and the DBWriter thread starts aggregating data.&lt;/p&gt;

&lt;p&gt;Then we start a loop where we wait for input, so the user can gracefully stop the program. When they do, we wait for all of the threads to halt with &lt;code&gt;thead.join&lt;/code&gt; and then we exit our program.&lt;/p&gt;

&lt;p&gt;There you go! That's the meat of my server! Keep in mind that this isn't by any means the "best" way to do this, and it is absolutely flawed. Keep an eye on the git repo to get updates!&lt;/p&gt;

</description>
      <category>python</category>
      <category>sockets</category>
      <category>sqlite3</category>
      <category>threading</category>
    </item>
    <item>
      <title>Intro to working with with ESP8266</title>
      <dc:creator>Jake Fenton</dc:creator>
      <pubDate>Wed, 18 Apr 2018 05:00:00 +0000</pubDate>
      <link>https://dev.to/bocajnotnef/intro-to-working-with-with-esp8266-3bno</link>
      <guid>https://dev.to/bocajnotnef/intro-to-working-with-with-esp8266-3bno</guid>
      <description>&lt;p&gt;originally posted &lt;a href="https://highnoiseratio.org/esp8266-intro.html" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  tl;dr
&lt;/h2&gt;

&lt;p&gt;I'm building environmental sensors using the ESP8266, a super cheap wifi-capable microcontroller that can run Micropython. This guide walks through writing driver code for the 8266 to collect data from a DHT and soil moisture sensor and beam it back over the network to a server applicaiton that collects the data for use later. The project code is available &lt;a href="https://github.com/bocajnotnef/microcontrollers/tree/master/greenhouse" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;So, I live in the Midwest, where things get exceptionally cold during the winter. I also enjoy gardening and fresh vegetables. These facts don't mix too well. Thankfully, places like the &lt;a href="http://www.extension.umn.edu/rsdp/statewide/deep-winter-greenhouse/#design-construction" rel="noopener noreferrer"&gt;University of Minnesota&lt;/a&gt; have extension programs working with deep winter greenhouses, designed to grow plants in the dead of winter.&lt;/p&gt;

&lt;p&gt;My (long term) goal is to build and automate one of these with microcontrollers to monitor and control the environment within the greenhouse. Since I didn't want to be learning how to program microcontrollers alongside building a greenhouse I decided to get a jump start on it.&lt;/p&gt;

&lt;p&gt;This post will detail my journey of making an environmental (temperature, humidity, soil moisture) sensor that reports back to a central server over the network.&lt;/p&gt;

&lt;p&gt;This guide/devblog/tutorial will condense the information available from the &lt;a href="https://docs.micropython.org/en/latest/esp8266/esp8266/tutorial/intro.html" rel="noopener noreferrer"&gt;Micropython ESP8266 tutorial&lt;/a&gt;, which is a phenomenally good reference, along with some documentation about the sensors I'm using.&lt;/p&gt;

&lt;h2&gt;
  
  
  Parts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;1 &lt;a href="https://www.ebay.com/itm/132532596048" rel="noopener noreferrer"&gt;ESP8266 ESP12&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;1 DHT11 sensor / 1 &lt;a href="https://www.ebay.com/itm/DHT22-Digital-Temperature-Humidity-Sensor-AM2302-Module-PCB-Cable-Arduino-Q32/371765844729?hash=item568ef89af9:g:X7EAAOSwpLNYBZCJ" rel="noopener noreferrer"&gt;DHT 22 Sensor&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;1 &lt;a href="https://www.ebay.com/itm/Soil-Hygrometer-Detection-Module-Moisture-Sensor-for-Arduino-Smart-Robot-Car/121861281045?epid=1938324160&amp;amp;hash=item1c5f7f9515:g:P7kAAOSw-xVaOFvk" rel="noopener noreferrer"&gt;soil moisture sensor&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;1 USB wall wart + micro cable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'll assume you have various kinds of jumper wires lying around, along with a laptop.&lt;/p&gt;

&lt;h2&gt;
  
  
  Software
&lt;/h2&gt;

&lt;p&gt;All the utilities I used were Python based; so I'm assuming you have a working Python 3 install alongside pip. You'll need some pip packages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;pip&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt; &lt;span class="n"&gt;adafruit&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;ampy&lt;/span&gt; &lt;span class="n"&gt;esptool&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll also need a copy of the most recent stable micropython firmware for the ESP8266 from the &lt;a href="http://micropython.org/download#esp8266" rel="noopener noreferrer"&gt;micropython page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I use the serial tool &lt;code&gt;picocom&lt;/code&gt; to talk to the board over USB; you're welcome to use whatever your favorite serial connection tool is, so long as it, y'know, works.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the ESP8266?
&lt;/h2&gt;

&lt;p&gt;So, having just started working with microcontrollers I don't know crazy much about them but I'll tell you what I do know about the 8266.&lt;/p&gt;

&lt;p&gt;Originally for this project I was going to use an arduino connected via USB to a raspi. The arduino would collect the sensor readings via it's GPIO port and report them back to the raspi via serial on USB. The pi would parse the incoming data, coallate it and send it to a controlling server. There were a couple problems with this deisgn:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Required a raspi to power and communicate with the arduino, with a physical connection. This would make it hard to place many monitoring sensors around the greenhouse, since now I need to run cable. Also increases cost, since for every 4 sensor arduinos I'd need one raspi to power and control them.&lt;/li&gt;
&lt;li&gt;I had to write the program for the arduino in C. This I kind of expected, since C is definetely the most well-suited language for microcontrollers, but also sucks, since C is a pain in the ass to use, especially for a beginner.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I could mitigate Problem 1 by connecting a wifi chip to the arduino, and beaming the data across the network. I didn't relish having to do that with C, but it was technically possible; quick research pointed me in the direction of a chip called the ESP8266, which was apparently really popular with people wanting to use microcontrollers with wifi. What I missed during my first pass was that the ESP8266 is a microcontroller &lt;em&gt;in it's own right&lt;/em&gt;. It doesn't need the arduino, and has GPIO capabilities of its own. In fact, the 8266 outclasses the arduino in available memory.&lt;/p&gt;

&lt;p&gt;So, I switched tacks from building an arduino connected to a raspi over USB and decided to use a fleet of 8266s beaming data back to a single, central raspi via wifi.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;The ESP8266s I ordered off of &lt;a href="https://www.ebay.com/itm/132532596045" rel="noopener noreferrer"&gt;Ebay&lt;/a&gt; claimed to ship with the AT firmwhere, where you can issue commands over serial to the ESP8266 for things like connecting to a network, opening a TCP/IP socket, beaming data, accepting incoming data, etc. Unfortunately for me, either they didn't have included firmware, the firmware wasn't the AT I was expecting I or I was simply too incompetent to correctly use it, so I spent about three hours trying to convince the damn things to do what I wanted and then I ran into the Micropython project.&lt;/p&gt;

&lt;p&gt;Following the instructions from their super helpful ESP8266 tutorial, I went hunting for the device in my &lt;code&gt;/dev&lt;/code&gt;; running &lt;code&gt;ls /dev/tty*&lt;/code&gt; and looking for things that end in &lt;code&gt;USB0&lt;/code&gt; or &lt;code&gt;ACM0&lt;/code&gt; will point you in the right direction.&lt;/p&gt;

&lt;p&gt;Once I figured out what port it was on, I copied the Micropython firmware onto the chip:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;esptool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;dev&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;ttyUSB0&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;baud&lt;/span&gt; &lt;span class="mi"&gt;460800&lt;/span&gt; &lt;span class="n"&gt;write&lt;/span&gt;\&lt;span class="n"&gt;_flash&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;flash&lt;/span&gt;\&lt;span class="n"&gt;_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;detect&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;fm&lt;/span&gt; &lt;span class="n"&gt;dio&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="n"&gt;esp8266&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;20171101&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;v1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;9.3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;bin&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then I connected to the chip with a serial terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;picocom&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;dev&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;ttyUSB0&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;b115200&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And I got greeted with the MicroPython REPL! Fantastic!&lt;/p&gt;

&lt;h2&gt;
  
  
  Hooking up the sensors
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/highnoiseratio.org%2Fimages%2Fesp8266-pinout.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/highnoiseratio.org%2Fimages%2Fesp8266-pinout.jpg" alt="ESP8266 Pinout"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Most of my sensor platforms will be a soil moisture sensor running with a LM393 comparator chip and a DHT 11 or DHT 22 sensor.&lt;/p&gt;

&lt;p&gt;The DHTs emit a digital sensor over a single wire interface, so you hook their positive lead to a 3.3v supply from the 8266, hook the negative lead to the ground on the 8266 and the middle data lead to one of the digital GPIO pins on the ESP8266.&lt;/p&gt;

&lt;p&gt;The moisture sensor unfortunately only gives an analog signal depending on how moist the soil is, between 0 and 1 volts. This will read as a value between 0 and 1024 using the ADC module within micropython--we'll come back to that later.&lt;/p&gt;

&lt;p&gt;As with the DHT sensor, the positive lead goes to 3.3v on the ESP8266, the negative lead goes to Ground and the analog out of the chip goes to the analog in pin of the 8266--there's only one analog input pin, in the upper left of the pinout diagram. It's labeled as "ADC0" or "A0" on the board I'm using.&lt;/p&gt;

&lt;p&gt;One thing to note about the LM393 chip, it contains a potentometer that sends a digital signal when the analog value crosses a threshold--a "0" for below, and "1" for above the threshold. The potentometer can be adjusted with a screwdriver and some patience. For my uses, I care more about having the analog-ish value.&lt;/p&gt;

&lt;p&gt;Now you'll note by now we've used two of the available three 3.3 rails of the ESP8266. It may be possible to split those lines to multiple directions, but I am not an electrical engineer and have no idea if that would twok, so proceed with caution.&lt;/p&gt;

&lt;p&gt;I'm also planning to supply power for the 8266 via it's USB port. Your plans may be different, but I'm a simple fellow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Writing the program
&lt;/h2&gt;

&lt;p&gt;So, as a bonus of using Micropython, I don't have to write C code. Since I'll be dealing with network interactions and data collection, I'm very happy with this.&lt;/p&gt;

&lt;p&gt;Now, the downside is I don't get fine-grained control over memory, and Micrpython inhabits more space on the device's program storage than an equivalent C binary would. I'm not planning to squeeze every little bit of performance out of the chip, so I'm okay with sacrificing a bit of space and management in favor of simpler code.&lt;/p&gt;

&lt;p&gt;Micropython offers several out-of-the-box modules to do what I need for sensor data collection and network communication. The binary for the 8266 also includes functions to hook into the network fairly easily. I recommend spending some time in the REPL via a serial link when you first get your binary flashed to get comfortable with the available functionality.&lt;/p&gt;

&lt;h3&gt;
  
  
  Connecting to the Network
&lt;/h3&gt;

&lt;p&gt;This is perhaps the meat and potatos of the ESP8266, and why you're using it in the first place: the damn thing is 2.4ghz wifi capable. Micropython is aware of this and incudes quick instructions for connecting in the &lt;code&gt;help()&lt;/code&gt; function available from the repl, and their docs include this function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;do_connect&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;network&lt;/span&gt;
    &lt;span class="n"&gt;sta_if&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;network&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;WLAN&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;network&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;STA_IF&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;sta_if&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isconnected&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;connecting to network...&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;sta_if&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;active&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;sta_if&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;essid&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;password&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;sta_if&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isconnected&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="k"&gt;pass&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;network config:&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sta_if&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ifconfig&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function, when called from your program, will block execution until the 8266 connects to the wifi network with the specified password.&lt;/p&gt;

&lt;p&gt;I've modified this a bit to blink the built-in LED on my board while it connects, so I can get an approximate idea of the state of the device. ( &lt;strong&gt;Weird Note:&lt;/strong&gt; for some reason, led.on() will turn the led off, and led.off() will turn it on. Dunno why.) You'll also note I pull the network name and password out to variables that I load from a config file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;do_connect&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;global&lt;/span&gt; &lt;span class="n"&gt;led_state&lt;/span&gt;
    &lt;span class="n"&gt;sta_if&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;network&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;WLAN&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;network&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;STA_IF&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;sta_if&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isconnected&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;connecting to network...&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;sta_if&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;active&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;sta_if&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NETNAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;NETPASS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;sta_if&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isconnected&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;led_state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;status_led&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="n"&gt;led_state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;status_led&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;off&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="n"&gt;led_state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
            &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.25&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;network config:&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sta_if&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ifconfig&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="n"&gt;status_led&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;off&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See? Nice and painless. (Aren't you glad this isn't C?)&lt;/p&gt;

&lt;h3&gt;
  
  
  Connecting to the Sensors
&lt;/h3&gt;

&lt;h4&gt;
  
  
  DHT Sensors
&lt;/h4&gt;

&lt;p&gt;Right, so you're connected to wifi. You're not talking to anything on the network yet, but that's okay, we'll come to that later.&lt;/p&gt;

&lt;p&gt;The micropython binary we're using includes a library for using DHT sensors, since they're apparently crazy popular. I have a DHT11, which is slightly cheaper and has disgustingly large errors in reads (2 degrees C!). The DHT22 is a slightly more expensive (DHT11 is ~$2/per, DHT22 is ~$3.5/per), but more accurate, at the cost of how often you can read from the sensor. We'll come to that too.&lt;/p&gt;

&lt;p&gt;So, hooking up the DHT sensors is stupid easy. We pull in the machine module, to access the hardware pin, and the DHT module to communicate with whatever's on that pin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dht&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DHT11&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;machine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Pin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wow, that was easy.&lt;/p&gt;

&lt;p&gt;Now, &lt;strong&gt;Important note:&lt;/strong&gt; The number you hand to machine.Pin is the number &lt;strong&gt;of the 8266 pin&lt;/strong&gt; , not of whatever handy board you're using. Pay attention to your pinout diagrams if you're having trouble connecting the sensor.&lt;/p&gt;

&lt;p&gt;Anyway, now that we have this DHT11 object we can tell it to measure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;measure&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which updates these values:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;temperature&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;humidity&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another note, on the DHT11, you can only call measure once every second or so. On the DHT22, you can only read once every two seconds. I don't know why this is specifically, or what the consequences are of not obeying that. Again, use caution if you're coloring outside the lines.&lt;/p&gt;

&lt;h4&gt;
  
  
  Soil Moisture Sensor
&lt;/h4&gt;

&lt;p&gt;As I mentioned before, the soil moisture sensor--as we have it hooked up--will give back an analog signal. We're going to have the ESP8266 interpret that signal as a digital value.&lt;/p&gt;

&lt;p&gt;Here, we're making an ADC object off of that pin:&lt;br&gt;
python&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;adc = machine.ADC(0)adc.read()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;adc.read()&lt;/code&gt; will yield a value between 0 and 1024. Apparently 1024 means "Dry" and "0" means "wetter than water", since I stuck the sensor in a cup of water and only got a reading of something like 300. I dunno why it's this way, but it is. Use as you will.&lt;/p&gt;

&lt;h3&gt;
  
  
  Network communication
&lt;/h3&gt;

&lt;p&gt;Okay, so we've got our data, we're connected to the wifi, now we need to take the data from the microcontroller we're on and shove it somewhere useful. Micropython includes a &lt;code&gt;socket&lt;/code&gt; module that behaves just like the normal module in [Macro]?Python. In my code, I have the IP and port of the server application recorded in a config file, and so we open the socket and start hammering data out to it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;socket_connected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;socket_connected&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;SERVIP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SERVPORT&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Initializing link...&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;socket_connected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;OSError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Socket connection failed... waiting.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="c1"&gt;# pulse LED to indicate problem
&lt;/span&gt;            &lt;span class="n"&gt;status_led&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;status_led&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;off&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;status_led&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;status_led&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;off&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;status_led&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;status_led&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;off&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;status_led&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;measure&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Soil: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;adc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;; temp: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;temperature&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;; hum: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;humidity&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;; from &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;mac&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;OSError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;socket_connected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Sent &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; bytes.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;status_led&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;off&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Walking through this:&lt;/p&gt;

&lt;p&gt;We drop into a forever loop, so we'll collect and transmit data until the end of time.&lt;/p&gt;

&lt;p&gt;While we don't have an active socket connection, try to make one. If the server isn't listening, the attempt to open a socket will timeout and we'll flash the LED angrily and try again.&lt;/p&gt;

&lt;p&gt;(I need to update this code to also check and make sure we still have a wifi link--no point in trying to transmit data if we aren't connected anyway.)&lt;/p&gt;

&lt;p&gt;If we have a socket connection, we aren't trapped in that loop and we continue on to the meat of the loop.&lt;/p&gt;

&lt;p&gt;We update the temperature sensor, then construct a message to transmit. This message can take whatever form you really want, I'm pretty sure it gets converted to bytes, so if you really wanted you could send raw binary data. Right now I'm just sending strings to make the dbeugging easier for me.&lt;/p&gt;

&lt;p&gt;I also append the mac address of this board so I can identify which sensor the readings are coming from, when I'm on the server. I obtain the mac address with this line. which I stole &lt;a href="https://forum.micropython.org/viewtopic.php?t=1890" rel="noopener noreferrer"&gt;from here&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;mac&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ubinascii&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hexlify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;network&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;WLAN&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;mac&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;:&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once we construct the message I print it, which dumps it to serial output, which makes debugging a cinch, and I write it to the socket.&lt;/p&gt;

&lt;p&gt;The sleep at the end gives the temperature sensor a moment to recuperate, and gives us a reasonable rate of data flow.&lt;/p&gt;

&lt;p&gt;So, with this, you have a microcontroller environmental sensor that can send data over the network!&lt;/p&gt;

&lt;p&gt;You can view all of my project code &lt;a href="https://github.com/bocajnotnef/microcontrollers/tree/master/greenhouse" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>dev</category>
      <category>python</category>
      <category>microcontroller</category>
      <category>micropython</category>
    </item>
  </channel>
</rss>
