<?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>Forem: Ross</title>
    <description>The latest articles on Forem by Ross (@rossdrew).</description>
    <link>https://forem.com/rossdrew</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%2F134632%2F1fa5d519-bb54-47d3-8210-2805e8346aa9.png</url>
      <title>Forem: Ross</title>
      <link>https://forem.com/rossdrew</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/rossdrew"/>
    <language>en</language>
    <item>
      <title>You don't understand Agile!</title>
      <dc:creator>Ross</dc:creator>
      <pubDate>Sat, 16 Jan 2021 12:23:20 +0000</pubDate>
      <link>https://forem.com/rossdrew/you-don-t-understand-agile-4g6j</link>
      <guid>https://forem.com/rossdrew/you-don-t-understand-agile-4g6j</guid>
      <description>&lt;h2&gt;
  
  
  You don't understand agile!
&lt;/h2&gt;

&lt;p&gt;I don't think you really understand agile.  Why do I think that?  Because 90% of people in the industry seem to &lt;a href="https://en.wikipedia.org/wiki/There_are_known_knowns#:~:text=%22There%20are%20known%20knowns%22%20is,of%20mass%20destruction%20to%20terrorist"&gt;not know that they don't know&lt;/a&gt; what agile is and as a result, think they know what agile is.  This results in pervasive misinformation.  Just as a pure numbers exercise, it's a good bet -&lt;em&gt;on my part&lt;/em&gt;- that you don't, simple.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"&lt;em&gt;...as we know, there are known knowns; there are things we know we know. We also know there are known unknowns; that is to say we know there are some things we do not know. But there are also unknown unknowns—the ones we don't know we don't know. And if one looks throughout the history of our country and other free countries, it is the latter category that tends to be the difficult ones.&lt;/em&gt;" - Donald Rumsfeld,  United States Secretary of Defense&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  How do you (think you) understand agile?
&lt;/h3&gt;

&lt;p&gt;I propose that most agile &lt;a href="https://en.wikipedia.org/wiki/Well_poisoning"&gt;wells are poisoned&lt;/a&gt;.  People learn, self-led on the job and are riddled with bias and obstacles which taints their understanding &amp;amp; implementation. These people make and take part in faulty implementations, find the faults they injected, rage then write articles about them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ad-Hoc Agile
&lt;/h3&gt;

&lt;p&gt;The major mistake we make when adopting agile is not consulting with experts.  Taking in consultants or sending people on courses.  Agile is different, it requires a change in attitude more than (certainly before) process and as a result:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;we assume agile is largely a process change and not a culture/mentality and extract only the process which makes no sense in most cases without the culture&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;we dismiss parts as common sense that then don't get attention in implementation.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;we don't strive for management buy-in an end up making massive compromises.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We try to phase agile in to avoid disruption and miss the core concept.  That agile is about embracing disruption.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The second thing we do is assume that people talking about agile, know about agile...&lt;/p&gt;

&lt;h3&gt;
  
  
  Learning from "experts"/articles online...
&lt;/h3&gt;

&lt;p&gt;Everywhere I see articles like &lt;a href="https://medium.com/critically-deciding/software-development-practices-desperately-need-real-attention-9477b4b85bd1"&gt;this one&lt;/a&gt; which base their premise on massively flawed articles such as: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"&lt;em&gt;Agile is the new waterfall…The reality of Agile is that you still have immutable decisions made by business people with no real understanding of technology. Those decisions are then forced on to developers. The end result is the same as Waterfall, only the names have changed.&lt;/em&gt;” — &lt;a href="https://medium.com/swlh/agile-is-the-new-waterfall-f7baef5d026d"&gt;ayasin, Architect &amp;amp; Developer&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Anyone who knows agile knows this is anything but.  "&lt;em&gt;immutable decisions&lt;/em&gt;" completely contradicts &lt;a href="https://www.agilealliance.org/agile101/12-principles-behind-the-agile-manifesto/"&gt;agile principle&lt;/a&gt; 2...so, not agile!  &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Welcome changing requirements, even late in development. Agile processes harness change for the customer’s competitive advantage.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Then in the same paragraph&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Those decisions are then forced on to developers&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;doesn't seem to match with &lt;a href="https://www.agilealliance.org/agile101/12-principles-behind-the-agile-manifesto/"&gt;agile principle&lt;/a&gt; 4&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Business people and developers must work together daily throughout the project.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And we are given the conclusion that "&lt;em&gt;Agile is the new waterfall&lt;/em&gt;".  Someone who has managed to be a developer so long they've become an architect seems like someone we can trust, right?  &lt;/p&gt;

&lt;h3&gt;
  
  
  All Agile is
&lt;/h3&gt;

&lt;p&gt;It's very specifically a &lt;strong&gt;change in thinking &amp;amp; culture&lt;/strong&gt;.  We strive to embrace uncertainty and cut out wastage so that we can deliver tiny amounts of high quality value quickly and repeatedly based on user feedback.  We then turn that attitude inward and cut wastage, make tiny amounts of high quality process changes quickly and repeatedly based on performance in the previous iteration.&lt;/p&gt;

&lt;p&gt;Anything that doesn't meet this, isn't agile.  All process added and actions performed which decrease quality, time to increment and/or isn't user value focused will corrode all agile implementations.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Every process that slows development in order to forecast.&lt;/li&gt;
&lt;li&gt;Every time there's a hand-off&lt;/li&gt;
&lt;li&gt;Every user feedback you shun&lt;/li&gt;
&lt;li&gt;Every failure to realise and focus the specific value  - added&lt;/li&gt;
&lt;li&gt;Every time you fail to trust each other&lt;/li&gt;
&lt;li&gt;Every single time you say "&lt;em&gt;that's not my job&lt;/em&gt;"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now the question is, am I right?  Get a certified consultant! Be ready to commit! Don't assume you know all you need to.&lt;/p&gt;

</description>
      <category>agile</category>
      <category>discuss</category>
      <category>projectmanagement</category>
    </item>
    <item>
      <title>Should comments in code be considered failures in coding?</title>
      <dc:creator>Ross</dc:creator>
      <pubDate>Mon, 26 Aug 2019 10:35:39 +0000</pubDate>
      <link>https://forem.com/rossdrew/should-comments-in-code-be-considered-failures-in-coding-2kbc</link>
      <guid>https://forem.com/rossdrew/should-comments-in-code-be-considered-failures-in-coding-2kbc</guid>
      <description>&lt;p&gt;Uncle bob says:&lt;/p&gt;



&lt;blockquote&gt;
&lt;br&gt;
&lt;p&gt;A comment is a failure to express yourself in code. If you fail, then write a comment; but try not to fail.&lt;/p&gt;— Uncle Bob Martin (@unclebobmartin) &lt;a href="https://twitter.com/unclebobmartin/status/870311898545258497?ref_src=twsrc%5Etfw"&gt;June 1, 2017&lt;/a&gt;&lt;br&gt;
&lt;/blockquote&gt; 

&lt;ul&gt;
&lt;li&gt;Should code be written in a way that's expressive enough on it's own?&lt;/li&gt;
&lt;li&gt;If you disagree, what are your thoughts on keeping comments up to date with changes?&lt;/li&gt;
&lt;li&gt;Is there a grey area?   Examples?&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>code</category>
      <category>comments</category>
      <category>failure</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Planning and Inaugural Meeting of the Edinburgh Kotlin User Group</title>
      <dc:creator>Ross</dc:creator>
      <pubDate>Tue, 30 Jul 2019 15:28:08 +0000</pubDate>
      <link>https://forem.com/rossdrew/planning-and-inaugural-meeting-of-the-edinburgh-kotlin-user-group-3n04</link>
      <guid>https://forem.com/rossdrew/planning-and-inaugural-meeting-of-the-edinburgh-kotlin-user-group-3n04</guid>
      <description>&lt;p&gt;NOTE: Adapted from my blog post at &lt;a href="https://www.symphonicsoft.com/technology-choices/"&gt;Symphonic Software&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why did we start a Kotlin User Group?
&lt;/h2&gt;

&lt;p&gt;My company have recently started moving from Java code to Kotlin.  We have never been shy in technology adaption.  We started with a full .NET stack, moved through an .NET/Java implementation then to Angular/Java.  Along the way through experimentation with Elm, Ember, JavaScript and REACT we picked up some Groovy and some Python.   We even had &lt;a href="https://dev.to/neilgall"&gt;Neil Gall&lt;/a&gt; -one of our Senior Developers- present our method of testing with Python at Europython 2018.  It's important to us to move with the times and use the best tools to create the best product.&lt;/p&gt;

&lt;p&gt;Although the team we have assembled at &lt;a href="https://www.symphonicsoft.com/"&gt;Symphonic&lt;/a&gt; has adapted to the changing technologies with skill and enthusiasm, we've found that conventions do not take hold as quickly.   For at least a period with new languages we find ourselves creating debt.  We've written non-Pythonic Python and bent Groovy to do things we didn't know how to express in it at the time.&lt;br&gt;
This is because it takes time and exposure to veterans to get comfortable with the intricacies of a language.   We can increase this exposure and perhaps decrease the time by talking to and interacting with people who use the language, so we decided to run a user group.&lt;/p&gt;

&lt;h2&gt;
  
  
  How did we do it?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Put together a budget on what we would like to spend to make it successful.
&lt;/li&gt;
&lt;li&gt;Put together some &lt;a href="https://twitter.com/edi_kug/status/1138197929498415107/photo/1"&gt;posters&lt;/a&gt; that we could paste up in tech sites around the city&lt;/li&gt;
&lt;li&gt;Advertised on &lt;a href="https://www.reddit.com/r/Edinburgh/comments/bhlcbk/edinburgh_kotlin_meetup/"&gt;Reddit&lt;/a&gt;, &lt;a href="https://opentechcalendar.co.uk/group/564-edinburgh-kotlin-user-group"&gt;Edinburgh Tech Calendar&lt;/a&gt;, &lt;a href="https://twitter.com/edi_kug"&gt;Twitter&lt;/a&gt; and &lt;a href="https://www.eventbrite.co.uk/o/ross-drew-23262607307"&gt;EventBrite&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Purchased refreshments (beer, juice, pizza)&lt;/li&gt;
&lt;li&gt;Decided on venue (our office) and put together a speaker ("Kotlin for Java Developers" by our Head of Engineering, Ewan Dawson)&lt;/li&gt;
&lt;li&gt;Registered with &lt;a href="https://kotlinlang.org/user-groups/user-group-list.html"&gt;Kotlin Community&lt;/a&gt; and notified them of the upcoming talk, they provided us with free T-shirts and stickers&lt;/li&gt;
&lt;li&gt;Registered with &lt;a href="https://www.jetbrains.com/community/support/#section=communities"&gt;Developer Community Support&lt;/a&gt; who provided us with a free 1 year JetBrains license to raffle off.&lt;/li&gt;
&lt;li&gt;Wrote a &lt;a href="https://github.com/rossdrew/programmingproblems/blob/1a575a1a25b1a319be7ae9fe0a34eebbd6fa1ebb/src/main/kotlin/com/kug/Tumbola.kt"&gt;small Kotlin program&lt;/a&gt;, containing an interesting quirk of the language which selected one of the present people to win the prize.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;kotlin.random.Random.Default.nextInt&lt;/span&gt;

&lt;span class="cm"&gt;/**&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="cm"&gt; * Number of people playing&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="cm"&gt; *&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="cm"&gt; * Q: Anyone know why val requires to be declared&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="cm"&gt; *    const yet 'lateinit val T = 9' indicates&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="cm"&gt; *    that val is immutable?&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="cm"&gt; */&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;PLAYERS&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;

&lt;span class="cm"&gt;/**&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="cm"&gt; * Original: Pick a winning number from 1 to players&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="cm"&gt; */&lt;/span&gt;
&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;pickWinningNumber&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;players&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;nextInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;players&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;h2&gt;
  
  
  How did it go?
&lt;/h2&gt;

&lt;p&gt;The 11 attendees enjoyed themselves if the SurveyMonkey survey I sent out afterwards is anything to go by.  People signed in and I used that list as both a health and safety list for fire regulations and as the start of a mailing list to send out my survey.&lt;/p&gt;

&lt;p&gt;The small program intended to pick a winner for the JetBrains license turned into a bit of a talking point.  Firstly because of the interesting IDE complaint it generated, secondly on a discussion of how Kotlin can make it even more concise.&lt;/p&gt;

&lt;p&gt;We had people put themselves and others forward for future talks and suggest ways of increasing membership, one of which was to create a &lt;a href="https://www.meetup.com/Edinburgh-Kotlin-User-Group/events/263449151/"&gt;Meetup page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We are now planning our second meetup, with a backlog of three speakers ready for more.  Currently bi-monthly until the membership and speaker list increases a little but going well.&lt;/p&gt;

&lt;p&gt;P.S. We're looking for speakers on anything Kotlin related if anyone is interested.&lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>edinburgh</category>
      <category>meetup</category>
      <category>usergroup</category>
    </item>
    <item>
      <title>Functional Enums in Java</title>
      <dc:creator>Ross</dc:creator>
      <pubDate>Sun, 23 Jun 2019 20:14:29 +0000</pubDate>
      <link>https://forem.com/rossdrew/functional-enums-in-java-34o1</link>
      <guid>https://forem.com/rossdrew/functional-enums-in-java-34o1</guid>
      <description>&lt;p&gt;A rehash of my &lt;a href="https://rossdrew.github.io//emulating-opcodes/"&gt;GitHub.io&lt;/a&gt; post._&lt;/p&gt;

&lt;h3&gt;
  
  
  Introduction
&lt;/h3&gt;

&lt;p&gt;The largest personal project I am currently undertaking, is that of an emulator (&lt;a href="https://github.com/rossdrew/emuRox"&gt;EmuRox&lt;/a&gt;). The main goal was to come up with a larger product that I am completely in control of and can experiment with tools and methods to become a better programmer. Sub goals include learning something about the machines I grew up with and maybe, perhaps getting to the point where I’ve written my own retro NES emulator. Long term, pie in the sky goal was to create a well designed, highly tested, accessible, open-source, pluggable, multi-emulator.&lt;/p&gt;

&lt;p&gt;First and foremost though, I wanted to strongly focus on what I feel is important in a good Java program:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Highly Tested&lt;/li&gt;
&lt;li&gt;Readable&lt;/li&gt;
&lt;li&gt;Efficient&lt;/li&gt;
&lt;li&gt;Maintainable / Extensible&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Satisfying all of the above, IMHO I would say it was generally well designed.&lt;/p&gt;

&lt;p&gt;So, I started with the most documented part of the NES. The &lt;a href="https://en.wikipedia.org/wiki/MOS_Technology_6502"&gt;MOS6502&lt;/a&gt; processor. What I want to talk about today, is how I emulated op-codes and how my approach gave me a nice upgrade path when I realised my implementation wasn’t as great as it could be.  As a side note, I'll be discussing why TDD is -if you understand and use it correctly- a very useful method in Java development.&lt;/p&gt;

&lt;h3&gt;
  
  
  Approach Number 1: The Result of Test Driven Development (TDD)
&lt;/h3&gt;

&lt;p&gt;One of the approaches I’ve been playing with is TDD. Where I write a failing test, then write the code to make it work and iteratively build a fully tested, modular product. This led me to writing the minimal amount of code to make tests work. The result was great process and…this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;step&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;debug&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"STEP &amp;gt;&amp;gt;&amp;gt;"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;OpCode&lt;/span&gt; &lt;span class="n"&gt;opCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OpCode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nextProgramByte&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getRawValue&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;

        &lt;span class="c1"&gt;//Execute the opcode&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;debug&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Instruction: {}..."&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;opCode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getOpCodeName&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opCode&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nl"&gt;ASL_A:&lt;/span&gt;
                &lt;span class="n"&gt;withRegister&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Register&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ACCUMULATOR&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;performASL&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nl"&gt;ASL_Z:&lt;/span&gt;
                &lt;span class="n"&gt;withByteAt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RoxWord&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nextProgramByte&lt;/span&gt;&lt;span class="o"&gt;()),&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;performASL&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nl"&gt;ASL_Z_IX:&lt;/span&gt;
                &lt;span class="n"&gt;withByteXIndexedAt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RoxWord&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nextProgramByte&lt;/span&gt;&lt;span class="o"&gt;()),&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;performASL&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nl"&gt;ASL_ABS_IX:&lt;/span&gt;
                &lt;span class="n"&gt;withByteXIndexedAt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nextProgramWord&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;performASL&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nl"&gt;ASL_ABS:&lt;/span&gt;
                &lt;span class="n"&gt;withByteAt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nextProgramWord&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;performASL&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nl"&gt;LSR_A:&lt;/span&gt;
                &lt;span class="n"&gt;withRegister&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Register&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ACCUMULATOR&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;performLSR&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nl"&gt;LSR_Z:&lt;/span&gt;
                &lt;span class="n"&gt;withByteAt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RoxWord&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nextProgramByte&lt;/span&gt;&lt;span class="o"&gt;()),&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;performLSR&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nl"&gt;LSR_Z_IX:&lt;/span&gt;
                &lt;span class="n"&gt;withByteXIndexedAt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RoxWord&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nextProgramByte&lt;/span&gt;&lt;span class="o"&gt;()),&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;performLSR&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nl"&gt;LSR_ABS:&lt;/span&gt;
                &lt;span class="n"&gt;withByteAt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nextProgramWord&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;performLSR&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nl"&gt;LSR_ABS_IX:&lt;/span&gt;
                &lt;span class="n"&gt;withByteXIndexedAt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nextProgramWord&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;performLSR&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

            &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is of course truncated as there are many, many more opcodes on the 6502. Does this fit my criteria for a well designed Java program?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Highly Tested&lt;/em&gt;: Floats around 98-99% line coverage. Static analysis. Mutation tested to 98%&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Readable&lt;/em&gt;: Partially. Each opcode has a path. The instructions to execute it are in English. Little annoying that you need to scroll so much and complicated instructions end up being messy to nest method calls so that they read fluidly.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Efficient&lt;/em&gt;: For large numbers of cases, switch statements are pretty efficient.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Maintainable&lt;/em&gt;: No. There are loads of methods that are there to reduce duplication which end up being duplication themselves. Parts of the logic are not separable like addressing and operations.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Extensible&lt;/em&gt;: Lets see…&lt;/p&gt;

&lt;p&gt;So I wanted to see if I could do better.&lt;/p&gt;

&lt;h3&gt;
  
  
  The legacy &amp;amp; and the beauty of TDD
&lt;/h3&gt;

&lt;p&gt;It led to some pretty hard to maintain code, but correct; Thanks to our tests, quickly and accurately verifiably correct. Which means we can mess with other implementations and the huge test space will theoretically catch any mistakes in a very short development cycle.&lt;/p&gt;

&lt;h3&gt;
  
  
  Approach Number 2: Functional Java Code
&lt;/h3&gt;

&lt;p&gt;I want to minimise duplication, writing code once for each operation, and once for each addressing mode. As we already reference opcodes by Enum, I wondered if it was possible to parse an opcode value (&lt;code&gt;0x0A&lt;/code&gt;) into it’s Enum (&lt;code&gt;ASL_A&lt;/code&gt;) then simply call an &lt;code&gt;execute()&lt;/code&gt; method on that Enum instance which fires off an attached lambda providing an environment (memory, registers and alu). As each Op-Code Enum knows it’s own Addressing Mode, it could call an &lt;code&gt;address()&lt;/code&gt; on that Addressing Mode (which also calls an attached lambda) providing us with all we need to make composable instructions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Overview
&lt;/h3&gt;

&lt;p&gt;So my enum becomes a definition containing a byte value, it’s addressing mode and the operation performed. The OpCode is then the intersection of Addressing Mode and Operation&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="no"&gt;ASL_A&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0x0A&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;AddressingMode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ACCUMULATOR&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Operation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ASL&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The operation argument is an operation on the environment (a: accumulator, r: registers, m: memory), given an addressed value (v):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;enum&lt;/span&gt; &lt;span class="nc"&gt;Operation&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;AddressedValueInstruction&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="cm"&gt;/** Shift all bits in byte left by one place, setting flags based on the result */&lt;/span&gt;
        &lt;span class="no"&gt;ASL&lt;/span&gt;&lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;RoxByte&lt;/span&gt; &lt;span class="n"&gt;newValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asl&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setFlagsBasedOn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newValue&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;newValue&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}),&lt;/span&gt;

        &lt;span class="o"&gt;...&lt;/span&gt;

        &lt;span class="nd"&gt;@Override&lt;/span&gt;
        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;RoxByte&lt;/span&gt; &lt;span class="nf"&gt;perform&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Mos6502Alu&lt;/span&gt; &lt;span class="n"&gt;alu&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Registers&lt;/span&gt; &lt;span class="n"&gt;registers&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Memory&lt;/span&gt; &lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;RoxByte&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;instruction&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;perform&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alu&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;registers&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The addressing mode uses an environment (r: registers, m: memory, a: accumulator) to address a value, runs a given operation (i) on it and places the return value back at the addressed location:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;enum&lt;/span&gt; &lt;span class="nc"&gt;AddressingMode&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Addressable&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="cm"&gt;/** Expects no argument, operation will be performed using the Accumulator Register*/&lt;/span&gt;
    &lt;span class="no"&gt;ACCUMULATOR&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Accumulator"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;RoxByte&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getRegister&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Registers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Register&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ACCUMULATOR&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setRegister&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Registers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Register&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ACCUMULATOR&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;perform&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="o"&gt;}),&lt;/span&gt;

    &lt;span class="o"&gt;...&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;address&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Registers&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Memory&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Mos6502Alu&lt;/span&gt; &lt;span class="n"&gt;alu&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;AddressedValueInstruction&lt;/span&gt; &lt;span class="n"&gt;instruction&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;alu&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;instruction&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then the op-code brings it all together by combining the addressing mode and operation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;enum&lt;/span&gt; &lt;span class="nc"&gt;OpCode&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Instruction&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="o"&gt;...&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;perform&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Mos6502Alu&lt;/span&gt; &lt;span class="n"&gt;alu&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Registers&lt;/span&gt; &lt;span class="n"&gt;registers&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Memory&lt;/span&gt; &lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;addressingMode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;registers&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;alu&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;operation:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;perform&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means the huge switch statement becomes one line of code&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;opCode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;perform&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alu&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;registers&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Problems
&lt;/h3&gt;

&lt;p&gt;There are some instructions which don’t fit this pattern nicely:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;AddressingMode.IMPLIED&lt;/em&gt;: The addressing mode is implied by the last two bits of the instruction byte&lt;br&gt;
The IMPLIED instructions do slightly different addressing based on the Operation. I’ll need to deal with these as individual cases, where Operations do their own addressing.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Operation.JMP&lt;/em&gt;: It -unlike all other instructions- passes a word (not a byte) from the addressing mode that could be AddressingMode.INDIRECT&lt;br&gt;
These do two things that make them hard to deal with. Firstly, their addressing is ABSOLUTE; the two byte (word) address that the Operation is supposed to use to load into the Program Counter. We could deal with this in the same way as the IMPLIED (in that the Operation then does some of it’s own addressing) if not for the case where JMP uses INDIRECT-ABSOLUTE addressing, which will take a two byte argument then from the address specified by that word, load a two byte address into the Program Counter. In this case, it cannot be done in the Operation because it has no idea what it’s Addressing Mode is.&lt;/p&gt;
&lt;h3&gt;
  
  
  Solution
&lt;/h3&gt;

&lt;p&gt;So in the end we have a bit of a hybrid:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;        &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Mos6502OpCode&lt;/span&gt; &lt;span class="n"&gt;opCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Mos6502OpCode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nextProgramByte&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getRawValue&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;

        &lt;span class="c1"&gt;//Execute the opcode&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;debug&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Instruction: {}..."&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;opCode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getOpCodeName&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opCode&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nl"&gt;JMP_ABS:&lt;/span&gt;
                &lt;span class="n"&gt;registers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setPC&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nextProgramWord&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nl"&gt;JMP_IND:&lt;/span&gt;
                &lt;span class="n"&gt;registers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setPC&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;getWordOfMemoryAt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nextProgramWord&lt;/span&gt;&lt;span class="o"&gt;()));&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

            &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;opCode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;perform&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alu&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;registers&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The edge cases make sure this is not the prettiest but it’s much nicer than it was and when I think of the next iteration to simplify this, I know that my tests are specific yet generic enough to support refactoring and redesign.&lt;/p&gt;

</description>
      <category>java</category>
      <category>functional</category>
      <category>emulation</category>
      <category>tdd</category>
    </item>
    <item>
      <title>Thoughts on Automated Plant Growth Measurement</title>
      <dc:creator>Ross</dc:creator>
      <pubDate>Fri, 14 Jun 2019 14:47:19 +0000</pubDate>
      <link>https://forem.com/rossdrew/thoughts-on-automated-plant-growth-measurement-59ab</link>
      <guid>https://forem.com/rossdrew/thoughts-on-automated-plant-growth-measurement-59ab</guid>
      <description>&lt;h3&gt;
  
  
  Introduction
&lt;/h3&gt;

&lt;p&gt;I have a greenhouse.  I grow chillies in said greenhouse.  I would like to use technology to improve my yield.&lt;br&gt;
Using a Raspberry Pi, some cheap electronics and some Python I've started to write the telemetry software that will allow me to make better choices. I've been thinking about how far I can take this.&lt;/p&gt;

&lt;p&gt;One such area in the future that will provide the input to get closer to the entire system being closed is plant growth monitoring.&lt;/p&gt;

&lt;h3&gt;
  
  
  Plant Growth
&lt;/h3&gt;

&lt;p&gt;So we need something to measure and as I see it, plants have two phases which can be measured&lt;/p&gt;

&lt;h5&gt;
  
  
  Phase 1: From Seed
&lt;/h5&gt;

&lt;p&gt;Measuring germination would be a case of detecting something appearing from nothing, the measurement being time from planting to germination.  Time should be pretty short (1-4 weeks) and any more is a failure.&lt;br&gt;
 Another useful metric might be the number of seeds which germinate from a given number planted.&lt;/p&gt;

&lt;h5&gt;
  
  
  Phase 2: From Germination
&lt;/h5&gt;

&lt;p&gt;This is where it get interesting as this feedback can be fed into the cycle and adjustments made to improve.  Useful metrics might be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Height of plant&lt;/li&gt;
&lt;li&gt;Physiological age: number of leaves&lt;/li&gt;
&lt;li&gt;Size of leaves&lt;/li&gt;
&lt;li&gt;Number of flowers/fruits&lt;/li&gt;
&lt;li&gt;Changes in color&lt;/li&gt;
&lt;li&gt;Weight of plant (with some compensation for watering)&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  Measuring Phases
&lt;/h5&gt;

&lt;p&gt;So we &lt;em&gt;can&lt;/em&gt; technically measure the first phase but unless we are doing several rounds of germination or using the data to feed back into the next year so I'll be concentrating on the second phase as it fits the brief of actions based on feedback to improve yield.&lt;/p&gt;

&lt;h4&gt;
  
  
  Techniques
&lt;/h4&gt;

&lt;p&gt;So we know what we want to measure, how do we measure it?&lt;/p&gt;

&lt;h5&gt;
  
  
  Height
&lt;/h5&gt;

&lt;p&gt;The simplest method of gauging plant height has been used for a very long time and is called an auxanometer.  This is essentially a string is tied to the top of the plant, it goes over a pulley to a weight and as the plant grows the weight lowers.  This is linear motion, which is easy to measure.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8ahHR5dN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/g1y6d62n2ysh7srykao8.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8ahHR5dN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/g1y6d62n2ysh7srykao8.jpg" alt="Auxanometer" width="800" height="1160"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The other option is image processing, which we'll discuss as part of...&lt;/p&gt;

&lt;h5&gt;
  
  
  Leaf count, Leaf Size, Flower/Fruit Count, Color Changes
&lt;/h5&gt;

&lt;p&gt;Without manual process, these are much harder to read.  Ideas could be a camera system which does image processing^[1][2], LIDAR which creates 3D models, infrared or some combination such as XBox Kinect systems^[3][4][5].&lt;/p&gt;

&lt;h5&gt;
  
  
  Weight
&lt;/h5&gt;

&lt;p&gt;An interesting option is plant weight.  Plants will obviously increase in weight as they increase in size.  There are a couple gotchas in that plants need watered and various states of being watered will have different weights and that offset will need to be accounted for.  The other is that weight will take into account things on the plant; moisture, pests, dirt and there would be no distinction between leaf, stem, flower or fruit.  The latter being a lesser concern.&lt;/p&gt;

&lt;h5&gt;
  
  
  Other
&lt;/h5&gt;

&lt;p&gt;Things like structure of the plant and it's leaves and growing direction can be handy for detecting disease, lack of water, excess heat.  Then being able to detect and possibly identify pests could lead to suggested or automated treatments.&lt;/p&gt;

&lt;h4&gt;
  
  
  A Way Forward
&lt;/h4&gt;

&lt;p&gt;There are quick wins, the auxanometer and weighing platform but ultimately if we don't want multiple machines around each plant the efficient solution is image/lidar/infrared processing.  It should do it all in a very compact way.  This of course is not a quick win solution and will require quite advanced software.&lt;/p&gt;

&lt;p&gt;So the plan, if I go forward with it will be to use a camera (perhaps an XBox Kinect) and write software to process height, leaf count &amp;amp; size, fruit &amp;amp; flower production and color.&lt;/p&gt;

&lt;h4&gt;
  
  
  Steps (quick wins first)
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Get the camera setup attached to my power grid and adjust as necessary&lt;/li&gt;
&lt;li&gt;Add software to tell plants apart even when they are moved, perhaps an identifying mark on the plantpot such as a number or even barcode, allowing us to encode things like plant type right there on the plant.&lt;/li&gt;
&lt;li&gt;Expand software to detect changes in plant color&lt;/li&gt;
&lt;li&gt;Expand software to detect height&lt;/li&gt;
&lt;li&gt;Expand software and hardware to detect leaf/flower size/count&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The last one may require hardware changes as a static camera and a static plant could mean that leafs/flowers could be hidden from the camera by the plant itself.  This hardware expansion may also by useful for rotating plants away from the sun to help them build good stems.&lt;/p&gt;

&lt;h4&gt;
  
  
  What to do with all this data?
&lt;/h4&gt;

&lt;p&gt;Very quickly from a little data we can start making the lives of our plants better, autonomously and suggesting manual remedies for common problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Under-watered or overheated plants tend to lose structural integrity in their leaves.  We can water them, or open vents to cool the greenhouse.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Pests or disease will discolour the plant, some pests can be removed with a spray of water, others with natural pesticides (like a rhubarb/chilli tea) and others could suggest a change in gardening practices like adding more plants that encourage ladybirds to eat pest like aphids.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Lack of growth, of flowers could suggest that we are over watering or under feeding.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Flowers which don't reach maturity could suggest improper feeding or undesirable humidity levels.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Growth direction could indicate that plants need to be turned more regularly so that they have to reach towards the sun, strengthening their stems.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Struggling plants might suggest greenhouse changes such as a better base, insulation or the introduction of a thermal mass to limit temperature spikes.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And the more time we can stop thinking about common problems, the more we can start thinking about how to increase yield volume and quality.&lt;/p&gt;

&lt;h5&gt;
  
  
  References
&lt;/h5&gt;

&lt;p&gt;^1: Lin, Ta-Te &amp;amp; Lai, Tsung-Cheng &amp;amp; Liu, Ting-Yu &amp;amp; Yeh, Yu-Hui &amp;amp; Liu, Chang-Chih &amp;amp; Chung, Wei-Chang. (2019). An Automatic Vision-Based Plant Growth Measurement System for Leafy Vegetables. &lt;/p&gt;

&lt;p&gt;^2: Deep learning for image-based prediction of plant growth in city farms Iljazi, J. (Author). 25 Sep 2017&lt;/p&gt;

&lt;p&gt;^3: Hu, Yang &amp;amp; Wang, Le &amp;amp; Xiang, Lirong &amp;amp; Wu, Qian &amp;amp; Jiang, Huanyu. (2018). Automatic Non-Destructive Growth Measurement of Leafy Vegetables Based on Kinect. Sensors. 18. 806. 10.3390/s18030806. &lt;/p&gt;

&lt;p&gt;^4: Chunlei Xia, Longtan Wang, Bu-Keun Chung, and Jang-Myung Lee, et al. (2015). In Situ 3D Segmentation of Individual Plant Leaves Using&lt;br&gt;
a RGB-D Camera for Agricultural Automation. Open Access Sensors ISSN 1424-8220&lt;/p&gt;

&lt;p&gt;^5: Jorge Martinez-Guanter, Ángela Ribeiro,et al. (2019). Low-Cost Three-Dimensional Modeling of Crop Plants. Sensors 2019, 19, 2883; doi:10.3390/s19132883&lt;/p&gt;

</description>
      <category>telemetry</category>
      <category>data</category>
      <category>automation</category>
    </item>
    <item>
      <title>Hardware Choices in Monitoring a Greenhouse</title>
      <dc:creator>Ross</dc:creator>
      <pubDate>Sun, 09 Jun 2019 00:06:10 +0000</pubDate>
      <link>https://forem.com/rossdrew/hardware-choices-in-monitoring-a-greenhouse-4b8g</link>
      <guid>https://forem.com/rossdrew/hardware-choices-in-monitoring-a-greenhouse-4b8g</guid>
      <description>&lt;h3&gt;
  
  
  What do we need?
&lt;/h3&gt;

&lt;p&gt;A power system for an off-grid, greenhouse telemetry Raspberry Pi setup.  Turns out it's actually pretty easy, even for a power layman like myself.&lt;/p&gt;

&lt;h4&gt;
  
  
  We need power
&lt;/h4&gt;

&lt;p&gt;First, make the Pi efficient.  I'm controlling my Pi via VNC remote desktop but I'll move it to headless soon.  I wont be using the HDMI so disabling that circuitry makes sense, let's save the 25mA that it uses:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/user/bin/tvservice -o
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then I don't need flashing lights, so another 10mA (5mA each) saved:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo 0 | sudo tee /sys/class/leds/led0/brightness
echo 0 | sudo tee /sys/class/leds/led1/brightness
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I've seen Pi power estimates (HDMI and lights are turned off) as high as 2 Watts per hour.  I want extra power though to allow later expansions and because I don't trust any data based on Scottish weather.  So let's just see how much bang we can get for our buck running it 24 hours.  &lt;/p&gt;

&lt;h4&gt;
  
  
  Can we power off grid?
&lt;/h4&gt;

&lt;p&gt;Using &lt;a href="http://re.jrc.ec.europa.eu/pvgis/apps4/pvest.php" rel="noopener noreferrer"&gt;European Commission Data&lt;/a&gt; we can see that in summer (April-September) using a &lt;a href="https://www.amazon.co.uk/gp/product/B01FKJUNFC/ref=ppx_yo_dt_b_asin_title_o01_s00?ie=UTF8&amp;amp;psc=1" rel="noopener noreferrer"&gt;50W solar panel&lt;/a&gt;, we can hope to generate between 130-200Wh per day with a yearly low of 40Wh (Ed in the table below).  My position is a little awkward (east facing with a shadow cut off point) so I'll be somewhere below that figure. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F0suebwl0v3mcxjxzcssx.png" 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/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F0suebwl0v3mcxjxzcssx.png" alt="Figures in kWh"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So I could almost run this system throughout winter.  If solar generation was spread out over 24 hours, which we know it isn't.  A bonus with my chosen panel is that it comes with a controller to save me messing with electronics and making a mess of the power circuits.&lt;/p&gt;

&lt;h4&gt;
  
  
  So we need power at night
&lt;/h4&gt;

&lt;p&gt;We need 48Wh to power the Pi (2Wh over 24h) and we're getting 130+ in a short time frame then nothing for the rest.  We need to spread that out.  So a battery. Something that will:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Give us room to grow&lt;/li&gt;
&lt;li&gt;Will support plenty of discharging/recharging&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, lets say &lt;a href="https://www.tayna.co.uk/leisure-batteries/hankook/dc24/?gclid=EAIaIQobChMIy4Csj7nU6wIVOYBQBh12wQHGEAQYASABEgIQQPD_BwE" rel="noopener noreferrer"&gt;80AH&lt;/a&gt;, that looks about as expensive as I'm willing to pay.  This equates to 960wH (80Ah x 12V) or 20 Raspberry Pi days straight.&lt;br&gt;
It's also a deep cycle (meaning it'll run pretty low, safely) so has quite a large buffer area for power issues and loads of extra power for expansion.&lt;/p&gt;

&lt;h3&gt;
  
  
  And that's it
&lt;/h3&gt;

&lt;p&gt;It works, it's been running for 3 days straight in my home, 1 in my greenhouse.  I get way more active solar charging time than I expected being east facing so I have more power than I know what to do with. &lt;/p&gt;

&lt;p&gt;Now to think of something else to do with it all.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fhlbvtvoaj7rw0g048gln.jpeg" 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/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fhlbvtvoaj7rw0g048gln.jpeg" alt="The greenhouse"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Next
&lt;/h3&gt;

&lt;p&gt;I'm also looking at products or techniques to allow me to monitor and log incoming solar charge and consumed battery.&lt;/p&gt;

</description>
      <category>rasberrypi</category>
      <category>hardware</category>
      <category>offgrid</category>
      <category>solar</category>
    </item>
    <item>
      <title>Technology Choices in Monitoring a Greenhouse</title>
      <dc:creator>Ross</dc:creator>
      <pubDate>Tue, 04 Jun 2019 08:36:47 +0000</pubDate>
      <link>https://forem.com/rossdrew/technology-choices-in-monitoring-a-greenhouse-2ppf</link>
      <guid>https://forem.com/rossdrew/technology-choices-in-monitoring-a-greenhouse-2ppf</guid>
      <description>&lt;h3&gt;
  
  
  Introduction
&lt;/h3&gt;

&lt;p&gt;I've started to put together a telemetry setup for my greenhouse.  I've been thinking about it for a while but ultimately I've left this a bit late.  It's summer, although the constant Scottish rain begs to differ.&lt;/p&gt;

&lt;p&gt;I've only recently installed a proper greenhouse and inspired by m'colleague Neil Galls &lt;a href="https://dev.to/neilgall/pirrigator-18hf"&gt;Pirragor&lt;/a&gt; Series, I've gotten started.  I'm not doing some fancy Rust cross cross compiling, resulting in installing a new OS like Neil.  I've opted to move my complications somewhere else, by growing chillies instead of tomatoes in various varieties.   Needing many more individual plants and finer grained plant care.   This means monitoring of temperature and humidity is the most important concern with some further thought needed in automating the upkeep of the individual plants of which there are over 20.&lt;/p&gt;

&lt;p&gt;Straight off the bat, off the shelf &lt;a href="https://www.raspberrypi.org/"&gt;Rasberry Pi&lt;/a&gt; is a good choice for rapid development.  Python is already available &lt;a href="https://github.com/rossdrew/gh-telemetry"&gt;so I got started&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Need Input!
&lt;/h3&gt;

&lt;p&gt;I need humidity and temperature monitored, hopefully at different points in the greenhouse and compared to outside.  Internally I'll be using &lt;a href="https://www.digikey.co.uk/product-detail/en/sparkfun-electronics/SEN-10167/1568-1793-ND/6163749?utm_adgroup=&amp;amp;mkwid=sLFm8fMw6&amp;amp;pcrid=338141659323&amp;amp;pkw=&amp;amp;pmt=&amp;amp;pdv=c&amp;amp;productid=6163749&amp;amp;slid=&amp;amp;gclid=EAIaIQobChMIgOjG0LHP4gIVZpPtCh2FAgsZEAQYAiABEgLQffD_BwE"&gt;AM2302 humidity/temperature sensor&lt;/a&gt; and the &lt;a href="https://github.com/adafruit/Adafruit_Python_DHT"&gt;Adafruit Python Drivers&lt;/a&gt; for it  which makes it as easy as&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;humidity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;temp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Adafruit_DHT&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read_retry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sensor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And rather than weather-proofing sensors and thinking about wiring it up, I'll just use a weather REST API in the form of &lt;a href="https://openweathermap.org/"&gt;OpenWeatherMap&lt;/a&gt; and I get things like cloud cover and barometric pressure for free.&lt;/p&gt;

&lt;h4&gt;
  
  
  Problems?
&lt;/h4&gt;

&lt;p&gt;I've noticed that randomly the AM2302 outputs a humidity of 3303.6 and a temperature of 70~ and the values had to be sanitised but otherwise, all good.&lt;/p&gt;

&lt;h3&gt;
  
  
  Those who cannot remember the past are condemned to repeat it!
&lt;/h3&gt;

&lt;p&gt;A grandiose way of saying we need to store the data for comparison.  Originally I stuck it all in a CSV file and tried -using &lt;a href="http://pygal.org/en/stable/"&gt;Pygal&lt;/a&gt;- to write my own charts, which was time consuming and ultimately inflexible.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uP62i9no--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/5cmjki1639z7kxlyg82b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uP62i9no--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/5cmjki1639z7kxlyg82b.png" alt="" width="800" height="602"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I need better control over the data which means a database.  All of my data is going to be tied to a specific time so a &lt;a href="https://en.wikipedia.org/wiki/Time_series_database"&gt;time-series database&lt;/a&gt; is what I'm looking for.  I installed &lt;a href="https://www.influxdata.com/time-series-technical-paper/?utm_source=google&amp;amp;utm_medium=cpc&amp;amp;utm_campaign=&amp;amp;utm_term=influxdb&amp;amp;utm_content=&amp;amp;gclid=EAIaIQobChMIhYKmj7LP4gIVCZztCh0QngkZEAAYASAAEgKQ2fD_BwE"&gt;InfluxDB&lt;/a&gt; on my Rasberry Pi, no hassle and with the help of the &lt;a href="https://influxdb-python.readthedocs.io/en/latest/include-readme.html"&gt;influxdb&lt;/a&gt; Python library, started to write my data there:&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;db_client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;InfluxDBClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'localhost'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8086&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'root'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'root'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'TelemetryHistory'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;record_entry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="s"&gt;"measurement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"am2302"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"tags"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="s"&gt;"update"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"whole"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="s"&gt;"device"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"am2302"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="s"&gt;"location"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"gh1"&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="s"&gt;"fields"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="s"&gt;"temp"&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;temp_reading&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="s"&gt;"humidity"&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;humidity_reading&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="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;write_success&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write_points&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;record_entry&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;InfluxDB, bullet point review:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;quick to install&lt;/li&gt;
&lt;li&gt;very quick to get started being schemaless&lt;/li&gt;
&lt;li&gt;very quick to learn&lt;/li&gt;
&lt;li&gt;perfect for analytic data, with good visualisation with Grafana&lt;/li&gt;
&lt;li&gt;it has other benefits I wont use (efficient eviction, high throughput)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then, using &lt;a href="https://grafana.com/"&gt;Grafana&lt;/a&gt; on my laptop, I could connect to the database on my Rasperry Pi and view whatever selected, filtered, calculated data I wanted with the ability to draw very flexible, zoomable, pretty graphs.  Granted of my room at this point but pretty nonetheless.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6R9RJkx3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/j4yp16f3s5822h63q15e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6R9RJkx3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/j4yp16f3s5822h63q15e.png" alt="Grafana" width="800" height="558"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Next up!
&lt;/h3&gt;

&lt;p&gt;I need to come up with a battery/solar panel configuration that will properly power all of this.&lt;/p&gt;

</description>
      <category>rasberrypi</category>
      <category>python</category>
      <category>influxdb</category>
      <category>sideprojects</category>
    </item>
  </channel>
</rss>
