<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-3220006345447041404</id><updated>2026-04-22T04:58:02.334-07:00</updated><category term="travel"/><category term="beagleboard"/><category term="electronics"/><category term="energy monitor"/><category term="python"/><category term="sar"/><category term="worldwind"/><category term="arduino"/><category term="otb"/><category term="economics"/><category term="arts"/><category term="open source"/><category term="philosophy"/><category term="quadcopter"/><category term="kinect"/><category term="opencv"/><category term="phd"/><category term="conference"/><category term="simulation"/><category term="teardown"/><category term="GPS"/><category term="qgis"/><category term="forest"/><category term="imu"/><category term="kenya"/><category term="energy harvesting"/><category term="gpgpu"/><category term="hackerspace"/><category term="imagery"/><category term="nodemcu"/><category term="point clouds"/><category term="radar"/><category term="solar"/><category term="3d reconstruction"/><category term="AWS"/><category term="Design patterns"/><category term="KiCAD"/><category term="MPI"/><category term="ads1115"/><category term="amazon aws"/><category term="art"/><category term="augmented reality"/><category term="blender"/><category term="csiro"/><category term="eclipse"/><category term="electronics manufacture"/><category term="esp8266"/><category term="gpu"/><category term="gsoc 2011"/><category term="hawkboard"/><category term="hobart"/><category term="igarss"/><category term="java"/><category term="matlab"/><category term="medieval fair"/><category term="modem"/><category term="nearmap"/><category term="netcdf"/><category term="neuroscience"/><category term="ossim"/><category term="photography"/><category term="physics"/><category term="sift"/><category term="stereo"/><category term="udoo"/><category term="unity3d"/><category term="weather"/><category term="ATM90E26"/><category term="BTC"/><category term="IoT"/><category term="LEDs"/><category term="MSVC"/><category term="Open-Source"/><category term="Xadow"/><category term="android"/><category term="armor"/><category term="atmel"/><category term="avr"/><category term="bengal"/><category term="bitcoin"/><category term="bundler"/><category term="c++"/><category term="calibration"/><category term="camera"/><category term="clustering"/><category term="cmake"/><category term="cognitive antenna"/><category term="collada"/><category term="community"/><category term="cuda"/><category term="demographics"/><category term="drums"/><category term="evolution"/><category term="fdtd"/><category term="fiji"/><category term="floating point"/><category term="foss4g"/><category term="fpga"/><category term="gdal"/><category term="geoserver"/><category term="gumstix"/><category term="hongkong"/><category term="initial conditions"/><category term="javascript"/><category term="jpeg2000"/><category term="jtag"/><category term="kernel"/><category term="liblas"/><category term="lidar"/><category term="linux"/><category term="litecoin"/><category term="makerfaire"/><category term="mapping"/><category term="mesh networks"/><category term="nasa"/><category term="oil spill"/><category term="openscenegraph"/><category term="osgi"/><category term="raspberry-pi"/><category term="recreation"/><category term="religion"/><category term="rust"/><category term="samba"/><category term="security"/><category term="singapore"/><category term="skills"/><category term="start-ups"/><category term="statistics"/><category term="subsurface"/><category term="surf"/><category term="teensy"/><category term="ublox"/><category term="unit tests"/><category term="vacation"/><category term="vlc"/><category term="volunteering"/><category term="x64"/><category term="3-phase AC"/><category term="3D printing"/><category term="3G"/><category term="3mt"/><category term="8051 CPU"/><category term="ADE7880"/><category term="AI"/><category term="Analog Devices"/><category term="Bike riding"/><category term="CC3200"/><category term="Code Logistics"/><category term="Cortex-M0"/><category term="DAC"/><category term="DIN Rail"/><category term="David Walsh"/><category term="Deep Learning. Technology"/><category term="DevOps"/><category term="EC2"/><category term="Energia"/><category term="FreeCAD"/><category term="HUD"/><category term="LTC"/><category term="Linuguistics"/><category term="MEEP"/><category term="MONA"/><category term="MYO"/><category term="NVCL"/><category term="NXP"/><category term="PCB Design"/><category term="R"/><category term="RDS"/><category term="RedBearLab"/><category term="Replication"/><category term="SD storage"/><category term="STM32"/><category term="Software Architecture"/><category term="Workarounds"/><category term="acolite"/><category term="acp"/><category term="adafruit feather"/><category term="ade7763"/><category term="agents"/><category term="agriculture"/><category term="airports"/><category term="alternator"/><category term="angel finance"/><category term="anthropology"/><category term="apache hive"/><category term="apple mapping"/><category term="approach"/><category term="ardor"/><category term="ardor3d"/><category term="arduino-cli"/><category term="artix-7"/><category term="artwork"/><category term="atm90e36"/><category term="auckland"/><category term="austender"/><category term="australia day"/><category term="banana"/><category term="bazaar"/><category term="beer"/><category term="beer goggles"/><category term="benchmark"/><category term="bil"/><category term="biochemistry"/><category term="biomass"/><category term="blynk"/><category term="business idea"/><category term="butterfly"/><category term="cambodia"/><category term="canberra"/><category term="carbon accounting"/><category term="cartography"/><category term="cgminer"/><category term="chicago"/><category term="classifiers"/><category term="cloud"/><category term="code review"/><category term="cognition"/><category term="collections"/><category term="colours"/><category term="control"/><category term="copyrights"/><category term="cosmology"/><category term="craft"/><category term="crops"/><category term="curl"/><category term="darts"/><category term="darwin"/><category term="data structures"/><category term="database"/><category term="dds"/><category term="denmark"/><category term="diagrams"/><category term="dinosaur"/><category term="drawing"/><category term="dsm"/><category term="ducklake"/><category term="eagle"/><category term="earth-observation"/><category term="earthhour"/><category term="earthquake"/><category term="ecp5"/><category term="education"/><category term="eeepc"/><category term="embedded"/><category term="encryption"/><category term="energy"/><category term="energy-monitor"/><category term="entertainment"/><category term="envisat"/><category term="eoli"/><category term="esp32"/><category term="facebook"/><category term="family"/><category term="family time"/><category term="feko"/><category term="firmware"/><category term="fishing"/><category term="flickr"/><category term="flight test"/><category term="flow"/><category term="forms"/><category term="france"/><category term="game"/><category term="gaming"/><category term="generalist"/><category term="geospatial"/><category term="geotools"/><category term="giraffe"/><category term="git"/><category term="github-copilot"/><category term="globerender"/><category term="go"/><category term="gold"/><category term="golf"/><category term="google"/><category term="google api"/><category term="graffiti"/><category term="gsoc 2012"/><category term="gstreamer"/><category term="haiti"/><category term="harris"/><category term="hash"/><category term="helicopter"/><category term="heroku"/><category term="hexiwear"/><category term="hfss"/><category term="high availabilty"/><category term="history"/><category term="holiday"/><category term="ide"/><category term="iglobe"/><category term="india"/><category term="inkscape"/><category term="installer"/><category term="interpolation"/><category term="jakarta"/><category term="jalapeno"/><category term="jni"/><category term="jogl"/><category term="jsr-223"/><category term="kd-tree"/><category term="kml"/><category term="kogan"/><category term="kolkata"/><category term="kriging"/><category term="kubernetes"/><category term="lamu"/><category term="latex"/><category term="learning"/><category term="limits"/><category term="literature"/><category term="litex"/><category term="loc"/><category term="logic analyser"/><category term="logic-analyzer"/><category term="lyx"/><category term="maintenance"/><category term="management"/><category term="maps"/><category term="mars"/><category term="mars rover"/><category term="materials"/><category term="maxim"/><category term="meetup"/><category term="meetup. AI"/><category term="melbourne"/><category term="mentoring"/><category term="mercurial"/><category term="mercury"/><category term="meshlab"/><category term="meta-art"/><category term="metalwork"/><category term="microcontroller"/><category term="microwave"/><category term="mingw"/><category term="mining"/><category term="mobile monday"/><category term="modular java"/><category term="motion tracking"/><category term="mountain bike"/><category term="mountain view"/><category term="multiresolution"/><category term="munich"/><category term="muti-spectral"/><category term="nairobi"/><category term="netv2"/><category term="neur.io"/><category term="nikon d800"/><category term="notes"/><category term="object tracking"/><category term="ocds"/><category term="onion"/><category term="open artwork"/><category term="open hardware"/><category term="openkinect"/><category term="openocd"/><category term="opticks"/><category term="optics"/><category term="organic structures"/><category term="osdc"/><category term="pandaboard"/><category term="patents"/><category term="pcb assembly"/><category term="pcileech"/><category term="penguin"/><category term="perception"/><category term="performance"/><category term="picasso"/><category term="piezo"/><category term="pirr"/><category term="politics"/><category term="polyglot"/><category term="polygons"/><category term="processor"/><category term="promotion"/><category term="public service"/><category term="publication"/><category term="pulse counting"/><category term="pxa"/><category term="python. csiro"/><category term="qt"/><category term="quickbird"/><category term="ray tracing"/><category term="re-earth"/><category term="reality television"/><category term="recycled cans"/><category term="reflow"/><category term="regression"/><category term="relativity"/><category term="rendering"/><category term="rendering throughput"/><category term="rendermonkey"/><category term="reprap"/><category term="research"/><category term="robot"/><category term="ros"/><category term="saleae"/><category term="samoa"/><category term="science"/><category term="scraping"/><category term="scripting"/><category term="scrypt"/><category term="sense"/><category term="serendipity"/><category term="serial"/><category term="shed"/><category term="shell"/><category term="shopping"/><category term="single phase"/><category term="sketchbook"/><category term="smart-plug"/><category term="sms"/><category term="sociology"/><category term="soldering"/><category term="space"/><category term="spaceapps"/><category term="speculation"/><category term="spelling"/><category term="stability"/><category term="stac"/><category term="streaming"/><category term="students"/><category term="sunderbans"/><category term="supernovas"/><category term="surfer"/><category term="swarm"/><category term="swig"/><category term="sydney"/><category term="terrasar"/><category term="tesla"/><category term="thingspeak"/><category term="tindie"/><category term="tp-link"/><category term="turing"/><category term="tvheadend"/><category term="twitter"/><category term="uart"/><category term="ubuntu"/><category term="ugrid"/><category term="uncertainity"/><category term="utilities"/><category term="valuation"/><category term="vancouver"/><category term="vangotech"/><category term="videos"/><category term="vision"/><category term="water meter"/><category term="wattwatchers"/><category term="weather radar"/><category term="webgl"/><category term="webgpu"/><category term="wifi"/><category term="wilderness society"/><category term="wind profiling"/><category term="windows"/><category term="work"/><category term="xbee"/><category term="xbmc"/><category term="xctu"/><category term="xenophobia"/><category term="zarr"/><title type='text'>Confused Life - Reloaded</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://whatnicklife.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3220006345447041404/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://whatnicklife.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/3220006345447041404/posts/default?start-index=26&amp;max-results=25&amp;redirect=false'/><author><name>Tisham Dhar</name><uri>http://www.blogger.com/profile/15154154153085427197</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>507</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-3220006345447041404.post-1788928931185438421</id><published>2026-04-03T15:00:00.000-07:00</published><updated>2026-04-03T18:23:56.122-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="AI"/><category scheme="http://www.blogger.com/atom/ns#" term="cloud"/><category scheme="http://www.blogger.com/atom/ns#" term="devops"/><category scheme="http://www.blogger.com/atom/ns#" term="maintenance"/><category scheme="http://www.blogger.com/atom/ns#" term="software architecture"/><title type='text'>From SaaS to Serviced Software -- the code was never the hard part</title><content type='html'>&lt;p&gt;Sometime in the last two years the bottleneck shifted. I used to
spend most of a greenfield week staring at an empty editor, scaffolding
routes, arguing with ORMs, and coaxing CSS into something that did not
look like a government form from 2004. Today I can prompt my way to a
working CRUD app with auth, a reasonable schema, and even half-decent
styling before lunch. The code, it turns out, was never the hard part.
The hard part was–and still is–keeping the thing alive once real users
touch it.&lt;/p&gt;
&lt;h2 id=&quot;the-saas-mental-model&quot;&gt;The SaaS mental model&lt;/h2&gt;
&lt;p&gt;“Software as a Service” trained an entire generation to think the
value lives in the application layer. Build a clever feature, wrap it in
a subscription, ship a landing page. The implicit promise: we write the
software, you pay monthly, everyone wins. That framing put the spotlight
squarely on &lt;strong&gt;creation&lt;/strong&gt;–new features, new integrations,
new UI polish.&lt;/p&gt;
&lt;p&gt;But anyone who has operated a SaaS product past the euphoric launch
week knows where the hours actually go:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Rotating secrets and patching CVEs at 11pm on a Friday&lt;/li&gt;
&lt;li&gt;Chasing down why the invoice PDF lambda timed out in ap-southeast-2
but not us-east-1&lt;/li&gt;
&lt;li&gt;Fighting Terraform drift after someone clicked through the console
“just this once”&lt;/li&gt;
&lt;li&gt;Explaining to a customer why their data export is 48 hours stale
because the Celery worker OOM-killed itself&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The ratio of build-time to keep-it-running-time was already lopsided.
AI just made it more obvious.&lt;/p&gt;
&lt;h2 id=&quot;enter-the-vibe-coded-prototype&quot;&gt;Enter the vibe-coded
prototype&lt;/h2&gt;
&lt;p&gt;Large language models have compressed the “zero to working prototype”
phase from weeks to hours. Cursor, Copilot, Aider, v0, Bolt – pick your
weapon. The scaffolding phase that used to justify a two-pizza team for
a quarter now fits in a solo weekend sprint. I have experienced this
first-hand: prompting out a FastAPI backend with DynamoDB tables, an SPA
frontend, and a deployment pipeline that mostly works. The code is not
elegant. It does not need to be. It is structurally correct enough to
demo and iterate.&lt;/p&gt;
&lt;p&gt;This is genuinely magical. It is also genuinely dangerous, because it
creates an illusion of completeness. The prototype works on your laptop,
passes the happy path tests the LLM also generated, and looks great in
the demo. Then production happens.&lt;/p&gt;
&lt;h2 id=&quot;production-is-where-software-goes-to-get-serviced&quot;&gt;Production is
where software goes to get serviced&lt;/h2&gt;
&lt;p&gt;Here is where the mental model needs updating. We are not really
selling Software as a Service anymore. We are selling &lt;strong&gt;Serviced
Software&lt;/strong&gt; – and the distinction matters.&lt;/p&gt;
&lt;p&gt;In the SaaS framing, the software is the product and the service is
the delivery mechanism. In the Serviced Software framing, the
&lt;strong&gt;service&lt;/strong&gt; is the product and the software is just the
substrate it runs on. Customers do not care that your backend is FastAPI
or Express or Rails. They care that:&lt;/p&gt;
&lt;ol type=&quot;1&quot;&gt;
&lt;li&gt;&lt;strong&gt;It is up&lt;/strong&gt; when they need it (hosting, redundancy,
failover)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Their data is safe&lt;/strong&gt; (encryption at rest and in
transit, access controls, backups that actually restore)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;It stays current&lt;/strong&gt; (dependency updates, OS patches,
framework migrations)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;It costs a predictable amount&lt;/strong&gt; (no surprise egress
bills, no runaway autoscaling)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Someone answers the phone&lt;/strong&gt; when it breaks at
3am&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;None of those are code problems. They are operational problems. And
they are the problems that AI is worst at solving, because they require
sustained human judgement over months and years, not a one-shot
generation pass.&lt;/p&gt;
&lt;h2 id=&quot;the-maintenance-asymmetry&quot;&gt;The maintenance asymmetry&lt;/h2&gt;
&lt;p&gt;There is a well-known asymmetry in software engineering: building
version 1.0 is perhaps 20% of the total lifetime cost. The remaining 80%
is maintenance, evolution, and eventual decommissioning. AI has
dramatically reduced the cost of that first 20%. But it has done almost
nothing for the other 80%.&lt;/p&gt;
&lt;p&gt;If anything, AI makes the maintenance problem worse. When code is
cheap to produce, people produce more of it. More repos, more
microservices, more side projects that “just need a small server.” Each
one becomes a maintenance liability. Each one needs patching,
monitoring, log rotation, certificate renewal, database vacuuming. The
&lt;a
href=&quot;https://techcrunch.com/2018/06/23/open-source-sustainability/&quot;&gt;open-source
maintainer burnout&lt;/a&gt; problem I wrote about after PyConAU 2019 is now
everyone’s problem, because everyone is now a maintainer of their own
vibe-coded fleet.&lt;/p&gt;
&lt;p&gt;I keep thinking about the analogy to 3D printing. When desktop
printers got cheap, everyone printed trinkets for a month. Then the
printers gathered dust because the hard part was never fabrication–it
was &lt;strong&gt;design, finishing, and material science&lt;/strong&gt;. The
bottleneck moved upstream and downstream simultaneously, leaving the
newly-cheap middle step feeling oddly irrelevant.&lt;/p&gt;
&lt;h2 id=&quot;what-serviced-software-looks-like-in-practice&quot;&gt;What “Serviced
Software” looks like in practice&lt;/h2&gt;
&lt;p&gt;If you accept that the value has shifted from code creation to code
stewardship, a few things follow:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Platform engineering matters more than feature
engineering.&lt;/strong&gt; Internal developer platforms (Backstage, Port,
Humanitec) that abstract away infrastructure and enforce guardrails are
more valuable than another AI code assistant. The companies investing in
paved roads for deployment, observability, and incident response will
win over those investing in faster code generation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Managed services eat custom code.&lt;/strong&gt; Every line of
custom infrastructure code is a future maintenance burden. I learned
this the hard way running &lt;a
href=&quot;https://whatnicklife.blogspot.com/2020/07/microservices-hardway.html&quot;&gt;microservices
from folders on EC2&lt;/a&gt; – cron jobs, plain-text .env files, manual venv
management. It worked, but every operational incident was my problem.
The appeal of managed Postgres over self-hosted, or Vercel over
hand-rolled CI/CD, is not laziness. It is recognizing where your scarce
operational attention should go.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Security becomes the primary differentiator.&lt;/strong&gt; When
everyone can generate a working app, the ones that survive are the ones
that do not get breached. Supply chain attacks, dependency confusion,
credential leaks in AI-generated code that helpfully hardcoded an API
key – these are the failure modes of the vibe-coding era. Security is
not a feature you bolt on; it is the service layer that justifies the
subscription.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cost modeling is a core engineering skill.&lt;/strong&gt; I wrote
about &lt;a
href=&quot;https://whatnicklife.blogspot.com/2020/07/microservices-hardway.html&quot;&gt;EKS
baseline costs&lt;/a&gt; being $70/month for personal projects back in 2020.
That sensitivity to operational cost used to be a niche concern. Now
that anyone can spin up infrastructure with a prompt, understanding what
it costs to keep running is table stakes. Cloud bills are the new
technical debt – invisible until they are catastrophic.&lt;/p&gt;
&lt;h2 id=&quot;tactical-tornados-vs-strategic-maintainers&quot;&gt;Tactical tornados vs
strategic maintainers&lt;/h2&gt;
&lt;p&gt;Every engineering org has its archetypes. The &lt;strong&gt;tactical
tornado&lt;/strong&gt; is the superstar feature developer who can bang out a
new module in a weekend, leave a trail of impressed stakeholders, and
move on to the next shiny thing. They are celebrated in sprint reviews,
promoted quickly, and held up as the template for “10x engineers.”
Product managers love them because they turn roadmap dreams into
demo-able reality at terrifying speed. AI amplifies the tornado: give
them Copilot and a weekend and they will generate an entire product
surface.&lt;/p&gt;
&lt;p&gt;Then Monday arrives. The tornado has moved on to the next feature.
Someone else inherits the code–no tests beyond the happy path, no
runbooks, secrets in environment variables that nobody documented, an
autoscaling policy copied from a blog post that assumed a different
traffic shape. The tactical tornado created value in a burst. The
&lt;strong&gt;strategic maintainer&lt;/strong&gt; captures it over months.&lt;/p&gt;
&lt;p&gt;Strategic maintainers are the people who go deep on the two or three
features that actually drive revenue. They understand the edge cases
customers hit at 2am. They know which database index is holding the
query plan together and what happens when the table crosses 50 million
rows. They are the ones who turn a flashy demo into a reliable
product–incrementally tightening error handling, adding observability,
negotiating with product managers about which “small” feature requests
would actually require rewriting the payment flow.&lt;/p&gt;
&lt;p&gt;Product managers sit in the middle of this tension. A good PM dreams
up the features that will deliver the most value and sequences them so
the team can ship without drowning in maintenance debt. A less
experienced PM treats every sprint as a feature factory, stacking new
work on top of un-serviced foundations, because the roadmap rewards
visible output over invisible resilience. In the Serviced Software
framing, the PM’s job is not just “what should we build next?” but “what
is costing us the most to keep running, and is it worth it?”&lt;/p&gt;
&lt;p&gt;The industry has historically rewarded tornados and feature-shipping
PMs disproportionately. Promotions go to the person who launched the
thing, not the person who kept it alive for three years. AI will sharpen
this imbalance unless orgs explicitly revalue the strategic maintainer.
When code generation is cheap, the scarce skill is not writing new
software–it is understanding existing software deeply enough to keep it
healthy.&lt;/p&gt;
&lt;h2 id=&quot;the-human-layer&quot;&gt;The human layer&lt;/h2&gt;
&lt;p&gt;There is a deeper point here that goes beyond tooling. The shift from
SaaS to Serviced Software is really a shift from
&lt;strong&gt;building&lt;/strong&gt; to &lt;strong&gt;caring&lt;/strong&gt;. Building is
exciting, creative, dopamine-rich. Caring is routine, patient, often
invisible. Our industry has always undervalued the people who keep the
lights on relative to the people who ship new features. AI will widen
that gap unless we consciously correct for it.&lt;/p&gt;
&lt;p&gt;The sysadmin, the SRE, the on-call engineer, the person who actually
reads the CVE advisories and patches before the exploit drops – these
roles are becoming more important, not less. The code is becoming
commodity. The care is becoming scarce.&lt;/p&gt;
&lt;h2 id=&quot;where-this-goes&quot;&gt;Where this goes&lt;/h2&gt;
&lt;p&gt;I do not think SaaS as a business model disappears. But I think the
honest version of what customers are paying for will increasingly sound
like: “We run and maintain this software so you do not have to.” That is
not a new idea – managed hosting has existed forever. What is new is
that the software layer itself is becoming thin enough that the
operational layer dominates the value proposition.&lt;/p&gt;
&lt;p&gt;We are entering an era where the question is not “can you build it?”
but “can you keep it running, secure, updated, and affordable for the
next five years?” The answer to that question has never been a one-shot
prompt. It is a sustained commitment – and that, for now, remains
stubbornly human.&lt;/p&gt;
</content><link rel='replies' type='application/atom+xml' href='http://whatnicklife.blogspot.com/feeds/1788928931185438421/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3220006345447041404/1788928931185438421' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3220006345447041404/posts/default/1788928931185438421'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3220006345447041404/posts/default/1788928931185438421'/><link rel='alternate' type='text/html' href='http://whatnicklife.blogspot.com/2026/04/from-saas-to-serviced-software-code-was.html' title='From SaaS to Serviced Software -- the code was never the hard part'/><author><name>Tisham Dhar</name><uri>http://www.blogger.com/profile/15154154153085427197</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3220006345447041404.post-604579248761733803</id><published>2026-03-07T16:00:00.000-08:00</published><updated>2026-03-08T00:02:48.833-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="acolite"/><category scheme="http://www.blogger.com/atom/ns#" term="acp"/><category scheme="http://www.blogger.com/atom/ns#" term="agents"/><category scheme="http://www.blogger.com/atom/ns#" term="ai"/><category scheme="http://www.blogger.com/atom/ns#" term="earth-observation"/><category scheme="http://www.blogger.com/atom/ns#" term="foss4g"/><category scheme="http://www.blogger.com/atom/ns#" term="kubernetes"/><category scheme="http://www.blogger.com/atom/ns#" term="performance"/><category scheme="http://www.blogger.com/atom/ns#" term="rust"/><title type='text'>Two Agents, One Codebase: An F1 Race Team Approach to Porting ACOLITE to Rust</title><content type='html'>&lt;p&gt;In Formula 1, every team fields two drivers. Not as a backup plan – as a strategy. One driver pushes the pace, forcing rivals to respond. The other holds position, manages tyres, and covers the alternative strategy. They share telemetry, they share a garage, but they are running different races on the same track. The team wins when both cars score points, not when one driver tries to do everything.&lt;/p&gt;
&lt;p&gt;Porting a scientific Python codebase to Rust feels remarkably similar. You need the aggressive driver – the one who charges into unfamiliar code and lays down fast laps of Rust implementation. And you need the calculating driver – the one who reads the data, watches for degradation, and calls out when the numerical precision is drifting. Two AI coding agents, paired like Norris and Piastri, sharing a codebase but operating on different parts of the problem.&lt;/p&gt;
&lt;iframe src=&quot;https://www.youtube.com/embed/F-dVCeV3_H8&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;h2 id=&quot;the-starting-grid-why-rust-for-acolite&quot;&gt;The Starting Grid: Why Rust for ACOLITE?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/acolite/acolite&quot;&gt;ACOLITE&lt;/a&gt; is RBINS’ atmospheric correction toolkit for aquatic remote sensing. It handles everything from Landsat and Sentinel-2 to hyperspectral sensors like PACE OCI (286 bands) and PRISMA (239 bands). The Dark Spectrum Fitting (DSF) algorithm is elegant – image-based, no external atmospheric inputs – but in Python, processing a full PACE scene involves reading 291 NetCDF variables, interpolating multi-dimensional LUTs, and correcting each pixel’s reflectance through a chain of gas transmittance, Rayleigh scattering, and aerosol models. On a decent machine, this takes around 230 seconds.&lt;/p&gt;
&lt;p&gt;The seed was planted at FOSS4G 2025 in Auckland when Leo Hardtke ran a tutorial on Earth Observation processing with Rust. It was plagued by Nix environment issues (as I noted in my &lt;a href=&quot;https://whatnicklife.blogspot.com/2025/11/foss4g-2025-auckland-hazy-hops-and.html&quot;&gt;conference write-up&lt;/a&gt;), but when the code ran, it was fast. Zero-cost abstractions and fearless concurrency are not just slogans at that point – they are wall-clock seconds you are not spending waiting for your atmospheric correction to finish.&lt;/p&gt;
&lt;p&gt;I had also been watching Rob Woodcock’s &lt;a href=&quot;https://github.com/woodcockr/acolite/blob/acolite-mp/README-ACOLITE-MP.md&quot;&gt;acolite-mp&lt;/a&gt; branch, which tackled the same performance problem from within Python. His approach was clever: per-band parallelism with memory budgets tuned to cloud CPU-to-RAM ratios (2, 4, or 8 GiB per core), replacing NumPy’s interpolation with the multithreaded &lt;code&gt;pyinterp&lt;/code&gt;, and carefully managing the GIL contention that Python’s threading model inflicts on you. He got Sentinel-2 from 791s down to 197s and Landsat from 312s to 99s on a 24-core i9 – roughly a 3-4x speedup.&lt;/p&gt;
&lt;p&gt;But the GIL is still there. The memory model is still Python’s. And as Rob himself noted, “further performance improvements are possible but require more extensive changes to the file handling” and “there is a fair amount of GIL contention which limits threading being caused by some structural choices in the implementation.” At some point, you are fighting the language rather than the problem.&lt;/p&gt;
&lt;p&gt;Rust sidesteps all of this. No GIL. No garbage collector. Rayon gives you data-parallel iterators that map across bands or tiles with work-stealing. Memory usage is deterministic and known at compile time – you can profile it statically before deploying, which is a sentence that makes no sense in Python-land but is table stakes in systems programming.&lt;/p&gt;
&lt;h2 id=&quot;the-pit-crew-two-agents-via-acp&quot;&gt;The Pit Crew: Two Agents via ACP&lt;/h2&gt;
&lt;p&gt;Here is where the teammate analogy really kicks in. In F1, a team with only one driver is not half a team – it is no team at all. You cannot run a split strategy with a single car. You cannot use one driver to hold up a rival while the other pulls a gap. The performance of the pair exceeds the sum of the individuals because they create options that a solo driver simply cannot.&lt;/p&gt;
&lt;p&gt;Porting 40,000+ lines of scientific Python to Rust is the same. A single AI agent writing Rust will drift – the implementation slowly diverging from Python’s numerical behaviour until your reflectance values are off by just enough to be scientifically useless. You need the second driver to keep it honest.&lt;/p&gt;
&lt;p&gt;The solution I landed on was a &lt;a href=&quot;https://github.com/whatnick/acolite/tree/feature/rust-port&quot;&gt;multi-agent orchestration harness&lt;/a&gt; using the &lt;a href=&quot;https://agentclientprotocol.com/&quot;&gt;Agent Client Protocol (ACP)&lt;/a&gt;, a JSON-RPC 2.0 protocol over NDJSON stdio that lets coding agents communicate in a structured way:&lt;/p&gt;
&lt;table&gt;
&lt;colgroup&gt;
&lt;col style=&quot;width: 24%&quot; /&gt;
&lt;col style=&quot;width: 20%&quot; /&gt;
&lt;col style=&quot;width: 55%&quot; /&gt;
&lt;/colgroup&gt;
&lt;thead&gt;
&lt;tr class=&quot;header&quot;&gt;
&lt;th&gt;Agent&lt;/th&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;th&gt;F1 Equivalent&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr class=&quot;odd&quot;&gt;
&lt;td&gt;&lt;strong&gt;Kiro&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Executor – writes Rust code, runs tests, reads files&lt;/td&gt;
&lt;td&gt;Lead driver – pushes the pace, sets fast laps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class=&quot;even&quot;&gt;
&lt;td&gt;&lt;strong&gt;Copilot&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Proposer – reviews output, suggests next steps, cross-checks Python&lt;/td&gt;
&lt;td&gt;Second driver – covers the strategy, watches the gaps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class=&quot;odd&quot;&gt;
&lt;td&gt;&lt;strong&gt;Human&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Approver – filters proposals before dispatch&lt;/td&gt;
&lt;td&gt;Team principal – makes the call on when to pit&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The workflow per sensor port looks like this:&lt;/p&gt;
&lt;ol type=&quot;1&quot;&gt;
&lt;li&gt;Human provides &lt;code&gt;--task&lt;/code&gt; to the orchestrator (&lt;code&gt;tools/agent_harness.py&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Kiro receives the task via ACP &lt;code&gt;session/prompt&lt;/code&gt; and starts writing code&lt;/li&gt;
&lt;li&gt;Kiro streams output via &lt;code&gt;session/update&lt;/code&gt; chunks&lt;/li&gt;
&lt;li&gt;Output goes to Copilot for review against the Python source&lt;/li&gt;
&lt;li&gt;Copilot proposes &lt;code&gt;ACTION:&lt;/code&gt; lines – “fix the gas transmittance interpolation order”, “the Rayleigh LUT needs pressure stacking”&lt;/li&gt;
&lt;li&gt;Human approves or rejects&lt;/li&gt;
&lt;li&gt;Approved actions go back to Kiro&lt;/li&gt;
&lt;li&gt;Repeat until regression tests pass or maximum cycles reached&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This is not vibe coding. This is a two-car team running a split strategy.&lt;/p&gt;
&lt;p&gt;Think about how McLaren or Red Bull operate. The lead driver qualifies on pole and sets the pace in clean air. The second driver starts on a different tyre compound, runs a longer first stint, and emerges from the pits into a different part of the field. They are solving complementary problems – one optimises for raw speed, the other for strategic coverage. Neither is redundant.&lt;/p&gt;
&lt;p&gt;Kiro is the lead driver. It attacks the Rust implementation aggressively – writing loaders, porting DSF algorithms, wiring up rayon parallelism. It sets fast laps. It also occasionally bins it into the gravel trap by hallucinating a NumPy broadcasting rule that does not exist in ndarray.&lt;/p&gt;
&lt;p&gt;Copilot is the second driver. It reads the Python source, cross-references the Rust output, and spots where the gap to parity is growing. “The gas transmittance interpolation order is wrong” is exactly the kind of radio call a second driver makes – not flashy, but it prevents a DNF.&lt;/p&gt;
&lt;p&gt;The human is the team principal. You do not override the drivers on every corner, but you make the strategic calls: do we pit now and fix this RMSE regression, or do we push on and address it in the next stint? Is a 0.002 RMSE difference in Sentinel-2 reflectance acceptable? (It is – that is within float32 precision.) When do we switch from tiled DSF to fixed DSF mode for this sensor?&lt;/p&gt;
&lt;p&gt;Together, they converge faster than either alone, for the same reason that two cars gathering tyre data in free practice gives the team more information than one car doing twice as many laps.&lt;/p&gt;
&lt;h2 id=&quot;the-telemetry-regression-tests-against-real-data&quot;&gt;The Telemetry: Regression Tests Against Real Data&lt;/h2&gt;
&lt;p&gt;In F1, both drivers generate telemetry. The team overlays their data – braking points, throttle application, cornering speed – to find where one is faster and why. The overlay is the truth. Not the driver’s feeling, not the engineer’s simulation, but what the car actually did on the track.&lt;/p&gt;
&lt;p&gt;Regression tests are our telemetry overlay. The Python ACOLITE output is Driver 1’s trace. The Rust output is Driver 2’s. We overlay them pixel-by-pixel, band-by-band, and look at the delta. When the traces diverge, something real has changed and we need to understand whether it is a genuine improvement or an error we need to correct.&lt;/p&gt;
&lt;p&gt;There are currently 141 Python regression tests that compare Rust output against Python output pixel-by-pixel across real satellite scenes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Landsat 8/9&lt;/strong&gt;: 13 regression + 13 Rust-vs-Python + 7 benchmark tests&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sentinel-2 A/B&lt;/strong&gt;: 19 regression + 15 Rust-vs-Python + 9 benchmark tests&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PACE OCI&lt;/strong&gt;: 17 regression + 14 Rust-vs-Python + 12 DSF comparison + 12 ROI + 10 full-scene tests&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The tolerances are tight. Sentinel-2 achieves RMSE &amp;lt; 0.002 (physics-equivalent). Landsat gets RMSE &amp;lt; 0.02. PACE full-scene (1710 x 1272 pixels x 291 bands) hits mean RMSE of 0.004 with 100% of pixels within 0.05 of Python. Correlation coefficients are R &amp;gt; 0.999 across all sensors.&lt;/p&gt;
&lt;p&gt;These are not toy tests on synthetic data. They run against actual L1 scenes downloaded from USGS and NASA. When the tests break, something real is wrong.&lt;/p&gt;
&lt;h2 id=&quot;the-performance-gap-where-the-seconds-go&quot;&gt;The Performance Gap: Where the Seconds Go&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr class=&quot;header&quot;&gt;
&lt;th&gt;Sensor&lt;/th&gt;
&lt;th&gt;Scene Size&lt;/th&gt;
&lt;th&gt;Rust&lt;/th&gt;
&lt;th&gt;Python&lt;/th&gt;
&lt;th&gt;Speedup&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr class=&quot;odd&quot;&gt;
&lt;td&gt;Landsat 8&lt;/td&gt;
&lt;td&gt;62M px x 7 bands&lt;/td&gt;
&lt;td&gt;66s&lt;/td&gt;
&lt;td&gt;180s&lt;/td&gt;
&lt;td&gt;2.7x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class=&quot;even&quot;&gt;
&lt;td&gt;Landsat 9&lt;/td&gt;
&lt;td&gt;62M px x 7 bands&lt;/td&gt;
&lt;td&gt;56s&lt;/td&gt;
&lt;td&gt;180s&lt;/td&gt;
&lt;td&gt;3.2x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class=&quot;odd&quot;&gt;
&lt;td&gt;Sentinel-2 A&lt;/td&gt;
&lt;td&gt;30M px x 11 bands&lt;/td&gt;
&lt;td&gt;52s&lt;/td&gt;
&lt;td&gt;182s&lt;/td&gt;
&lt;td&gt;3.5x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class=&quot;even&quot;&gt;
&lt;td&gt;Sentinel-2 B&lt;/td&gt;
&lt;td&gt;30M px x 11 bands&lt;/td&gt;
&lt;td&gt;64s&lt;/td&gt;
&lt;td&gt;173s&lt;/td&gt;
&lt;td&gt;2.7x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class=&quot;odd&quot;&gt;
&lt;td&gt;PACE OCI (full)&lt;/td&gt;
&lt;td&gt;1710 x 1272 x 291 bands&lt;/td&gt;
&lt;td&gt;84s&lt;/td&gt;
&lt;td&gt;230s&lt;/td&gt;
&lt;td&gt;2.7x&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The PACE result is particularly satisfying. The key optimisation was switching from 291 per-band NetCDF reads to 3 bulk detector reads, then applying rayon-parallel atmospheric correction across tiles. Load is 12 seconds, AC is 34 seconds, write is 35 seconds. That write phase for a 291-band hyperspectral cube goes to GeoZarr V3 with gzip compression – try doing that in a Python event loop without your memory allocator throwing a tantrum.&lt;/p&gt;
&lt;h2 id=&quot;energy-efficiency-the-fuel-strategy-nobody-talks-about&quot;&gt;Energy Efficiency: The Fuel Strategy Nobody Talks About&lt;/h2&gt;
&lt;p&gt;Here is the part where I get philosophical – and where the F1 analogy turns from metaphor into mirror.&lt;/p&gt;
&lt;p&gt;Formula 1 underwent a &lt;a href=&quot;https://www.redbull.com/us-en/fuel-efficiency-strategies-in-formula-1-racing&quot;&gt;fuel efficiency revolution in 2014&lt;/a&gt;. The FIA introduced hybrid power units, capped fuel flow at 100 kg/hour (monitored 2,200 times per second), and forced teams to extract maximum performance from minimum fuel. The result was not slower cars – it was faster cars that used less. The 2026 regulations go further: fossil carbon is prohibited entirely, the MGU-K will deliver three times the electrical power (350kW vs today’s 120kW), producing up to 1,000 horsepower while burning sustainable fuel. Less fuel, more power. That is not a trade-off – it is an engineering constraint that drives innovation.&lt;/p&gt;
&lt;p&gt;The same constraint applies to scientific computing, we just pretend it does not. Cloud computing bills are denominated in dollars, but the underlying unit is energy. Every CPU cycle your atmospheric correction burns is a watt drawn from a power grid somewhere. When you are processing continental-scale Sentinel-2 archives or the full PACE ocean colour mission, those watts add up. Python is the V10 era of scientific computing – glorious, unrestricted, and profligate with resources.&lt;/p&gt;
&lt;p&gt;Rust is the hybrid power unit. Its advantage is not just speed – it is energy per unit of work. A 3x speedup roughly translates to using a third of the compute time, which means a third of the energy, a third of the carbon footprint, and a third of your AWS bill. The Rust Foundation and others have pointed to studies showing compiled languages like Rust and C using an order of magnitude less energy than interpreted languages for equivalent workloads. Just as F1 teams discovered that fuel efficiency constraints forced them to build fundamentally better engines, switching to Rust forces you to think about memory layout, allocation patterns, and data flow in ways that Python’s garbage collector lets you ignore – until the bill arrives.&lt;/p&gt;
&lt;p&gt;And here is the irony that would make an F1 sustainability officer wince: Earth observation processing is meant to monitor the planet’s health. Burning excess energy to do it is like running your emissions-monitoring car on leaded fuel. F1 recognised that the sport’s 20-car grid is only 1% of its total carbon footprint, but pursued fuel efficiency anyway because the technology trickles down. The same logic applies to EO processing pipelines. The individual savings per scene are modest, but at continental archive scale they compound – just like how F1’s hybrid innovations now power road cars from Ferrari’s SF90 to the electric components in every modern turbo engine.&lt;/p&gt;
&lt;p&gt;Static memory profiling makes this tangible. In Rust, I can tell you at compile time that a Sentinel-2 full-scene atmospheric correction will peak at approximately N gigabytes of memory, because the allocations are deterministic. In Python, you find out at runtime – usually when the OOM killer visits your pod. F1 teams know their fuel load to the gram before the formation lap. Rust gives you the same certainty for compute.&lt;/p&gt;
&lt;h2 id=&quot;kubernetes-1.35-and-vertical-pod-autoscaling&quot;&gt;Kubernetes 1.35 and Vertical Pod Autoscaling&lt;/h2&gt;
&lt;p&gt;This deterministic memory behaviour dovetails nicely with Kubernetes 1.35’s improvements to &lt;a href=&quot;https://github.com/kubernetes/autoscaler/tree/master/vertical-pod-autoscaler&quot;&gt;Vertical Pod Autoscaler (VPA)&lt;/a&gt;. VPA watches your pod’s actual resource usage and adjusts CPU and memory requests/limits accordingly. When your workload has predictable resource usage – as Rust workloads tend to – VPA converges quickly to the right allocation instead of oscillating between OOM kills and wasted headroom.&lt;/p&gt;
&lt;p&gt;For a processing pipeline that ingests satellite scenes of varying sizes (a Landsat scene is 62 million pixels across 7 bands; a PACE scene is 2.2 million pixels across 291 bands), VPA can right-size pods per sensor type. Rust’s static memory profile means the VPA recommendations stabilise fast, which means tighter bin-packing, which means more scenes processed per node, which means lower cost per scene.&lt;/p&gt;
&lt;p&gt;Compare this to Python pods where memory usage is non-deterministic, garbage collection spikes are unpredictable, and the VPA has to overprovision to avoid OOM. The 2 GiB/core cloud ratio that Rob’s acolite-mp was carefully designed around becomes less of a constraint when your language does not waste half of it on interpreter overhead.&lt;/p&gt;
&lt;h2 id=&quot;out-of-band-development-preventing-merge-conflicts-with-upstream&quot;&gt;Out-of-Band Development: Preventing Merge Conflicts with Upstream&lt;/h2&gt;
&lt;p&gt;One design decision I am particularly happy with is keeping the Rust port on a separate feature branch (&lt;code&gt;feature/rust-port&lt;/code&gt;) and treating it as out-of-band from the Python codebase. ACOLITE upstream is actively maintained by Quinten Vanhellemont at RBINS, with regular additions of new sensors, algorithm refinements, and bug fixes. A traditional “rewrite in Rust” approach would create an immediate fork that diverges with every upstream commit.&lt;/p&gt;
&lt;p&gt;Instead, the Rust code lives in &lt;code&gt;src/&lt;/code&gt;, &lt;code&gt;benches/&lt;/code&gt;, and &lt;code&gt;tests/&lt;/code&gt; directories that do not exist in upstream Python ACOLITE. The Python code in &lt;code&gt;acolite/&lt;/code&gt; stays untouched. The regression tests are the synchronisation mechanism – they import both the Python ACOLITE modules and the compiled Rust binary, run the same scene through both, and compare outputs.&lt;/p&gt;
&lt;p&gt;When upstream adds a new sensor or changes a gas transmittance coefficient, the regression tests fail in the Rust port. That failure is the trigger: it goes into the agent harness as a &lt;code&gt;--task&lt;/code&gt;, Kiro investigates the numerical difference, Copilot cross-references the upstream commit, and the fix lands in Rust without touching a single Python file. No merge conflicts. No rebasing nightmares. Just tests that enforce parity.&lt;/p&gt;
&lt;p&gt;This is how you keep an acceleration layer in sync with a moving target – you do not try to merge them. You test them against each other.&lt;/p&gt;
&lt;h2 id=&quot;what-is-next-the-gap-to-full-sensor-parity&quot;&gt;What Is Next: The Gap to Full Sensor Parity&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/whatnick/acolite/blob/feature/rust-port/RUST_PORT_ROADMAP.md&quot;&gt;roadmap&lt;/a&gt; has the current state at 48 Rust tests, 141 Python regression tests, and three sensors fully validated (Landsat 8/9, Sentinel-2 A/B, PACE OCI). The architecture – loader, AC, writer – is clean and extensible. But three sensors out of 30+ is a qualifying lap, not a race win. Here is what closing the gap to full ACOLITE parity actually looks like.&lt;/p&gt;
&lt;h3 id=&quot;sensor-coverage-3-down-30-to-go&quot;&gt;Sensor Coverage: 3 down, 30+ to go&lt;/h3&gt;
&lt;p&gt;Python ACOLITE supports a sprawling constellation of sensors. The Rust port has ticked off the three highest-priority ones but the remaining fleet breaks into tiers:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tier 1 – Near-term (shared loader patterns exist):&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr class=&quot;header&quot;&gt;
&lt;th&gt;Sensor&lt;/th&gt;
&lt;th&gt;Bands&lt;/th&gt;
&lt;th&gt;Loader Type&lt;/th&gt;
&lt;th&gt;Blocker&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr class=&quot;odd&quot;&gt;
&lt;td&gt;Sentinel-3 OLCI&lt;/td&gt;
&lt;td&gt;21&lt;/td&gt;
&lt;td&gt;NetCDF&lt;/td&gt;
&lt;td&gt;Sensor def exists, needs full pipeline&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class=&quot;even&quot;&gt;
&lt;td&gt;PRISMA&lt;/td&gt;
&lt;td&gt;239&lt;/td&gt;
&lt;td&gt;HDF5&lt;/td&gt;
&lt;td&gt;Shares pattern with PACE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class=&quot;odd&quot;&gt;
&lt;td&gt;DESIS&lt;/td&gt;
&lt;td&gt;235&lt;/td&gt;
&lt;td&gt;HDF5&lt;/td&gt;
&lt;td&gt;Shares pattern with PACE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class=&quot;even&quot;&gt;
&lt;td&gt;EnMAP&lt;/td&gt;
&lt;td&gt;224&lt;/td&gt;
&lt;td&gt;HDF5&lt;/td&gt;
&lt;td&gt;Shares pattern with PACE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class=&quot;odd&quot;&gt;
&lt;td&gt;EMIT&lt;/td&gt;
&lt;td&gt;285&lt;/td&gt;
&lt;td&gt;NetCDF&lt;/td&gt;
&lt;td&gt;Similar to PACE OCI&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;These are the low-hanging fruit. The PACE port proved out the NetCDF and hyperspectral GeoZarr writer path; PRISMA/DESIS/EnMAP share the HDF5 loader pattern. Each is a well-scoped &lt;code&gt;--task&lt;/code&gt; for the agent harness – Kiro writes the loader and wires up the AC pipeline, Copilot validates against Python output on a reference scene.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tier 2 – Medium-term (new loader work required):&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr class=&quot;header&quot;&gt;
&lt;th&gt;Sensor&lt;/th&gt;
&lt;th&gt;Bands&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr class=&quot;odd&quot;&gt;
&lt;td&gt;Landsat 5 TM / 7 ETM+&lt;/td&gt;
&lt;td&gt;7-8&lt;/td&gt;
&lt;td&gt;Older calibration metadata formats&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class=&quot;even&quot;&gt;
&lt;td&gt;PlanetScope (Dove/SuperDove)&lt;/td&gt;
&lt;td&gt;4-8&lt;/td&gt;
&lt;td&gt;Commercial format, GeoTIFF based&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class=&quot;odd&quot;&gt;
&lt;td&gt;WorldView-2/3&lt;/td&gt;
&lt;td&gt;6-29&lt;/td&gt;
&lt;td&gt;Multi-resolution, pan-sharpening&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class=&quot;even&quot;&gt;
&lt;td&gt;Pleiades&lt;/td&gt;
&lt;td&gt;5-7&lt;/td&gt;
&lt;td&gt;DIMAP format&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class=&quot;odd&quot;&gt;
&lt;td&gt;QuickBird-2&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Legacy but still used&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class=&quot;even&quot;&gt;
&lt;td&gt;VIIRS (NPP/J1/J2)&lt;/td&gt;
&lt;td&gt;22&lt;/td&gt;
&lt;td&gt;Swath-based HDF5, three platforms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class=&quot;odd&quot;&gt;
&lt;td&gt;Aqua/Terra MODIS&lt;/td&gt;
&lt;td&gt;36&lt;/td&gt;
&lt;td&gt;HDF4/HDF-EOS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class=&quot;even&quot;&gt;
&lt;td&gt;GOCI-2&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;Korean ocean colour mission&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Each of these needs a dedicated loader – different metadata formats, different calibration approaches, different file layouts. The atmospheric correction core (DSF, gas transmittance, Rayleigh, aerosol models) is shared, but getting the radiometrically calibrated top-of-atmosphere reflectance array into the pipeline is the per-sensor work.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tier 3 – Geostationary and niche (lowest priority for aquatic applications):&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;GOES ABI, Himawari AHI, MTG-I FCI, SEVIRI, Sentinel-3 SLSTR, AMAZONIA-1 WFI, CHRIS, HYPERION, HICO, HyperField, HYPSO, Tanager. Some of these (HYPERION, HICO) are decommissioned but their archives are still processed. Others (Tanager at 420 bands, HYPSO at 120) are newer hyperspectral missions that would benefit most from Rust’s performance advantage.&lt;/p&gt;
&lt;h3 id=&quot;beyond-loaders-the-algorithm-gap&quot;&gt;Beyond Loaders: The Algorithm Gap&lt;/h3&gt;
&lt;p&gt;Sensor parity is not just about reading files. Python ACOLITE has several processing features the Rust port does not yet implement:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ROI subsetting&lt;/strong&gt;: Limit processing to a bounding box or polygon – critical for operational workflows that do not need a full scene&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ancillary data retrieval&lt;/strong&gt;: NCEP ozone, pressure, and wind speed from NASA OBPG; currently the Rust port uses default values&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DEM-derived pressure&lt;/strong&gt;: Copernicus DEM at 30/90m for surface pressure estimation in mountainous coastal regions&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Glint correction&lt;/strong&gt;: Sun glint removal for low-latitude ocean scenes&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RAdCor adjacency correction&lt;/strong&gt;: The physics-based adjacency effect correction developed under the STEREO program&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;TACT thermal processing&lt;/strong&gt;: Surface temperature from Landsat thermal bands via libRadtran – this one is architecturally interesting because it requires calling an external Fortran radiative transfer code&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Interface reflectance (rsky)&lt;/strong&gt;: Sky reflection correction at the air-water interface&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;L2W water products&lt;/strong&gt;: Chlorophyll-a (OC algorithms), TSS (Nechad, Dogliotti), turbidity, Secchi depth – the derived products that downstream scientists actually use&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The L2W gap is the most consequential. Most ACOLITE users do not care about surface reflectance per se; they want chlorophyll maps or turbidity time series. Until the Rust port can produce L2W outputs, it remains a fast atmospheric correction engine rather than a complete aquatic remote sensing toolkit.&lt;/p&gt;
&lt;h3 id=&quot;the-realistic-path&quot;&gt;The Realistic Path&lt;/h3&gt;
&lt;p&gt;Closing this gap is not a sprint, it is an endurance race – appropriately enough. The agent harness makes each sensor port a repeatable, testable unit of work. The pattern is established: write loader, wire to AC pipeline, run regression tests against Python, fix deltas, validate on real data. Each sensor port takes the agents a day or two of focused work plus human review.&lt;/p&gt;
&lt;p&gt;At the current pace, Tier 1 sensors are within reach in the near term. Tier 2 will follow as the loader library matures. The algorithm features (ancillary data, glint, TACT) are orthogonal to sensor coverage and can be developed in parallel. L2W is the final milestone – when the Rust port can ingest a Sentinel-2 scene and produce a chlorophyll-a map that matches Python to within measurement uncertainty, the port will be race-ready for production.&lt;/p&gt;
&lt;p&gt;Each of these is a &lt;code&gt;--task&lt;/code&gt; for the agent harness. Two drivers, one constructor’s championship. The lead driver pushes into unfamiliar sensor territory, the second driver validates against Python, and the telemetry overlay catches every divergence before it compounds into a retirement.&lt;/p&gt;
&lt;p&gt;If the intersection of Rust, Earth observation, and AI-assisted development interests you, the code is all on &lt;a href=&quot;https://github.com/whatnick/acolite/tree/feature/rust-port&quot;&gt;GitHub&lt;/a&gt;. Feel free to ping me with ideas, bug reports, or competing approaches – especially if you have a cleverer way to handle the N-dimensional LUT interpolation. That one was a fun 3 days of Rapid Rust Rewrite fuelled by AI Amphetamine Analogs.&lt;/p&gt;
</content><link rel='replies' type='application/atom+xml' href='http://whatnicklife.blogspot.com/feeds/604579248761733803/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3220006345447041404/604579248761733803' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3220006345447041404/posts/default/604579248761733803'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3220006345447041404/posts/default/604579248761733803'/><link rel='alternate' type='text/html' href='http://whatnicklife.blogspot.com/2026/03/two-agents-one-codebase-f1-race-team.html' title='Two Agents, One Codebase: An F1 Race Team Approach to Porting ACOLITE to Rust'/><author><name>Tisham Dhar</name><uri>http://www.blogger.com/profile/15154154153085427197</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img.youtube.com/vi/F-dVCeV3_H8/default.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3220006345447041404.post-8038859141391912899</id><published>2026-02-27T16:00:00.000-08:00</published><updated>2026-02-28T14:37:38.221-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="arduino"/><category scheme="http://www.blogger.com/atom/ns#" term="arduino-cli"/><category scheme="http://www.blogger.com/atom/ns#" term="embedded"/><category scheme="http://www.blogger.com/atom/ns#" term="energy-monitor"/><category scheme="http://www.blogger.com/atom/ns#" term="esp32"/><category scheme="http://www.blogger.com/atom/ns#" term="github-copilot"/><category scheme="http://www.blogger.com/atom/ns#" term="logic-analyzer"/><category scheme="http://www.blogger.com/atom/ns#" term="saleae"/><title type='text'>Copilot + Arduino CLI + Saleae: Driver Development for V93XX</title><content type='html'>&lt;p&gt;I have been spending time building out the &lt;a
href=&quot;https://github.com/whatnick/V93XX_Arduino&quot;&gt;V93XX_Arduino&lt;/a&gt;
library for Vangotech energy-monitoring ASICs, and this is one of those
projects where tooling makes or breaks momentum.&lt;/p&gt;
&lt;p&gt;The pairing that worked best for me was:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/features/copilot&quot;&gt;GitHub Copilot&lt;/a&gt; for
repetitive protocol code, tests, and workflow glue&lt;/li&gt;
&lt;li&gt;&lt;a
href=&quot;https://arduino.github.io/arduino-cli/latest/&quot;&gt;arduino-cli&lt;/a&gt; for
deterministic compile and upload loops&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.saleae.com/&quot;&gt;Saleae Logic Analyzer&lt;/a&gt; captures
to confirm what is &lt;em&gt;actually&lt;/em&gt; on the wire&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The short version: Copilot gets you to a plausible driver quickly,
but the logic analyzer gets you to a &lt;em&gt;correct&lt;/em&gt; driver.&lt;/p&gt;
&lt;figure&gt;
&lt;iframe src=&quot;https://www.youtube.com/embed/7EaPbl-LAnU&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;figcaption&gt;V93XX driver workflow walkthrough&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;why-this-trio-works&quot;&gt;Why this trio works&lt;/h2&gt;
&lt;p&gt;Developing protocol drivers is usually a game of “spec says one
thing, silicon does another thing”.&lt;/p&gt;
&lt;p&gt;If you rely only on serial logs, you can miss timing and framing
issues. If you rely only on captures, you can waste hours writing
boilerplate and one-off scripts. Using these three together gives a
tighter loop:&lt;/p&gt;
&lt;ol type=&quot;1&quot;&gt;
&lt;li&gt;Copilot proposes code and tests from your intent&lt;/li&gt;
&lt;li&gt;Arduino CLI compiles and flashes quickly from scripts&lt;/li&gt;
&lt;li&gt;Saleae confirms framing, parity, baud behavior, and CRC bytes&lt;/li&gt;
&lt;li&gt;Copilot helps refactor after you learn what the bus is doing&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In practice, this turned the V9381 UART ChecksumMode and waveform/FFT
work from a stop-start activity into a repeatable pipeline.&lt;/p&gt;
&lt;h2 id=&quot;project-context-v93xx_arduino&quot;&gt;Project context:
V93XX_Arduino&lt;/h2&gt;
&lt;p&gt;Repository: &lt;a
href=&quot;https://github.com/whatnick/V93XX_Arduino&quot;&gt;whatnick/V93XX_Arduino&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The library currently covers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;V93XX_UART&lt;/code&gt; for V9360 and V9381 UART modes (including
address pins and checksum modes)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;V93XX_SPI&lt;/code&gt; for V9381 SPI paths (faster acquisition, up
to MHz clocks)&lt;/li&gt;
&lt;li&gt;Examples for baseline comms, waveform capture, and FFT&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Useful docs in the repo:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a
href=&quot;https://github.com/whatnick/V93XX_Arduino/blob/main/docs/GETTING_STARTED.md&quot;&gt;docs/GETTING_STARTED.md&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a
href=&quot;https://github.com/whatnick/V93XX_Arduino/blob/main/docs/TESTING.md&quot;&gt;docs/TESTING.md&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a
href=&quot;https://github.com/whatnick/V93XX_Arduino/blob/main/docs/COPILOT.md&quot;&gt;docs/COPILOT.md&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;practical-workflow&quot;&gt;Practical workflow&lt;/h2&gt;
&lt;h3 id=&quot;start-with-a-machine-checkable-baseline&quot;&gt;1) Start with a
machine-checkable baseline&lt;/h3&gt;
&lt;p&gt;Before touching hardware, run the local CRC and framing tests.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb1&quot;&gt;&lt;pre
class=&quot;sourceCode bash&quot;&gt;&lt;code class=&quot;sourceCode bash&quot;&gt;&lt;span id=&quot;cb1-1&quot;&gt;&lt;a href=&quot;#cb1-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;python&lt;/span&gt; tools/test_checksum_mode.py&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If this is red, do not flash anything yet.&lt;/p&gt;
&lt;h3 id=&quot;use-copilot-for-structured-implementation-work&quot;&gt;2) Use Copilot
for structured implementation work&lt;/h3&gt;
&lt;p&gt;I get better results when prompts are specific and constrained.
Example prompt:&lt;/p&gt;
&lt;pre class=&quot;text&quot;&gt;&lt;code&gt;Implement V9381 UART read path with explicit ChecksumMode behavior.
Keep Clean mode strict and Dirty mode permissive.
Add unit tests for CRC-8 edge cases and frame parsing.
Do not change public method names.&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Copilot is strongest here at:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Building test scaffolding quickly&lt;/li&gt;
&lt;li&gt;Keeping repetitive register access code consistent&lt;/li&gt;
&lt;li&gt;Producing incremental refactors after captures reveal protocol edge
cases&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;consume-datasheets-with-pdf-mcp-and-keep-them-in-repo&quot;&gt;3)
Consume datasheets with PDF MCP and keep them in-repo&lt;/h3&gt;
&lt;p&gt;Before generating more driver code, I now ingest the vendor datasheet
with &lt;a
href=&quot;https://github.com/SylphxAI/pdf-reader-mcp&quot;&gt;pdf-reader-mcp&lt;/a&gt; so
Copilot can work from extracted register tables and command framing
notes.&lt;/p&gt;
&lt;p&gt;My workflow is:&lt;/p&gt;
&lt;ol type=&quot;1&quot;&gt;
&lt;li&gt;Commit the original datasheet PDF to the repository, for example
under &lt;code&gt;docs/datasheets/v93xx/&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Use PDF MCP to extract the high-value sections (register map,
UART/SPI timing, checksum/CRC rules, waveform buffer details).&lt;/li&gt;
&lt;li&gt;Save extracted artifacts back into the repo as text or markdown
notes, for example
&lt;code&gt;docs/datasheets/v93xx/register_notes.md&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Prompt Copilot using both code and extracted notes so generated
changes are tied to concrete datasheet language.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This gives you a versioned paper trail from silicon docs to driver
behavior, which is very useful when reconciling captures from the logic
analyzer.&lt;/p&gt;
&lt;h3 id=&quot;compile-and-flash-with-arduino-cli&quot;&gt;4) Compile and flash with
Arduino CLI&lt;/h3&gt;
&lt;p&gt;For ESP32-S3 targets, this keeps the build deterministic and
scriptable:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb3&quot;&gt;&lt;pre
class=&quot;sourceCode bash&quot;&gt;&lt;code class=&quot;sourceCode bash&quot;&gt;&lt;span id=&quot;cb3-1&quot;&gt;&lt;a href=&quot;#cb3-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;arduino-cli&lt;/span&gt; board list&lt;/span&gt;
&lt;span id=&quot;cb3-2&quot;&gt;&lt;a href=&quot;#cb3-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;arduino-cli&lt;/span&gt; compile &lt;span class=&quot;at&quot;&gt;--fqbn&lt;/span&gt; esp32:esp32:esp32s3 examples/V9381_UART_DIRTY_MODE&lt;/span&gt;
&lt;span id=&quot;cb3-3&quot;&gt;&lt;a href=&quot;#cb3-3&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;arduino-cli&lt;/span&gt; upload &lt;span class=&quot;at&quot;&gt;--fqbn&lt;/span&gt; esp32:esp32:esp32s3 &lt;span class=&quot;at&quot;&gt;--port&lt;/span&gt; COM3 examples/V9381_UART_DIRTY_MODE&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;PowerShell users can run the project helper script:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb4&quot;&gt;&lt;pre
class=&quot;sourceCode powershell&quot;&gt;&lt;code class=&quot;sourceCode powershell&quot;&gt;&lt;span id=&quot;cb4-1&quot;&gt;&lt;a href=&quot;#cb4-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;\tools\run_automated_tests&lt;span class=&quot;op&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;fu&quot;&gt;ps1&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;Port COM3&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That pipeline can run unit tests, compile, upload, serial
verification, and optional capture/analysis phases.&lt;/p&gt;
&lt;h3 id=&quot;validate-on-wire-behavior-with-saleae&quot;&gt;5) Validate on-wire
behavior with Saleae&lt;/h3&gt;
&lt;p&gt;The logic analyzer phase is where protocol assumptions get
tested.&lt;/p&gt;
&lt;p&gt;For UART work:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Confirm bus settings (baud, parity, stop bits) match the target
mode&lt;/li&gt;
&lt;li&gt;Verify frame boundaries and inter-frame timing&lt;/li&gt;
&lt;li&gt;Check CRC byte placement and value against expected payload
sum/complement logic&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If using the helper scripts in this repo:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb5&quot;&gt;&lt;pre
class=&quot;sourceCode bash&quot;&gt;&lt;code class=&quot;sourceCode bash&quot;&gt;&lt;span id=&quot;cb5-1&quot;&gt;&lt;a href=&quot;#cb5-1&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;python&lt;/span&gt; tools/capture_v9381_uart.py&lt;/span&gt;
&lt;span id=&quot;cb5-2&quot;&gt;&lt;a href=&quot;#cb5-2&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;python&lt;/span&gt; tools/analyze_checksum_captures.py &lt;span class=&quot;pp&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;capture_dir&lt;/span&gt;&lt;span class=&quot;pp&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This gives a concrete report of expected vs observed CRC and whether
behaviour matches Clean vs Dirty semantics.&lt;/p&gt;
&lt;h2 id=&quot;what-changed-in-my-debugging-habits&quot;&gt;What changed in my
debugging habits&lt;/h2&gt;
&lt;h3 id=&quot;old-approach&quot;&gt;Old approach&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Edit sketch&lt;/li&gt;
&lt;li&gt;Upload&lt;/li&gt;
&lt;li&gt;Stare at serial output&lt;/li&gt;
&lt;li&gt;Guess&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;new-approach&quot;&gt;New approach&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Ask Copilot for narrow, test-backed change&lt;/li&gt;
&lt;li&gt;Build and flash with Arduino CLI from script&lt;/li&gt;
&lt;li&gt;Capture with Saleae and compare against expected frame math&lt;/li&gt;
&lt;li&gt;Feed mismatch details back into Copilot for targeted fixes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It feels closer to hardware TDD than trial-and-error firmware
hacking.&lt;/p&gt;
&lt;h2 id=&quot;trade-offs-and-cost-notes&quot;&gt;Trade-offs and cost notes&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Arduino CLI is free and excellent for repeatable CI-style local
loops&lt;/li&gt;
&lt;li&gt;Copilot is a paid productivity tool, but pays for itself when
protocol code churn is high&lt;/li&gt;
&lt;li&gt;Saleae hardware is not cheap, but it can save days when
parity/timing/CRC bugs are subtle&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you are doing serious serial or SPI driver work, a logic analyzer
is not optional for long.&lt;/p&gt;
&lt;h2 id=&quot;troubleshooting-notes-that-keep-coming-up&quot;&gt;Troubleshooting notes
that keep coming up&lt;/h2&gt;
&lt;ol type=&quot;1&quot;&gt;
&lt;li&gt;Wrong serial configuration (especially parity) can look like random
CRC failure.&lt;/li&gt;
&lt;li&gt;Upload success does not imply runtime protocol correctness.&lt;/li&gt;
&lt;li&gt;Dirty mode can hide issues by design; keep a Clean mode path for
strict validation.&lt;/li&gt;
&lt;li&gt;Keep datasheet extracts in-repo so Copilot prompts reference real
tables, not memory.&lt;/li&gt;
&lt;li&gt;A scripted workflow (&lt;code&gt;pdf-reader-mcp&lt;/code&gt; +
&lt;code&gt;arduino-cli&lt;/code&gt; + capture + analysis) beats ad-hoc manual steps
every time.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;closing&quot;&gt;Closing&lt;/h2&gt;
&lt;p&gt;For this V93XX work, the winning combination was AI-assisted coding
plus old-school instrumentation.&lt;/p&gt;
&lt;p&gt;Copilot helps me move faster, Arduino CLI keeps the loop
reproducible, and Saleae captures keep me honest.&lt;/p&gt;
&lt;p&gt;If you are building protocol drivers, treat those as complementary
tools, not alternatives.&lt;/p&gt;
</content><link rel='replies' type='application/atom+xml' href='http://whatnicklife.blogspot.com/feeds/8038859141391912899/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3220006345447041404/8038859141391912899' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3220006345447041404/posts/default/8038859141391912899'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3220006345447041404/posts/default/8038859141391912899'/><link rel='alternate' type='text/html' href='http://whatnicklife.blogspot.com/2026/02/copilot-arduino-cli-saleae-driver.html' title='Copilot + Arduino CLI + Saleae: Driver Development for V93XX'/><author><name>Tisham Dhar</name><uri>http://www.blogger.com/profile/15154154153085427197</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img.youtube.com/vi/7EaPbl-LAnU/default.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3220006345447041404.post-3902826425366259988</id><published>2026-01-27T16:00:00.000-08:00</published><updated>2026-02-01T14:55:15.971-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="artix-7"/><category scheme="http://www.blogger.com/atom/ns#" term="fpga"/><category scheme="http://www.blogger.com/atom/ns#" term="jtag"/><category scheme="http://www.blogger.com/atom/ns#" term="litex"/><category scheme="http://www.blogger.com/atom/ns#" term="netv2"/><category scheme="http://www.blogger.com/atom/ns#" term="openocd"/><category scheme="http://www.blogger.com/atom/ns#" term="pcileech"/><category scheme="http://www.blogger.com/atom/ns#" term="raspberry-pi"/><title type='text'>Loading FPGA Bitstreams with OpenOCD and Raspberry Pi - From Captain DMA to NeTV2</title><content type='html'>&lt;h2 id=&quot;a-hot-adelaide-afternoon-and-a-pile-of-fpgas&quot;&gt;A Hot Adelaide Afternoon and a Pile of FPGAs&lt;/h2&gt;
&lt;p&gt;I was recruited to wire together the NeTV2 to the Raspberry Pi 5 PCI bus by some means. &lt;a href=&quot;https://wafer.space/about.html&quot;&gt;Tim&lt;/a&gt; donated a bunch of hardware to make it work. I picked them up from his place, while he sorted through the contents of his container. The ultimate aim is to get them going as part of &lt;a href=&quot;https://ps1.fpgas.online/fpgas/&quot;&gt;fpgas.online&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The box contained a treasure trove: an NeTV2 boards from bunnie’s (Andrew Huang) video overlay project, and lots of Raspberry Pi’s. As I went down the rabbit hole I acquired some more hardware for myself, Captain DMA development boards, and various other Artix-7 based experiments (Acorn, LiteFury). These boards share a common trait – they’re designed to appear as network devices on a PCI Express bus, which makes them interesting for all sorts of applications from video processing to… let’s say “creative” system analysis and game hacking using auto-target features.&lt;/p&gt;
&lt;p&gt;The challenge with inheriting random FPGA boards is getting new gateware onto them. The original programming cables might be lost, proprietary software might be Windows-only and in Chinese, and documentation can be scarce. This is where OpenOCD and a humble Raspberry Pi come to the rescue. As long as you figure out which pins are the JTAG, and can get a &lt;a href=&quot;https://github.com/AlphamaxMedia/netv2mvp-scripts/pull/1&quot;&gt;PR merged&lt;/a&gt;.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;https://lh3.googleusercontent.com/pw/AP1GczOoOvoR6l13ubi_mrwFfM_4AexAW6DQ67SRTvG84NPs9llZma4NHTbgRZddiWEIbVjv7ujPzQsXrDTlO-DuvTyCz--4eKXX42wxqpAh3HmPKIcq81SGyrK7f5IVY1fBRHh-byXhQxAUtYIBd3pMgwRUQQ=w623-h827-s-no-gm?authuser=0&quot; alt=&quot;&quot; /&gt;&lt;figcaption&gt;Pi4 and Pi5 with NeTV2&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;the-problem-dma-cards-and-their-programming-woes&quot;&gt;The Problem: DMA Cards and Their Programming Woes&lt;/h2&gt;
&lt;p&gt;Captain DMA cards (and similar Artix-7 based DMA devices) typically come with a CH347 USB JTAG interface. The vendor provides a GUI tool, but it’s entirely in Chinese and only runs on Windows. For those of us who prefer reproducible, scripted workflows on Linux – or want to program boards headless on a Raspberry Pi – this is less than ideal.&lt;/p&gt;
&lt;p&gt;The workflow the GUI implements is actually straightforward:&lt;/p&gt;
&lt;ol type=&quot;1&quot;&gt;
&lt;li&gt;Connect to the CH347 JTAG interface&lt;/li&gt;
&lt;li&gt;Detect the FPGA/JTAG chain&lt;/li&gt;
&lt;li&gt;Load a BSCAN SPI bitstream for JTAG-to-SPI access&lt;/li&gt;
&lt;li&gt;Program the SPI flash with the target FPGA image&lt;/li&gt;
&lt;li&gt;Refresh the FPGA to load the new bitstream&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The key insight is that we’re not programming the FPGA directly – we’re using JTAG to access the SPI flash chip that stores the bitstream. The BSCAN primitive acts as a bridge between JTAG and the SPI flash.&lt;/p&gt;
&lt;h2 id=&quot;openocd-scripts-for-captain-dma&quot;&gt;OpenOCD Scripts for Captain DMA&lt;/h2&gt;
&lt;p&gt;I’ve put together a set of scripts at https://github.com/whatnick/fpga-dma-scripts that replicate the Chinese GUI’s functionality using pure OpenOCD commands. The scripts support Linux/macOS and Windows, and handle:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Automatic BSCAN bitstream download from quartiq’s prebuilt collection&lt;/li&gt;
&lt;li&gt;CH347 interface configuration installation&lt;/li&gt;
&lt;li&gt;Version checking for OpenOCD (needs 0.12.0+dev for CH347 support)&lt;/li&gt;
&lt;li&gt;Cross-platform flashing with proper error handling&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;
&lt;img src=&quot;https://lh3.googleusercontent.com/pw/AP1GczPqLlS0_Fq1p9r7yxBNHXH110BrGtYnbzos090yTkNh9eg_dLfoH4uCBVidZTUjEHbep07EJZ1xLxtyRg2cz_kSP5-T4r_m1hA3vvau9xRkNZamT8G6mIwK9vOE-0In1jeeLv6l_WCQzXHXy70ql4QjwQ=w1098-h827-s-no-gm?authuser=0&quot; alt=&quot;&quot; /&gt;&lt;figcaption&gt;Captain DMA clone attached to Raspberry Pi&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3 id=&quot;basic-usage&quot;&gt;Basic Usage&lt;/h3&gt;
&lt;p&gt;On Linux/macOS:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb1&quot;&gt;&lt;pre class=&quot;sourceCode bash&quot;&gt;&lt;code class=&quot;sourceCode bash&quot;&gt;&lt;span id=&quot;cb1-1&quot;&gt;&lt;a href=&quot;#cb1-1&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;./flash.sh&lt;/span&gt; 75t /path/to/pcileech_75t484_x1.bin&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;On Windows:&lt;/p&gt;
&lt;pre class=&quot;cmd&quot;&gt;&lt;code&gt;flash.cmd 75t C:\path\to\pcileech_75t484_x1.bin&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The scripts support three Artix-7 variants: 35T, 75T, and 100T. The underlying OpenOCD command is:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb3&quot;&gt;&lt;pre class=&quot;sourceCode bash&quot;&gt;&lt;code class=&quot;sourceCode bash&quot;&gt;&lt;span id=&quot;cb3-1&quot;&gt;&lt;a href=&quot;#cb3-1&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;openocd&lt;/span&gt; -c &lt;span class=&quot;st&quot;&gt;&amp;quot;set BSCAN_FILE bscan_spi_xc7a75t.bit&amp;quot;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-2&quot;&gt;&lt;a href=&quot;#cb3-2&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;ex&quot;&gt;-c&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;set FPGAIMAGE pcileech_75t484_x1.bin&amp;quot;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb3-3&quot;&gt;&lt;a href=&quot;#cb3-3&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;ex&quot;&gt;-f&lt;/span&gt; flash.cfg&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The flash.cfg orchestrates the JTAG chain detection, BSCAN loading, and SPI programming sequence.&lt;/p&gt;
&lt;h3 id=&quot;example-output&quot;&gt;Example Output&lt;/h3&gt;
&lt;p&gt;A successful flash looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Open On-Chip Debugger 0.12.0+dev-02377-gb9e401616 (2026-01-25-09:47)
Licensed under GNU GPL v2
For bug reports, read
        http://openocd.org/doc/doxygen/bugs.html
xc7_program
jtagspi_program
Info : CH347 USB To UART+JTAG from vendor wch.cn with serial number 0123456789 found. (Chip version=5.44, Firmware=0x45)
Info : clock speed 7500 kHz
Info : JTAG tap: xc7.tap tap/device found: 0x13632093 (mfg: 0x049 (Xilinx), part: 0x3632, ver: 0x1)
Info : [xc7.proxy] Examination succeed
Info : Found flash device &amp;#39;win w25q64fv/jv&amp;#39; (ID 0x1740ef)
Info : sector 0 took 234 ms
Info : sector 1 took 250 ms
...
Info : sector 32 took 259 ms
Info : sector 33 took 256 ms&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each sector takes about 230-260ms to program. A full 75T bitstream covers around 34 sectors, so expect 8-10 seconds for the flash operation.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;https://lh3.googleusercontent.com/pw/AP1GczOWiH7EPsnYT2TNeojmmERC_bMaomprkOQTDBU2O01TtNoX2w5f-m1VA3dsmcNbFfQ9GEZ5TQ2BLBNAUeF-vajcSMzXwtf1lzdK7oFaN-77kjOEej52QDaqun4EdPgxVdxmeAPZbGm-nOePuLR3TAghcQ=w1098-h827-s-no-gm?authuser=0&quot; alt=&quot;&quot; /&gt;&lt;figcaption&gt;NeTV2 Wired over PCI-e&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;netv2-bunnies-video-overlay-board&quot;&gt;NeTV2: Bunnie’s Video Overlay Board&lt;/h2&gt;
&lt;p&gt;The NeTV2 (Network Television version 2) is bunnie’s open-source HDMI video overlay board. It uses the same Xilinx Artix-7 family (XC7A35T or XC7A100T depending on variant) and was designed for real-time HDMI signal processing. The board features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Artix-7 FPGA (35T or 100T variant)&lt;/li&gt;
&lt;li&gt;DDR3 SDRAM (K4B2G1646F)&lt;/li&gt;
&lt;li&gt;PCIe x4 interface&lt;/li&gt;
&lt;li&gt;RMII Ethernet&lt;/li&gt;
&lt;li&gt;HDMI input and output&lt;/li&gt;
&lt;li&gt;SD card slot&lt;/li&gt;
&lt;li&gt;SPI flash for bitstream storage&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The original NeTV2 scripts from bunnie’s repo (https://github.com/bunnie/netv2mvp-scripts) were designed for Raspberry Pi 2/3 using the older sysfs GPIO interface. I’ve submitted a PR (https://github.com/AlphamaxMedia/netv2mvp-scripts/pull/1) that updates these for Raspberry Pi 4 and upstream OpenOCD.&lt;/p&gt;
&lt;h3 id=&quot;raspberry-pi-4-gpio-jtag-configuration&quot;&gt;Raspberry Pi 4 GPIO JTAG Configuration&lt;/h3&gt;
&lt;p&gt;The key changes for RPi4 compatibility involve the &lt;code&gt;bcm2835gpio&lt;/code&gt; driver configuration:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb5&quot;&gt;&lt;pre class=&quot;sourceCode tcl&quot;&gt;&lt;code class=&quot;sourceCode tcl&quot;&gt;&lt;span id=&quot;cb5-1&quot;&gt;&lt;a href=&quot;#cb5-1&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;# Boilerplate setup for Rpi on Alphamax configuration&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-2&quot;&gt;&lt;a href=&quot;#cb5-2&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-3&quot;&gt;&lt;a href=&quot;#cb5-3&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;adapter driver bcm2835gpio&lt;/span&gt;
&lt;span id=&quot;cb5-4&quot;&gt;&lt;a href=&quot;#cb5-4&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-5&quot;&gt;&lt;a href=&quot;#cb5-5&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;transport &lt;span class=&quot;ot&quot;&gt;select&lt;/span&gt; jtag&lt;/span&gt;
&lt;span id=&quot;cb5-6&quot;&gt;&lt;a href=&quot;#cb5-6&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-7&quot;&gt;&lt;a href=&quot;#cb5-7&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;set&lt;/span&gt; _CHIPNAME xc7a35t&lt;/span&gt;
&lt;span id=&quot;cb5-8&quot;&gt;&lt;a href=&quot;#cb5-8&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-9&quot;&gt;&lt;a href=&quot;#cb5-9&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;# Raspi4 uses a different peripheral base address&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-10&quot;&gt;&lt;a href=&quot;#cb5-10&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;# RPi 2/3: 0x3F000000&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-11&quot;&gt;&lt;a href=&quot;#cb5-11&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;# RPi 4:   0xFE000000&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-12&quot;&gt;&lt;a href=&quot;#cb5-12&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;bcm2835gpio peripheral_base &lt;span class=&quot;dv&quot;&gt;0x3F000000&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-13&quot;&gt;&lt;a href=&quot;#cb5-13&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-14&quot;&gt;&lt;a href=&quot;#cb5-14&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;# Speed coefficients tuned for RPi 3B+&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-15&quot;&gt;&lt;a href=&quot;#cb5-15&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;bcm2835gpio speed_coeffs &lt;span class=&quot;dv&quot;&gt;100000&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-16&quot;&gt;&lt;a href=&quot;#cb5-16&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-17&quot;&gt;&lt;a href=&quot;#cb5-17&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;# GPIO pin assignments for JTAG&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-18&quot;&gt;&lt;a href=&quot;#cb5-18&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;adapter gpio tck &lt;span class=&quot;dv&quot;&gt;4&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-19&quot;&gt;&lt;a href=&quot;#cb5-19&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;adapter gpio tms &lt;span class=&quot;dv&quot;&gt;17&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-20&quot;&gt;&lt;a href=&quot;#cb5-20&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;adapter gpio tdi &lt;span class=&quot;dv&quot;&gt;27&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-21&quot;&gt;&lt;a href=&quot;#cb5-21&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;adapter gpio tdo &lt;span class=&quot;dv&quot;&gt;22&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-22&quot;&gt;&lt;a href=&quot;#cb5-22&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;adapter gpio srst &lt;span class=&quot;dv&quot;&gt;24&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-23&quot;&gt;&lt;a href=&quot;#cb5-23&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-24&quot;&gt;&lt;a href=&quot;#cb5-24&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;reset_config none&lt;/span&gt;
&lt;span id=&quot;cb5-25&quot;&gt;&lt;a href=&quot;#cb5-25&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb5-26&quot;&gt;&lt;a href=&quot;#cb5-26&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;adapter speed &lt;span class=&quot;dv&quot;&gt;10000&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The GPIO pins map directly to the Raspberry Pi’s header:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr class=&quot;header&quot;&gt;
&lt;th&gt;Signal&lt;/th&gt;
&lt;th&gt;GPIO&lt;/th&gt;
&lt;th&gt;Physical Pin&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr class=&quot;odd&quot;&gt;
&lt;td&gt;TCK&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class=&quot;even&quot;&gt;
&lt;td&gt;TMS&lt;/td&gt;
&lt;td&gt;17&lt;/td&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class=&quot;odd&quot;&gt;
&lt;td&gt;TDI&lt;/td&gt;
&lt;td&gt;27&lt;/td&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class=&quot;even&quot;&gt;
&lt;td&gt;TDO&lt;/td&gt;
&lt;td&gt;22&lt;/td&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class=&quot;odd&quot;&gt;
&lt;td&gt;SRST&lt;/td&gt;
&lt;td&gt;24&lt;/td&gt;
&lt;td&gt;18&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&quot;spi-flash-programming-with-raspberry-pi&quot;&gt;SPI Flash Programming with Raspberry Pi&lt;/h3&gt;
&lt;p&gt;The cl-spifpga-rpi4.cfg config file handles the actual programming:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb6&quot;&gt;&lt;pre class=&quot;sourceCode tcl&quot;&gt;&lt;code class=&quot;sourceCode tcl&quot;&gt;&lt;span id=&quot;cb6-1&quot;&gt;&lt;a href=&quot;#cb6-1&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;# Burn an FPGA image onto the SPI ROM&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-2&quot;&gt;&lt;a href=&quot;#cb6-2&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-3&quot;&gt;&lt;a href=&quot;#cb6-3&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;source&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt;find&lt;/span&gt; interface/alphamax-rpi.cfg&lt;span class=&quot;kw&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-4&quot;&gt;&lt;a href=&quot;#cb6-4&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-5&quot;&gt;&lt;a href=&quot;#cb6-5&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;source&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt;find&lt;/span&gt; cpld/xilinx-xc7.cfg&lt;span class=&quot;kw&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-6&quot;&gt;&lt;a href=&quot;#cb6-6&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;source&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ot&quot;&gt;find&lt;/span&gt; cpld/jtagspi.cfg&lt;span class=&quot;kw&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-7&quot;&gt;&lt;a href=&quot;#cb6-7&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-8&quot;&gt;&lt;a href=&quot;#cb6-8&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;init&lt;/span&gt;
&lt;span id=&quot;cb6-9&quot;&gt;&lt;a href=&quot;#cb6-9&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-10&quot;&gt;&lt;a href=&quot;#cb6-10&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;jtagspi_init xc7.pld &lt;span class=&quot;dt&quot;&gt;$BSCAN_FILE&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-11&quot;&gt;&lt;a href=&quot;#cb6-11&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;jtagspi_program &lt;span class=&quot;dt&quot;&gt;$FPGAIMAGE&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-12&quot;&gt;&lt;a href=&quot;#cb6-12&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-13&quot;&gt;&lt;a href=&quot;#cb6-13&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;virtex2 refresh xc7.pld&lt;/span&gt;
&lt;span id=&quot;cb6-14&quot;&gt;&lt;a href=&quot;#cb6-14&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb6-15&quot;&gt;&lt;a href=&quot;#cb6-15&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;exit&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The command to flash a NeTV2 from a Raspberry Pi:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb7&quot;&gt;&lt;pre class=&quot;sourceCode bash&quot;&gt;&lt;code class=&quot;sourceCode bash&quot;&gt;&lt;span id=&quot;cb7-1&quot;&gt;&lt;a href=&quot;#cb7-1&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;/opt/openocd/src/openocd&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-2&quot;&gt;&lt;a href=&quot;#cb7-2&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ex&quot;&gt;-c&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;set BSCAN_FILE /home/k8s/netv2mvp-scripts/bscan_spi_xc7a100t.bit&amp;quot;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-3&quot;&gt;&lt;a href=&quot;#cb7-3&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ex&quot;&gt;-c&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;set FPGAIMAGE /home/k8s/pcileech_netv2_top.bin&amp;quot;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb7-4&quot;&gt;&lt;a href=&quot;#cb7-4&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;  &lt;span class=&quot;ex&quot;&gt;-f&lt;/span&gt; /home/k8s/netv2mvp-scripts/cl-spifpga-rpi4.cfg&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The output shows the Macronix SPI flash being programmed:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Info : BCM2835 GPIO JTAG/SWD bitbang driver
Info : clock speed 10000 kHz
Info : JTAG tap: xc7.tap tap/device found: 0x13631093 (mfg: 0x049 (Xilinx), part: 0x3631, ver: 0x1)
Info : [xc7.proxy] Examination succeed
Info : Found flash device &amp;#39;mac 25l6405&amp;#39; (ID 0x1720c2)
Info : sector 0 took 286 ms
Info : sector 1 took 282 ms
...&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note the device ID difference: &lt;code&gt;0x13631093&lt;/code&gt; for the 100T part versus &lt;code&gt;0x13632093&lt;/code&gt; for the 75T. The flash chip is a Macronix MX25L6405 (ID 0x1720c2) versus the Winbond W25Q64FV (ID 0x1740ef) on the Captain DMA boards.&lt;/p&gt;
&lt;h2 id=&quot;litex-builds-for-netv2&quot;&gt;LiteX Builds for NeTV2&lt;/h2&gt;
&lt;p&gt;If you want to run something other than the original gateware, LiteX has excellent support for the NeTV2. The board definition lives at https://github.com/litex-hub/litex-boards/blob/master/litex_boards/targets/kosagi_netv2.py.&lt;/p&gt;
&lt;h3 id=&quot;building-a-basic-litex-soc&quot;&gt;Building a Basic LiteX SoC&lt;/h3&gt;
&lt;p&gt;Install LiteX following the standard setup, then:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb9&quot;&gt;&lt;pre class=&quot;sourceCode bash&quot;&gt;&lt;code class=&quot;sourceCode bash&quot;&gt;&lt;span id=&quot;cb9-1&quot;&gt;&lt;a href=&quot;#cb9-1&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;&lt;span class=&quot;bu&quot;&gt;cd&lt;/span&gt; litex-boards/litex_boards/targets&lt;/span&gt;
&lt;span id=&quot;cb9-2&quot;&gt;&lt;a href=&quot;#cb9-2&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-3&quot;&gt;&lt;a href=&quot;#cb9-3&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;# Build for XC7A35T variant with Ethernet&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-4&quot;&gt;&lt;a href=&quot;#cb9-4&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;./kosagi_netv2.py&lt;/span&gt; --variant=a7-35 --with-ethernet --build&lt;/span&gt;
&lt;span id=&quot;cb9-5&quot;&gt;&lt;a href=&quot;#cb9-5&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-6&quot;&gt;&lt;a href=&quot;#cb9-6&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;# Or for the 100T variant with PCIe&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb9-7&quot;&gt;&lt;a href=&quot;#cb9-7&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;./kosagi_netv2.py&lt;/span&gt; --variant=a7-100 --with-pcie --build&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The target supports:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;DDR3 SDRAM&lt;/strong&gt;: Using the K4B2G1646F module with LiteDRAM&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ethernet&lt;/strong&gt;: RMII PHY via LiteEth&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PCIe&lt;/strong&gt;: x4 Gen2 via LitePCIe&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SD Card&lt;/strong&gt;: Both SPI mode and native SDIO&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LED Chaser&lt;/strong&gt;: For the obligatory blinky demo&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;platform-definition-highlights&quot;&gt;Platform Definition Highlights&lt;/h3&gt;
&lt;p&gt;The platform file defines the IO constraints:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb10&quot;&gt;&lt;pre class=&quot;sourceCode python&quot;&gt;&lt;code class=&quot;sourceCode python&quot;&gt;&lt;span id=&quot;cb10-1&quot;&gt;&lt;a href=&quot;#cb10-1&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;_io &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; [&lt;/span&gt;
&lt;span id=&quot;cb10-2&quot;&gt;&lt;a href=&quot;#cb10-2&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;co&quot;&gt;# 50 MHz clock input&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-3&quot;&gt;&lt;a href=&quot;#cb10-3&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;    (&lt;span class=&quot;st&quot;&gt;&amp;quot;clk50&amp;quot;&lt;/span&gt;, &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;, Pins(&lt;span class=&quot;st&quot;&gt;&amp;quot;J19&amp;quot;&lt;/span&gt;), IOStandard(&lt;span class=&quot;st&quot;&gt;&amp;quot;LVCMOS33&amp;quot;&lt;/span&gt;)),&lt;/span&gt;
&lt;span id=&quot;cb10-4&quot;&gt;&lt;a href=&quot;#cb10-4&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;    &lt;/span&gt;
&lt;span id=&quot;cb10-5&quot;&gt;&lt;a href=&quot;#cb10-5&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;co&quot;&gt;# User LEDs&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-6&quot;&gt;&lt;a href=&quot;#cb10-6&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;    (&lt;span class=&quot;st&quot;&gt;&amp;quot;user_led&amp;quot;&lt;/span&gt;, &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;, Pins(&lt;span class=&quot;st&quot;&gt;&amp;quot;M21&amp;quot;&lt;/span&gt;),  IOStandard(&lt;span class=&quot;st&quot;&gt;&amp;quot;LVCMOS33&amp;quot;&lt;/span&gt;)),&lt;/span&gt;
&lt;span id=&quot;cb10-7&quot;&gt;&lt;a href=&quot;#cb10-7&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;    (&lt;span class=&quot;st&quot;&gt;&amp;quot;user_led&amp;quot;&lt;/span&gt;, &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;, Pins(&lt;span class=&quot;st&quot;&gt;&amp;quot;N20&amp;quot;&lt;/span&gt;),  IOStandard(&lt;span class=&quot;st&quot;&gt;&amp;quot;LVCMOS33&amp;quot;&lt;/span&gt;)),&lt;/span&gt;
&lt;span id=&quot;cb10-8&quot;&gt;&lt;a href=&quot;#cb10-8&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;co&quot;&gt;# ...&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-9&quot;&gt;&lt;a href=&quot;#cb10-9&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;    &lt;/span&gt;
&lt;span id=&quot;cb10-10&quot;&gt;&lt;a href=&quot;#cb10-10&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;co&quot;&gt;# SPI Flash for bitstream storage&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb10-11&quot;&gt;&lt;a href=&quot;#cb10-11&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;    (&lt;span class=&quot;st&quot;&gt;&amp;quot;spiflash&amp;quot;&lt;/span&gt;, &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;,&lt;/span&gt;
&lt;span id=&quot;cb10-12&quot;&gt;&lt;a href=&quot;#cb10-12&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;        Subsignal(&lt;span class=&quot;st&quot;&gt;&amp;quot;cs_n&amp;quot;&lt;/span&gt;, Pins(&lt;span class=&quot;st&quot;&gt;&amp;quot;T19&amp;quot;&lt;/span&gt;)),&lt;/span&gt;
&lt;span id=&quot;cb10-13&quot;&gt;&lt;a href=&quot;#cb10-13&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;        Subsignal(&lt;span class=&quot;st&quot;&gt;&amp;quot;mosi&amp;quot;&lt;/span&gt;, Pins(&lt;span class=&quot;st&quot;&gt;&amp;quot;P22&amp;quot;&lt;/span&gt;)),&lt;/span&gt;
&lt;span id=&quot;cb10-14&quot;&gt;&lt;a href=&quot;#cb10-14&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;        Subsignal(&lt;span class=&quot;st&quot;&gt;&amp;quot;miso&amp;quot;&lt;/span&gt;, Pins(&lt;span class=&quot;st&quot;&gt;&amp;quot;R22&amp;quot;&lt;/span&gt;)),&lt;/span&gt;
&lt;span id=&quot;cb10-15&quot;&gt;&lt;a href=&quot;#cb10-15&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;        Subsignal(&lt;span class=&quot;st&quot;&gt;&amp;quot;wp&amp;quot;&lt;/span&gt;,   Pins(&lt;span class=&quot;st&quot;&gt;&amp;quot;P21&amp;quot;&lt;/span&gt;)),&lt;/span&gt;
&lt;span id=&quot;cb10-16&quot;&gt;&lt;a href=&quot;#cb10-16&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;        Subsignal(&lt;span class=&quot;st&quot;&gt;&amp;quot;hold&amp;quot;&lt;/span&gt;, Pins(&lt;span class=&quot;st&quot;&gt;&amp;quot;R21&amp;quot;&lt;/span&gt;)),&lt;/span&gt;
&lt;span id=&quot;cb10-17&quot;&gt;&lt;a href=&quot;#cb10-17&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;        IOStandard(&lt;span class=&quot;st&quot;&gt;&amp;quot;LVCMOS33&amp;quot;&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb10-18&quot;&gt;&lt;a href=&quot;#cb10-18&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;    ),&lt;/span&gt;
&lt;span id=&quot;cb10-19&quot;&gt;&lt;a href=&quot;#cb10-19&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The platform also defines the programmer configuration, which now supports both OpenOCD and OpenFPGALoader:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb11&quot;&gt;&lt;pre class=&quot;sourceCode python&quot;&gt;&lt;code class=&quot;sourceCode python&quot;&gt;&lt;span id=&quot;cb11-1&quot;&gt;&lt;a href=&quot;#cb11-1&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;&lt;span class=&quot;kw&quot;&gt;def&lt;/span&gt; create_programmer(&lt;span class=&quot;va&quot;&gt;self&lt;/span&gt;, programmer&lt;span class=&quot;op&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&amp;quot;openocd&amp;quot;&lt;/span&gt;):&lt;/span&gt;
&lt;span id=&quot;cb11-2&quot;&gt;&lt;a href=&quot;#cb11-2&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;cf&quot;&gt;if&lt;/span&gt; programmer &lt;span class=&quot;op&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;openfpgaloader&amp;quot;&lt;/span&gt;:&lt;/span&gt;
&lt;span id=&quot;cb11-3&quot;&gt;&lt;a href=&quot;#cb11-3&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;cf&quot;&gt;return&lt;/span&gt; OpenFPGALoader(cable&lt;span class=&quot;op&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&amp;quot;digilent_hs2&amp;quot;&lt;/span&gt;)&lt;/span&gt;
&lt;span id=&quot;cb11-4&quot;&gt;&lt;a href=&quot;#cb11-4&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;    &lt;span class=&quot;cf&quot;&gt;elif&lt;/span&gt; programmer &lt;span class=&quot;op&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;openocd&amp;quot;&lt;/span&gt;:&lt;/span&gt;
&lt;span id=&quot;cb11-5&quot;&gt;&lt;a href=&quot;#cb11-5&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;        bscan_spi &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;bscan_spi_xc7a100t.bit&amp;quot;&lt;/span&gt; &lt;span class=&quot;cf&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;xc7a100t&amp;quot;&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;self&lt;/span&gt;.device &lt;span class=&quot;cf&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;bscan_spi_xc7a35t.bit&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb11-6&quot;&gt;&lt;a href=&quot;#cb11-6&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;        &lt;span class=&quot;cf&quot;&gt;return&lt;/span&gt; OpenOCD(&lt;span class=&quot;st&quot;&gt;&amp;quot;openocd_netv2_rpi.cfg&amp;quot;&lt;/span&gt;, bscan_spi)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;provisioning-for-fpgas.online&quot;&gt;Provisioning for fpgas.online&lt;/h2&gt;
&lt;p&gt;The ultimate destination for these NeTV2 boards is &lt;a href=&quot;https://ps1.fpgas.online/fpgas/&quot;&gt;fpgas.online&lt;/a&gt; – a community project that provides free remote access to FPGA development boards. The service currently has around 10 FPGA boards connected, each with a webcam pointed at the LEDs so you can see your bitstream running in real-time.&lt;/p&gt;
&lt;p&gt;Each board is attached to a Raspberry Pi that handles:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;JTAG programming via the GPIO bitbang interface&lt;/li&gt;
&lt;li&gt;Webcam streaming for visual feedback&lt;/li&gt;
&lt;li&gt;Web-based terminal access for interactive development&lt;/li&gt;
&lt;li&gt;Queue management so multiple users can share the hardware&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is where the Raspberry Pi JTAG programming approach really shines – you can reflash gateware remotely without any physical access to the boards. Combined with LiteX’s rapid build cycle, it becomes practical to iterate on FPGA designs from anywhere in the world.&lt;/p&gt;
&lt;p&gt;If you want to try FPGA development without buying hardware, head over to https://ps1.fpgas.online/fpgas/ and claim a board. There’s usually one free and ready to use.&lt;/p&gt;
&lt;h2 id=&quot;why-this-matters&quot;&gt;Why This Matters&lt;/h2&gt;
&lt;p&gt;These techniques apply to any Artix-7 board with SPI flash storage:&lt;/p&gt;
&lt;ol type=&quot;1&quot;&gt;
&lt;li&gt;&lt;strong&gt;Reproducibility&lt;/strong&gt;: Scripts in version control beat clicking through GUIs&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Automation&lt;/strong&gt;: CI/CD pipelines can flash test firmware automatically&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Headless operation&lt;/strong&gt;: A Raspberry Pi in a lab can program boards remotely&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cross-platform&lt;/strong&gt;: The same OpenOCD configs work on Linux, macOS, and Windows&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tool preservation&lt;/strong&gt;: When vendors disappear, open source tooling remains&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Remote labs&lt;/strong&gt;: Services like fpgas.online can offer FPGA access to anyone&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The BSCAN SPI approach is particularly elegant – it uses a small “helper” bitstream that turns the FPGA’s JTAG interface into a SPI master, allowing you to program the flash chip that normally stores the FPGA configuration. Once programmed, a power cycle or refresh command loads the new bitstream.&lt;/p&gt;
&lt;h2 id=&quot;resources&quot;&gt;Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;fpgas.online Remote Lab&lt;/strong&gt;: https://ps1.fpgas.online/fpgas/&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Captain DMA Scripts&lt;/strong&gt;: https://github.com/whatnick/fpga-dma-scripts&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;NeTV2 RPi4 Scripts&lt;/strong&gt;: https://github.com/AlphamaxMedia/netv2mvp-scripts/pull/1&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LiteX NeTV2 Target&lt;/strong&gt;: https://github.com/litex-hub/litex-boards/blob/master/litex_boards/targets/kosagi_netv2.py&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;BSCAN SPI Bitstreams&lt;/strong&gt;: https://github.com/quartiq/bscan_spi_bitstreams&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PCILeech FPGA Project&lt;/strong&gt;: https://github.com/ufrisk/pcileech-fpga&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Video Walkthrough&lt;/strong&gt;: https://youtu.be/CNQnafoOTCM&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The next time you inherit a box of mystery FPGA boards, you’ll know what to do. OpenOCD and a Raspberry Pi can breathe new life into almost any Xilinx 7-series board – no proprietary tools, no Windows VM, no Chinese language skills required.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;https://lh3.googleusercontent.com/pw/AP1GczPZTGeXPh0Ry_lgyPZ0yhLZl4BcrjvF-NaD50y8osBgnp2dtR0uZrm_r538wEhMsWBX8ep3OPvhO69x2tmD83rr8uks9dgh_zTgIKf87Ku_lVv-3gd2aPdeZgokvfRA3U1Rh7DyXFdMkq2EtfZN6O_YGw=w623-h827-s-no-gm?authuser=0&quot; alt=&quot;&quot; /&gt;&lt;figcaption&gt;SQRL Acorn boards&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Feel free to ping me with other interesting DMA or video processing boards you’ve encountered. There’s always more gateware to explore.&lt;/p&gt;
</content><link rel='replies' type='application/atom+xml' href='http://whatnicklife.blogspot.com/feeds/3902826425366259988/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3220006345447041404/3902826425366259988' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3220006345447041404/posts/default/3902826425366259988'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3220006345447041404/posts/default/3902826425366259988'/><link rel='alternate' type='text/html' href='http://whatnicklife.blogspot.com/2026/01/loading-fpga-bitstreams-with-openocd.html' title='Loading FPGA Bitstreams with OpenOCD and Raspberry Pi - From Captain DMA to NeTV2'/><author><name>Tisham Dhar</name><uri>http://www.blogger.com/profile/15154154153085427197</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://lh3.googleusercontent.com/pw/AP1GczOoOvoR6l13ubi_mrwFfM_4AexAW6DQ67SRTvG84NPs9llZma4NHTbgRZddiWEIbVjv7ujPzQsXrDTlO-DuvTyCz--4eKXX42wxqpAh3HmPKIcq81SGyrK7f5IVY1fBRHh-byXhQxAUtYIBd3pMgwRUQQ=s72-w623-h827-s-c-no-gm?authuser=0" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3220006345447041404.post-7017091486894311247</id><published>2025-12-24T16:00:00.000-08:00</published><updated>2025-12-28T19:12:26.399-08:00</updated><title type='text'>Seven Years to Kubernetes: A Turing Pi 1 Christmas Miracle</title><content type='html'>&lt;figure&gt;&lt;img alt=&quot;Turing Pi 1 Cluster Board&quot; src=&quot;https://lh3.googleusercontent.com/pw/AP1GczNgAdriNJGw8gK7NeudfKWQ0xZaDhEiSRbRf1I5rqddafhjWINTGRnSUMnaiMZlq3MlNdjY6BZa5hEN_TFpA9E4t1g67WWRx4zzQO4InPSb0YEISAeva-mmStspIGT0XuA3Q2flBDedhgUKiM0waiLz4A=w979-h1305-s-no-gm?authuser=0&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Turing Pi 1 Cluster Board&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;the-seven-year-itch-for-hardware&quot;&gt;The Seven Year Itch (For
Hardware)&lt;/h2&gt;
&lt;p&gt;Often I buy more hardware than I need. &lt;del&gt;Actually, strike
that&lt;/del&gt; – I &lt;em&gt;always&lt;/em&gt; buy more hardware than I need. It’s a
disease, really. This particular affliction manifested in 2018 when I
pre-ordered a &lt;a href=&quot;https://turingpi.com/&quot;&gt;Turing Pi 1&lt;/a&gt; because I
had convinced myself that building a Raspberry Pi cluster would be the
&lt;em&gt;perfect&lt;/em&gt; way to learn Kubernetes.&lt;/p&gt;
&lt;p&gt;It was not the perfect way.&lt;/p&gt;
&lt;p&gt;Little did I realize that it would take me &lt;strong&gt;seven
years&lt;/strong&gt; to gather all seven &lt;a href=&quot;https://www.mouser.com/new/raspberry-pi/raspberry-pi-cm3plus-compute-modules/&quot;&gt;Raspberry
Pi Compute Module 3+&lt;/a&gt; boards and finally bootstrap a &lt;a href=&quot;https://k3s.io/&quot;&gt;k3s&lt;/a&gt; cluster. In that time:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Kubernetes went through approximately 47 major versions&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The Raspberry Pi 4 and 5 came out (and experienced their own chip
shortages)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I discovered my Turing Pi board had a faulty ethernet
switch&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I aged visibly, just look at my github profile and videos from
recent conference presentations.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;!--Image: Close-up of the faulty ethernet switch IC--&gt;
&lt;figure&gt;
&lt;img alt=&quot;The Ethernet Switch of Broken Dreams&quot; src=&quot;https://lh3.googleusercontent.com/pw/AP1GczPkgl5Y3sIwqYwnvloHPWnmbpOhT1GZsTpGlOvbYbDyw1vBK_Tzt3W00DC2TwcP76WwPqIusmtvnNh3CepfQdDCOSNaCmJ3dFqLQ_s5nv4CI5BSMtMJgnsopHPj27SBggWoAXJZuYw2VLsZ8jzTRIkL8g=w1733-h1305-s-no-gm?authuser=0&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;The Ethernet Switch of Broken
Dreams&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;the-recipe-for-homelab-kubernetes-suffering&quot;&gt;The Recipe for
Homelab Kubernetes Suffering&lt;/h2&gt;
&lt;p&gt;In this write-up, I’ll outline what it &lt;em&gt;actually&lt;/em&gt; takes to set
up a Raspberry Pi 3+ cluster in 2025. Consider this a cautionary tale
wrapped in a tutorial. I’ll probably resell this now-functioning cluster
to another masochist – er, enthusiast – and use the recouped capital to
buy something newer that will sit on my shelf for another seven
years.&lt;/p&gt;
&lt;h3 id=&quot;step-1-acquire-the-base-board&quot;&gt;Step 1: Acquire the Base
Board&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&quot;https://turingpi.com/&quot;&gt;Turing Pi 1&lt;/a&gt; was a great
option back in the day. It’s a mini-ITX form factor board that accepts
up to 7 Raspberry Pi Compute Modules in SODIMM slots. The on-board
gigabit ethernet switch was supposed to be the killer feature – no
external networking required!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pro tip&lt;/strong&gt;: Make sure the on-board switch actually
works. Test it &lt;em&gt;before&lt;/em&gt; you commit to this path. Mine didn’t,
which I discovered approximately 6 years too late.&lt;/p&gt;
&lt;!--Video: Quick overview of the Turing Pi 1 board layout--&gt;
&lt;h3 id=&quot;step-2-collect-your-compute-modules-like-pokemon-but-expensive&quot;&gt;Step
2: Collect Your Compute Modules (Like Pokemon, But Expensive)&lt;/h3&gt;
&lt;p&gt;You’ll need &lt;a href=&quot;https://www.mouser.com/c/embedded-solutions/computing/system-on-modules-som/?m=Raspberry%20Pi&amp;amp;series=Raspberry%20Pi%20CM3&quot;&gt;Raspberry
Pi Compute Module 3+&lt;/a&gt; boards. The Turing Pi 1 can handle up to 7 of
them. I sourced mine from &lt;a href=&quot;https://www.mouser.com/&quot;&gt;Mouser
Electronics&lt;/a&gt;, though availability has been… variable… over the
years.&lt;/p&gt;
&lt;p&gt;I really wish there were more alternatives in the SODIMM compute
module format. If you’re in the business of making one with a newer
processor and more RAM, let’s talk. Seriously. My DMs are open.&lt;/p&gt;
&lt;!--Image: All 7 compute modules laid out before installation--&gt;
&lt;figure&gt;
&lt;img alt=&quot;Seven Compute Modules Ready for Battle&quot; src=&quot;https://lh3.googleusercontent.com/pw/AP1GczPGChQz4ifz4urKNmdyqWAXq6iAyC_b9FiUxXpJqDfu9BKk-TPETVwa4LfGsJNvNB7v2baeTExC1c6-p2aF8FDo14__G2-rx_ToMTemDMSR26cwQeHBlj-SEQr_F6Mlj0ZWs30cazW8uNoLaWPX-HClzQ=w1733-h1305-s-no-gm?authuser=0&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Seven Compute Modules Ready for
Battle&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3 id=&quot;step-3-flash-the-os-the-easy-part-they-said&quot;&gt;Step 3: Flash the
OS (The Easy Part, They Said)&lt;/h3&gt;
&lt;p&gt;The Compute Modules have onboard eMMC storage, which is the preferred
boot device. Trying to use SD cards will lead to disappointment,
inconsistent boots, and existential questioning of your life
choices.&lt;/p&gt;
&lt;p&gt;Here’s the gear you’ll need:&lt;/p&gt;
&lt;ol type=&quot;1&quot;&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A Compute Module IO Board&lt;/strong&gt; - Something like the
&lt;a href=&quot;https://www.waveshare.com/cm3-io-base-b.htm&quot;&gt;Waveshare CM3/CM3+
IO Board&lt;/a&gt; or the &lt;a href=&quot;https://www.raspberrypi.com/products/compute-module-io-board-v3/&quot;&gt;official
Raspberry Pi IO Board&lt;/a&gt; to put the module in USB mass storage
mode&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/raspberrypi/usbboot&quot;&gt;rpiboot/usbboot&lt;/a&gt;&lt;/strong&gt;
- The tool that makes the eMMC appear as a USB drive&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://www.raspberrypi.com/software/&quot;&gt;Raspberry
Pi Imager&lt;/a&gt;&lt;/strong&gt; - The official tool for flashing OS
images&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Critical step&lt;/strong&gt;: Bake in your SSH public key during
the imaging process. This will save you from having to find 7 spare HDMI
cables and keyboards. The Pi Imager has a settings gear icon that lets
you configure hostname, SSH keys, and WiFi – use it.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb1&quot;&gt;&lt;pre class=&quot;sourceCode bash&quot;&gt;&lt;code class=&quot;sourceCode bash&quot;&gt;&lt;span id=&quot;cb1-1&quot;&gt;&lt;a aria-hidden=&quot;true&quot; href=&quot;#cb1-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-2&quot;&gt;&lt;a aria-hidden=&quot;true&quot; href=&quot;#cb1-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;# Generate an SSH key if you don&#39;t have one&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-3&quot;&gt;&lt;a aria-hidden=&quot;true&quot; href=&quot;#cb1-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb1-4&quot;&gt;&lt;a aria-hidden=&quot;true&quot; href=&quot;#cb1-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;ssh-keygen&lt;/span&gt; &lt;span class=&quot;at&quot;&gt;-t&lt;/span&gt; ed25519 &lt;span class=&quot;at&quot;&gt;-C&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&quot;kubernetes-cluster&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;!--Image: Compute module in the IO board, ready for flashing--&gt;
&lt;figure&gt;
&lt;img alt=&quot;Flashing Setup with IO Board&quot; src=&quot;https://lh3.googleusercontent.com/pw/AP1GczMGgzgkCJelT_sQGVEn5NoHlZ4Ja7A7ay4QDjt2Labml4e8884f-o2VeLAUwmpUG-fk8n2zRYVmwGMKMQdEYR6H_ItabmI4X4O866Avzv7jC6RY0jJsJYou_7Hn0ifUNpqVIlzwU86PNmB4kEIpsGQw1w=w960-h744-s-no-gm?authuser=0&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Flashing Setup with IO Board&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3 id=&quot;step-4-network-configuration-here-be-dragons&quot;&gt;Step 4: Network
Configuration (Here Be Dragons)&lt;/h3&gt;
&lt;p&gt;Plug in all the modules and fire up the on-board Turing Pi ethernet.
If you’re lucky, the on-board network works and you can access all the
nodes. Marvel at how easy this was.&lt;/p&gt;
&lt;p&gt;If you’re me, you’ll discover the switch is dead and enter the seven
stages of homelab grief:&lt;/p&gt;
&lt;ol type=&quot;1&quot;&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Denial&lt;/strong&gt;: “It’s probably just a loose
connection”&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Anger&lt;/strong&gt;: Unprintable + emails to Turing Pi support
and learning that the board is End-of-Life and unsupported.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Bargaining&lt;/strong&gt;: “Maybe I only need 4 nodes
anyway”&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Depression&lt;/strong&gt;: &lt;em&gt;stares at pile of unused compute
modules&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Acceptance&lt;/strong&gt;: “I guess I’m buying USB ethernet
adapters”&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;The Workaround&lt;/strong&gt;: Get a bunch of USB-to-Ethernet
adapters like the &lt;a href=&quot;https://www.amazon.com/TP-Link-Foldable-Gigabit-Ethernet-Compatible/dp/B00YUU3KC6&quot;&gt;TP-Link
UE300&lt;/a&gt; and wire them into an external switch.&lt;/p&gt;
&lt;p&gt;Unfortunately, only 4 of the compute modules have their USB ports
exposed on the Turing Pi 1. For the other 3, you’ll need to do some
creative soldering to expose the USB D+/D- and power lines. That’s just
12 more flying wires on the board. What could go wrong?&lt;/p&gt;
&lt;!--Image: The magnificent spaghetti of USB ethernet adapters--&gt;
&lt;figure&gt;
&lt;iframe allowfullscreen=&quot;&quot; frameborder=&quot;0&quot; src=&quot;https://www.youtube.com/embed/piBWttzrFEA&quot;&gt;&lt;/iframe&gt;
&lt;figcaption&gt;USB Ethernet Adapters and Working cluster&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3 id=&quot;step-5-the-case-mod-optional-but-satisfying&quot;&gt;Step 5: The Case
Mod (Optional But Satisfying)&lt;/h3&gt;
&lt;p&gt;I got a nice acrylic case to put it all in. It has a fan connection
on top for cooling, which you’ll need because 7 Pi’s generate surprising
heat.&lt;/p&gt;
&lt;p&gt;There were no extra slots for the 3 additional USB connections I
needed. But I have a Dremel, two weeks of Christmas holidays, and
absolutely no fear of voiding warranties.&lt;/p&gt;
&lt;!--Image: The acrylic case with custom USB cutouts--&gt;
&lt;figure&gt;
&lt;img alt=&quot;Custom Dremel Work on Acrylic Case&quot; src=&quot;https://lh3.googleusercontent.com/pw/AP1GczO23WP7xUanX4BUTK0ksSsKq1aYG1xfjEElwC6AbSdDH3KWPek9k7PLhclnleIKFxz9nE_OVC3hOcZ1WE4Q0K6SFJDmgdD8Q4HRc66JfgqGD6z1u08Uf_RjGYZQzrqENKYpgvUJB0fC_ahoq_tqAGXcLA=w1024-h796-s-no-gm?authuser=0&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Custom Dremel Work on Acrylic
Case&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3 id=&quot;step-6-actually-installing-kubernetes-the-easy-part-for-real-this-time&quot;&gt;Step
6: Actually Installing Kubernetes (The Easy Part, For Real This
Time)&lt;/h3&gt;
&lt;p&gt;With SSH keys baked in, installing &lt;a href=&quot;https://docs.k3s.io/&quot;&gt;k3s&lt;/a&gt; is delightfully straightforward
using &lt;a href=&quot;https://github.com/alexellis/k3sup&quot;&gt;k3sup&lt;/a&gt; (pronounced
“ketchup”, because of course it is).&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb2&quot;&gt;&lt;pre class=&quot;sourceCode bash&quot;&gt;&lt;code class=&quot;sourceCode bash&quot;&gt;&lt;span id=&quot;cb2-1&quot;&gt;&lt;a aria-hidden=&quot;true&quot; href=&quot;#cb2-1&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-2&quot;&gt;&lt;a aria-hidden=&quot;true&quot; href=&quot;#cb2-2&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;# Install k3sup&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-3&quot;&gt;&lt;a aria-hidden=&quot;true&quot; href=&quot;#cb2-3&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-4&quot;&gt;&lt;a aria-hidden=&quot;true&quot; href=&quot;#cb2-4&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;at&quot;&gt;-sLS&lt;/span&gt; https://get.k3sup.dev &lt;span class=&quot;kw&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;sh&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-5&quot;&gt;&lt;a aria-hidden=&quot;true&quot; href=&quot;#cb2-5&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-6&quot;&gt;&lt;a aria-hidden=&quot;true&quot; href=&quot;#cb2-6&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;fu&quot;&gt;sudo&lt;/span&gt; install k3sup /usr/local/bin/&lt;/span&gt;
&lt;span id=&quot;cb2-7&quot;&gt;&lt;a aria-hidden=&quot;true&quot; href=&quot;#cb2-7&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-8&quot;&gt;&lt;a aria-hidden=&quot;true&quot; href=&quot;#cb2-8&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-9&quot;&gt;&lt;a aria-hidden=&quot;true&quot; href=&quot;#cb2-9&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-10&quot;&gt;&lt;a aria-hidden=&quot;true&quot; href=&quot;#cb2-10&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;# Bootstrap the first node as the server&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-11&quot;&gt;&lt;a aria-hidden=&quot;true&quot; href=&quot;#cb2-11&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-12&quot;&gt;&lt;a aria-hidden=&quot;true&quot; href=&quot;#cb2-12&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;k3sup&lt;/span&gt; install &lt;span class=&quot;at&quot;&gt;--ip&lt;/span&gt; 192.168.1.101 &lt;span class=&quot;at&quot;&gt;--user&lt;/span&gt; k8s&lt;/span&gt;
&lt;span id=&quot;cb2-13&quot;&gt;&lt;a aria-hidden=&quot;true&quot; href=&quot;#cb2-13&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-14&quot;&gt;&lt;a aria-hidden=&quot;true&quot; href=&quot;#cb2-14&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-15&quot;&gt;&lt;a aria-hidden=&quot;true&quot; href=&quot;#cb2-15&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-16&quot;&gt;&lt;a aria-hidden=&quot;true&quot; href=&quot;#cb2-16&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;# Join additional nodes as agents&lt;/span&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-17&quot;&gt;&lt;a aria-hidden=&quot;true&quot; href=&quot;#cb2-17&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-18&quot;&gt;&lt;a aria-hidden=&quot;true&quot; href=&quot;#cb2-18&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;k3sup&lt;/span&gt; join &lt;span class=&quot;at&quot;&gt;--ip&lt;/span&gt; 192.168.1.102 &lt;span class=&quot;at&quot;&gt;--server-ip&lt;/span&gt; 192.168.1.101 &lt;span class=&quot;at&quot;&gt;--user&lt;/span&gt; k8s&lt;/span&gt;
&lt;span id=&quot;cb2-19&quot;&gt;&lt;a aria-hidden=&quot;true&quot; href=&quot;#cb2-19&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-20&quot;&gt;&lt;a aria-hidden=&quot;true&quot; href=&quot;#cb2-20&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;ex&quot;&gt;k3sup&lt;/span&gt; join &lt;span class=&quot;at&quot;&gt;--ip&lt;/span&gt; 192.168.1.103 &lt;span class=&quot;at&quot;&gt;--server-ip&lt;/span&gt; 192.168.1.101 &lt;span class=&quot;at&quot;&gt;--user&lt;/span&gt; k8s&lt;/span&gt;
&lt;span id=&quot;cb2-21&quot;&gt;&lt;a aria-hidden=&quot;true&quot; href=&quot;#cb2-21&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;/span&gt;
&lt;span id=&quot;cb2-22&quot;&gt;&lt;a aria-hidden=&quot;true&quot; href=&quot;#cb2-22&quot; tabindex=&quot;-1&quot;&gt;&lt;/a&gt;&lt;span class=&quot;co&quot;&gt;# ... repeat for remaining nodes&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/alexellis/k3sup&quot;&gt;k3sup&lt;/a&gt; SSHes into
each machine, downloads the necessary bits, and bootstraps a
low-resource-friendly cluster with &lt;a href=&quot;https://etcd.io/&quot;&gt;etcd&lt;/a&gt;
(or SQLite) as the datastore. It’s genuinely magical compared to
kubeadm.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Reality check&lt;/strong&gt;: After the k3s install, the Pi 3
doesn’t have much headroom left for actually running applications. We’re
talking about 1GB of RAM shared between the OS, kubelet, and your
workloads. It’s a great testbed for learning the k3s API and running ARM
binaries natively, but don’t expect to run your company’s microservices
on it.&lt;/p&gt;
&lt;!--Video: k3sup installation process and kubectl get nodes--&gt;
&lt;figure&gt;
&lt;iframe allowfullscreen=&quot;&quot; frameborder=&quot;0&quot; src=&quot;https://www.youtube.com/embed/oq7Lz8Mx1dI&quot;&gt;&lt;/iframe&gt;
&lt;figcaption&gt;K3Sup based cluster setup&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;the-final-result&quot;&gt;The Final Result&lt;/h2&gt;
&lt;p&gt;After seven years of procrastination, hardware hunting, debugging
dead ethernet switches, creative soldering, and Dremel work, I finally
have a working 7-node Kubernetes cluster.&lt;/p&gt;
&lt;p&gt;It also serves as a rather festive Christmas decoration with the
green PCB and red blinking LEDs. Very on-brand for the holidays.&lt;/p&gt;
&lt;h2 id=&quot;whats-next&quot;&gt;What’s Next?&lt;/h2&gt;
&lt;p&gt;Hopefully I’ve been a good boy this year and Santa will bring me some
newer clustering hardware to play with. The &lt;a href=&quot;https://turingpi.com/product/turing-pi-2-5/&quot;&gt;Turing Pi 2.5&lt;/a&gt;
looks tempting with its support for CM4, Jetson, and the &lt;a href=&quot;https://turingpi.com/product/turing-rk1/&quot;&gt;Turing RK1&lt;/a&gt;
modules.&lt;/p&gt;
&lt;p&gt;But knowing me, I’ll buy it in 2025 and finally get it working by
2032.&lt;/p&gt;
&lt;h2 id=&quot;hardware-shopping-list&quot;&gt;Hardware Shopping List&lt;/h2&gt;
&lt;p&gt;For anyone brave enough to follow this path, here’s what you’ll
need:&lt;/p&gt;
&lt;table&gt;
&lt;colgroup&gt;
&lt;col style=&quot;width: 31%;&quot;&gt;&lt;/col&gt;
&lt;col style=&quot;width: 31%;&quot;&gt;&lt;/col&gt;
&lt;col style=&quot;width: 36%;&quot;&gt;&lt;/col&gt;
&lt;/colgroup&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Item&lt;/th&gt;
&lt;th&gt;Link&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Turing Pi 1 Board&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://turingpi.com/&quot;&gt;Turing Pi&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Check if ethernet works!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Raspberry Pi CM3+ (x7)&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://www.mouser.com/new/raspberry-pi/raspberry-pi-cm3plus-compute-modules/&quot;&gt;Mouser&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;8GB/16GB/32GB eMMC options&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CM IO Board for flashing&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://www.waveshare.com/&quot;&gt;Waveshare&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Or official RPi IO Board&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;USB Ethernet Adapters&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://www.amazon.com/&quot;&gt;Amazon&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Just in case&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ethernet Switch&lt;/td&gt;
&lt;td&gt;Your choice&lt;/td&gt;
&lt;td&gt;8+ ports recommended&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Acrylic Case&lt;/td&gt;
&lt;td&gt;Various&lt;/td&gt;
&lt;td&gt;With fan for cooling&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;software-tools&quot;&gt;Software &amp;amp; Tools&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://www.raspberrypi.com/software/&quot;&gt;Raspberry Pi
Imager&lt;/a&gt; - OS flashing tool&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/raspberrypi/usbboot&quot;&gt;rpiboot/usbboot&lt;/a&gt; - For
eMMC flashing&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://k3s.io/&quot;&gt;k3s&lt;/a&gt; - Lightweight Kubernetes
distribution&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/alexellis/k3sup&quot;&gt;k3sup&lt;/a&gt; - k3s
installer via SSH&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://etcd.io/&quot;&gt;etcd&lt;/a&gt; - Distributed key-value
store&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Feel free to ping me with your own homelab Kubernetes horror stories.
Misery loves company.&lt;/p&gt;
</content><link rel='replies' type='application/atom+xml' href='http://whatnicklife.blogspot.com/feeds/7017091486894311247/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3220006345447041404/7017091486894311247' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3220006345447041404/posts/default/7017091486894311247'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3220006345447041404/posts/default/7017091486894311247'/><link rel='alternate' type='text/html' href='http://whatnicklife.blogspot.com/2025/12/seven-years-to-kubernetes-turing-pi-1.html' title='Seven Years to Kubernetes: A Turing Pi 1 Christmas Miracle'/><author><name>Tisham Dhar</name><uri>http://www.blogger.com/profile/15154154153085427197</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://lh3.googleusercontent.com/pw/AP1GczNgAdriNJGw8gK7NeudfKWQ0xZaDhEiSRbRf1I5rqddafhjWINTGRnSUMnaiMZlq3MlNdjY6BZa5hEN_TFpA9E4t1g67WWRx4zzQO4InPSb0YEISAeva-mmStspIGT0XuA3Q2flBDedhgUKiM0waiLz4A=s72-w979-h1305-s-c-no-gm?authuser=0" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3220006345447041404.post-5561528550520861108</id><published>2025-12-12T00:53:47.054-08:00</published><updated>2025-12-12T00:53:47.054-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="austender"/><category scheme="http://www.blogger.com/atom/ns#" term="ducklake"/><category scheme="http://www.blogger.com/atom/ns#" term="go"/><category scheme="http://www.blogger.com/atom/ns#" term="ocds"/><category scheme="http://www.blogger.com/atom/ns#" term="scraping"/><title type='text'>Refactoring the Austender Scraper: From Colly to OCDS</title><content type='html'>&lt;p&gt;The AusTender analyser started life as a straight HTML scraper built
with &lt;a href=&quot;https://github.com/gocolly/colly&quot;&gt;Colly&lt;/a&gt;, walking the
procurement portal page by page. It worked, but it was always one
redesign away from a slow death: layout shifts, odd pagination edges,
and the constant need to throttle hard so I could sleep at night.&lt;/p&gt;
&lt;p&gt;Then the Australian Government exposed an &lt;a
href=&quot;https://standard.open-contracting.org/&quot;&gt;Open Contracting Data
Standard (OCDS)&lt;/a&gt; API. That changed the whole game. Instead of
scraping tables and div soup, I can treat the portal like a versioned
data feed.&lt;/p&gt;
&lt;p&gt;Part of why I care: I am kind of fascinated by government spending as
a system. Budgets read like a mixture of engineering constraints and
political storytelling, and I keep wanting to trace the thread from
“budget line item” to “actual contract award” without hand-waving. The
Treasurer’s Final Budget Outcome release (2022-23, “first surplus in 15
years”) is exactly the sort of headline that makes me want to drill down
into the mechanics: &lt;a
href=&quot;https://ministers.treasury.gov.au/ministers/jim-chalmers-2022/media-releases/final-budget-outcome-shows-first-surplus-15-years&quot;&gt;Final
Budget Outcome shows first surplus in 15 years&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So the redesign in &lt;a
href=&quot;https://github.com/whatnick/austender_analyser&quot;&gt;&lt;code&gt;austender_analyser&lt;/code&gt;&lt;/a&gt;
does three things differently:&lt;/p&gt;
&lt;ol type=&quot;1&quot;&gt;
&lt;li&gt;&lt;strong&gt;Fetch via OCDS, not HTML&lt;/strong&gt;: Reduce breakage by
consuming the API’s canonical JSON, not scraped pages.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Persist to Ducklake&lt;/strong&gt;: Store releases, parties, and
contracts in &lt;a href=&quot;https://github.com/duckdb/ducklake&quot;&gt;Ducklake&lt;/a&gt;
so you can query locally without rerunning the whole pipeline. This does
not quite work yet; I am treating it as a learning exercise with
Ducklake. It is much easier to learn on a real problem than on toy demo
datasets.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Treat caching as optional&lt;/strong&gt;: Counterintuitively, the
local cache is sometimes slower than pulling fresh data. Ducklake’s
startup and query overhead can outweigh a simple, parallelized upstream
call. The new design keeps the cache but makes it opt-in and
measurable.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If you prefer Python, the upstream API team ships a reference
walkthrough in the &lt;a
href=&quot;https://github.com/austender/austender-ocds-api/blob/master/examples/python/README.md&quot;&gt;austender-ocds-api
repo&lt;/a&gt; (see also the &lt;a
href=&quot;https://app.swaggerhub.com/apis/austender/ocds-api/1.1#/&quot;&gt;SwaggerHub
docs&lt;/a&gt; and an example endpoint like &lt;a
href=&quot;https://api.tenders.gov.au/ocds/findById/CN1117592&quot;&gt;&lt;code&gt;findById&lt;/code&gt;&lt;/a&gt;).&lt;/p&gt;
&lt;figure&gt;
&lt;img
src=&quot;https://raw.githubusercontent.com/whatnick/austender_analyser/main/docs/KPMG_result_2023_01_22.png&quot;
alt=&quot;Early KPMG scrape results (2023)&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Early KPMG scrape results
(2023)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;why-move-off-colly&quot;&gt;Why move off Colly?&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Scraping HTML is like doing accounting by screenshot. OCDS is the
ledger export.&lt;/li&gt;
&lt;li&gt;Less breakage: OCDS is documented and versioned; DOM scraping is
brittle.&lt;/li&gt;
&lt;li&gt;Faster iteration: You model on structured data immediately, not
after a fragile extraction layer.&lt;/li&gt;
&lt;li&gt;Clear rate behavior: You can respect API limits without guessing at
dynamic page loads.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;why-keep-ducklake-in-the-loop&quot;&gt;Why keep Ducklake in the
loop?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/duckdb/ducklake&quot;&gt;Ducklake&lt;/a&gt; is the
reproducibility knob. It lets me freeze a snapshot, replay transforms,
and run offline queries when I am iterating on analysis (or when the
upstream is slow, or when I just do not want to be a bad citizen).&lt;/p&gt;
&lt;p&gt;But caches are not free. Ducklake has startup and query overhead, and
that can be slower than simply pulling fresh JSON in parallel. So the
pipeline treats Ducklake like a tool, not a religion: measure the
latency, pick the faster path, keep an escape hatch when you need
repeatability.&lt;/p&gt;
&lt;figure&gt;
&lt;img
src=&quot;https://raw.githubusercontent.com/whatnick/austender_analyser/main/docs/reindex_disk_usage.png&quot;
alt=&quot;Reindex disk usage&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Reindex disk usage&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;current-flow&quot;&gt;Current flow&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Pull OCDS releases in batches, keyed by release date and procurement
identifiers.&lt;/li&gt;
&lt;li&gt;Normalize the JSON into &lt;a
href=&quot;https://github.com/duckdb/ducklake&quot;&gt;Ducklake&lt;/a&gt; tables (releases,
awards, suppliers, items).&lt;/li&gt;
&lt;li&gt;Emit lightweight summaries for quick diffing between runs.&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;
&lt;img
src=&quot;https://raw.githubusercontent.com/whatnick/austender_analyser/main/docs/KPMG_contracts_flood.png&quot;
alt=&quot;KPMG contracts flood view&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;KPMG contracts flood view&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;lessons-learned&quot;&gt;Lessons learned&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;A stable API beats heroic HTML scraping almost every time. Even in
times of AI and (firecrawl)[https://www.firecrawl.dev/].&lt;/li&gt;
&lt;li&gt;Caches are not free; measure them. Sometimes stressing the upstream
lightly is faster and still acceptable within published rate
limits.&lt;/li&gt;
&lt;li&gt;Keep exit hatches: allow forcing cache use, bypassing it, and
snapshotting runs for reproducibility.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Next steps: Going deeper : tighten validation against the OCDS
schema, add minimal observability (latency histograms for API vs cache),
and ship a “fast path” mode that only hydrates the fields needed for
high-level spend dashboards. Going broader : find sites and build API
and Web aggregators for Australian state tender sites (e.g. &lt;a
href=&quot;https://www.tenders.vic.gov.au/contract/search?keywords=datacom&amp;amp;title=&amp;amp;code=&amp;amp;buyerId=&amp;amp;supplierName=&amp;amp;minCost=&amp;amp;expiryDateFrom=&amp;amp;expiryDateTo=&amp;amp;startDateFrom=&amp;amp;startDateTo=&amp;amp;contractStatus=&amp;amp;awardedDateFrom=&amp;amp;page=1&amp;amp;preset=&amp;amp;browse=false&amp;amp;desc=true&amp;amp;orderBy=startDate&quot;&gt;VicTender&lt;/a&gt;
and international ones.&lt;/p&gt;
</content><link rel='replies' type='application/atom+xml' href='http://whatnicklife.blogspot.com/feeds/5561528550520861108/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3220006345447041404/5561528550520861108' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3220006345447041404/posts/default/5561528550520861108'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3220006345447041404/posts/default/5561528550520861108'/><link rel='alternate' type='text/html' href='http://whatnicklife.blogspot.com/2025/12/refactoring-austender-scraper-from.html' title='Refactoring the Austender Scraper: From Colly to OCDS'/><author><name>Tisham Dhar</name><uri>http://www.blogger.com/profile/15154154153085427197</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3220006345447041404.post-5021821387650199920</id><published>2025-12-06T03:36:26.069-08:00</published><updated>2025-12-06T03:36:26.069-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="economics"/><category scheme="http://www.blogger.com/atom/ns#" term="energy"/><category scheme="http://www.blogger.com/atom/ns#" term="limits"/><category scheme="http://www.blogger.com/atom/ns#" term="solar"/><title type='text'>Solar Ceilings and Compounding Dreams</title><content type='html'>&lt;p&gt;It is fashionable to wave away physical constraints with vague
references to solar abundance and human ingenuity. Yet every balance
sheet eventually meets a balance of energy. Solar photons may shower
Earth with roughly 170,000 terawatts, but financial markets expect
growth that compounds on top of itself forever. The math linking those
stories rarely appears in the same paragraph—so let’s put them
together.&lt;/p&gt;
&lt;h2 id=&quot;setting-the-stage&quot;&gt;Setting the Stage&lt;/h2&gt;
&lt;p&gt;I keep coming back to Tom Murphy’s dialogue in &lt;a
href=&quot;https://dothemath.ucsd.edu/2012/04/economist-meets-physicist/&quot;&gt;&lt;em&gt;Exponential
Economist Meets Finite Physicist&lt;/em&gt;&lt;/a&gt;. In Act One, Murphy plots U.S.
energy use from 1650 onward and it traces a remarkably straight
exponential line at ~3% per year. Economists in the conversation shrug;
after all, 2–3% feels modest. But compounding at that pace means energy
demand multiplies by ten every century. Our economic models implicitly
assume something even more optimistic : &lt;strong&gt;8–10% returns&lt;/strong&gt;
in equity markets, pension targets, and venture decks; without asking
what energy supply function supports that.&lt;/p&gt;
&lt;h2 id=&quot;thermodynamic-guardrails&quot;&gt;Thermodynamic Guardrails&lt;/h2&gt;
&lt;p&gt;Murphy distills the second law of thermodynamics into plain
language:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“At a 2.3% growth rate (conveniently chosen to represent a 10×
increase every century), we would reach boiling temperature in about 400
years… Even if we don’t have a name for the energy source yet, as long
as it obeys thermodynamics, we cook ourselves with perpetual energy
increase.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That thought experiment matters less for the literal 400-year timer
and more because it shows energy growth must decelerate to avoid turning
Earth into a heat engine. Solar panels, fusion, space mirrors … pick
your technology. The waste heat still has to radiate away. We cannot
spreadsheet, app and AI our way around Stefan–Boltzmann and Black Body
radiation.&lt;/p&gt;
&lt;h2 id=&quot;solar-arithmetic-vs-demand-curves&quot;&gt;Solar Arithmetic vs Demand
Curves&lt;/h2&gt;
&lt;p&gt;Let’s grant the optimists a heroic build-out: cover 5% of Earth’s
land area with 20%-efficient photovoltaic arrays, assume a generous 200
W/m² average output, and we net roughly 20 TW—about the entire human
primary energy demand today. That is fantastic news for decarbonization,
but it is not a blank check for compounding GDP. If demand keeps growing
at 3%, we would need 20 TW × (1.03)ⁿ in perpetuity. Within 250 years
we’d be trying to harvest thousands of terawatts—orders of magnitude
more land, materials, storage, and transmission than our initial miracle
project. Solar abundance is real; solar infinity is fiction.&lt;/p&gt;
&lt;h2 id=&quot;finance-is-an-energy-iou&quot;&gt;Finance Is an Energy IOU&lt;/h2&gt;
&lt;p&gt;Money is a claim on future work, and work requires energy. When
pensions assume 7–8% annual returns, when startups pledge 10× growth,
and when national budgets bake in permanent productivity gains, they are
effectively promising that future societies will deliver 2–3 doublings
of net energy per century. If we instead hit a solar plateau—because
land, materials, or social license cap expansion—those financial
promises become unmoored. We can pretend that virtual goods, algorithmic
trading, or luxury desserts (to borrow Murphy’s Act Four anecdote)
deliver infinite utility without added energy, but the chefs, coders,
and data centers still eat, commute, and cool their CPU’s , GPU’s and
Tensor processors. The intangible economy rides on a very tangible
energy base.&lt;/p&gt;
&lt;h2 id=&quot;rewriting-the-business-plan&quot;&gt;Rewriting the Business Plan&lt;/h2&gt;
&lt;p&gt;Accepting a solar ceiling does not doom us to stagnation. It just
forces different design constraints:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;grow quality, not quantity—prioritize outcomes per unit energy … do
proof of useful work rather that roll the dice and gamble.&lt;/li&gt;
&lt;li&gt;align finance with expected energy supply rather than mythical
exponentials … and I am not talking of wasting energy on crypto.&lt;/li&gt;
&lt;li&gt;treat efficiency gains as buying time, not as a perpetual motion
machine … if you learnt enough physics in high school to reject the
perpetual motion machine, but have been lulled into perpetual 8% returns
from the finance markets, there is a serious schizophrenia issue.&lt;/li&gt;
&lt;li&gt;embed thermodynamic literacy in economic education so debates start
from the same math.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Murphy ends his essay noting that growth is not a “good quantum
number.” It is not conserved. Our job is to craft institutions,
portfolios, and narratives that can thrive when net energy flattens,
because physics already told us that day will arrive long before our
spreadsheets hit overflow errors.&lt;/p&gt;
</content><link rel='replies' type='application/atom+xml' href='http://whatnicklife.blogspot.com/feeds/5021821387650199920/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3220006345447041404/5021821387650199920' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3220006345447041404/posts/default/5021821387650199920'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3220006345447041404/posts/default/5021821387650199920'/><link rel='alternate' type='text/html' href='http://whatnicklife.blogspot.com/2025/12/solar-ceilings-and-compounding-dreams.html' title='Solar Ceilings and Compounding Dreams'/><author><name>Tisham Dhar</name><uri>http://www.blogger.com/profile/15154154153085427197</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3220006345447041404.post-5715192484569103603</id><published>2025-12-06T03:05:00.000-08:00</published><updated>2025-12-06T03:05:24.173-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="darwin"/><category scheme="http://www.blogger.com/atom/ns#" term="evolution"/><category scheme="http://www.blogger.com/atom/ns#" term="management"/><category scheme="http://www.blogger.com/atom/ns#" term="travel"/><title type='text'>Darwin 2022 - Ruminations Compendium</title><content type='html'>&lt;p&gt;Collected reflections from the July 2022 Darwin trip, a narrative of
adaptation, organisational change, and expansion can live in a single
place.&lt;/p&gt;
&lt;h2 id=&quot;july-19-lemmings-and-launchpads&quot;&gt;July 19 – Lemmings And
Launchpads&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;There is no exception to the rule that every organic being
naturally increases at so high a rate, that if not destroyed the earth
would soon be covered by the progeny of a single pair. Even slow
breeding man has doubled in twenty five years, and at this rate in a few
thousand years there would literally be no standing room for his
progeny.&lt;/em&gt; – &lt;strong&gt;Charles Darwin&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Like the lemming marching and diving into the ocean to self‑regulate,
humanity plunges itself into vices of its own creation: alcohol, drugs,
violence, and greed. Perhaps the next plunge is into the real ocean or
into the vacuum of space, chasing more room in which to stand or float.
Failure in harsh environments creates room by removing weaker
individuals, or greater resilience by rewarding the most adaptable.
Colonial Australia itself was founded on such selection—the most
adaptable individuals and the strictest rule enforcers reshaped an
unforgiving frontier.&lt;/p&gt;
&lt;h2 id=&quot;july-20-organisational-evolution-in-flight&quot;&gt;July 20 –
Organisational Evolution In Flight&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Seeing that a few members of such water-breathing classes as the
Crustacea and Mollusca are adapted to live on the land, and seeing that
we have flying birds and mammals, flying insects of vast diversified
types, and formerly had flying reptiles. It is conceivable that flying
fish, which now glide far through air, slightly rising and falling by
the aid of their fluttering fins, might have been modified into
perfectly winged animals.&lt;/em&gt; – &lt;strong&gt;Charles Darwin&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The ability to skim over water for a few metres comes from external
tweaks, but the ability to cross the Pacific like a Godwin Tern comes
from internal rewiring: hollow bones, high metabolism, and a brain with
a built‑in compass. Organisations face the same distinction. A brief
digital-transformation spasm can bolt on an app or a website, yet
sustaining that flight demands internal metamorphosis and a sense of
direction from leadership. Caterpillars become butterflies through
wholesale change—so must companies that aspire to be more than flying
fish.&lt;/p&gt;
&lt;h2 id=&quot;july-23-questions-for-the-corporate-naturalist&quot;&gt;July 23 –
Questions For The Corporate Naturalist&lt;/h2&gt;
&lt;ol type=&quot;1&quot;&gt;
&lt;li&gt;&lt;strong&gt;Where are the transitional forms?&lt;/strong&gt;&lt;br /&gt;
Organisations with no lines on the org chart operate as pure adhocracy.
Hidden behind corporate veils, they are like pupae in cocoons, waiting
to emerge in a more defined shape.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;How can specialised organs evolve?&lt;/strong&gt;&lt;br /&gt;
Marketing machines, technology muscle, sales teeth, enterprise-planning
backbone, analyst frontal lobes—each department is an organ honed for a
specific survival task.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Is behaviour or instinct inheritable?&lt;/strong&gt;&lt;br /&gt;
Culture answers this. The rituals, stories, and incentives that survive
layoffs and leadership changes become the genetic code of the firm.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Why are some species sterile when crossed, while others are
fertile?&lt;/strong&gt;&lt;br /&gt;
Some mergers and acquisitions thrive; others fail because the two
organisational genomes cannot integrate and diverge instead of
hybridising.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;july-24-conquering-new-lands&quot;&gt;July 24 – Conquering New
Lands&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;He who believes in the struggle for existence and in the
principle of natural selection, will acknowledge that every organic
being is constantly endeavouring to increase in numbers; and that if any
one being vary ever so little, either in habits or structure, and thus
gain an advantage over some of that inhabitant, however different it may
be from its own place, it will seize on the place of that
inhabitant.&lt;/em&gt; – &lt;strong&gt;Charles Darwin&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;International expansion is a contest for ecological niches. Bringing
hard‑won optimisations from one country to another is a bid to displace
incumbents. The organisations that vary—by process, by product, by
mindset—claim new ground first.&lt;/p&gt;
</content><link rel='replies' type='application/atom+xml' href='http://whatnicklife.blogspot.com/feeds/5715192484569103603/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3220006345447041404/5715192484569103603' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3220006345447041404/posts/default/5715192484569103603'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3220006345447041404/posts/default/5715192484569103603'/><link rel='alternate' type='text/html' href='http://whatnicklife.blogspot.com/2025/12/darwin-2022-ruminations-compendium.html' title='Darwin 2022 - Ruminations Compendium'/><author><name>Tisham Dhar</name><uri>http://www.blogger.com/profile/15154154153085427197</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3220006345447041404.post-4282903695964131183</id><published>2025-11-24T16:00:00.000-08:00</published><updated>2025-12-30T04:13:55.938-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="auckland"/><category scheme="http://www.blogger.com/atom/ns#" term="foss4g"/><category scheme="http://www.blogger.com/atom/ns#" term="geospatial"/><category scheme="http://www.blogger.com/atom/ns#" term="open-source"/><category scheme="http://www.blogger.com/atom/ns#" term="re-earth"/><category scheme="http://www.blogger.com/atom/ns#" term="rust"/><category scheme="http://www.blogger.com/atom/ns#" term="stac"/><category scheme="http://www.blogger.com/atom/ns#" term="webgpu"/><category scheme="http://www.blogger.com/atom/ns#" term="zarr"/><title type='text'>FOSS4G 2025 Auckland: Hazy Hops and Geospatial Heavy Lifting</title><content type='html'>&lt;p&gt;Every year, there is an international gathering of geospatial
software geeks working in open source somewhere in the world. This has
become known as the FOSS4G conference–with the “F” preferentially
standing for “Freedom” rather than just “Free”. The last one of these I
attended in person was a long while ago in Sydney (2009!). Since then, I
have attended a couple of the local Oceania editions and even served on
the board of the non-profit that organizes them, but this was my first
global one in a long time.&lt;/p&gt;
&lt;p&gt;It was great to see the community still alive with a lot of energy,
attracting around 400 people from around the world to Tāmaki
Makaurau.&lt;/p&gt;
&lt;h2 id=&quot;travel-and-weather-the-metallica-tax&quot;&gt;Travel and Weather: The
Metallica Tax&lt;/h2&gt;
&lt;p&gt;November in Auckland is very pleasant. Perhaps that is what drew so
many events there at once. Accommodation was expensive to unaffordable
due to a Metallica concert and an Indigenous education conference
happening simultaneously. There were, of course, amazing shows and
entertainment on offer as a result, but my wallet definitely felt the
“Metallica Tax”. I ended up staying a 30-minute bus ride away from the
city centre in Takapuna, which gave me some nice morning views of the
Hauraki Gulf before diving into the windowless conference rooms.&lt;/p&gt;
&lt;figure&gt;
&lt;img
src=&quot;https://lh3.googleusercontent.com/pw/AP1GczO4yfiFrntpFvWikQ7ctSPWjOFhxseHa1wt9CKdp5duB9G2xdNDDZYcs7TIrBDcNpaPbFhGCLxWu9jh0hRUFvUPbeytR_6114voHZF2c2eO1xakqVI2uYwFz0C2Daa1WMgV7HWf1OLT_YPBZ8xrJyobuw=w1733-h1305-s-no-gm?authuser=0&quot;
alt=&quot;Samoan Dance at the Opening&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Samoan Dance at the Opening&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;tutorials-rust-ai-and-no-code-flows&quot;&gt;Tutorials: Rust, AI, and
No-Code Flows&lt;/h2&gt;
&lt;h3 id=&quot;eo-with-rust---leo-hardtke&quot;&gt;EO with Rust - Leo Hardtke&lt;/h3&gt;
&lt;p&gt;Leo Hardtke’s tutorial was all about making Earth Observation (EO)
processing faster with Rust and without the Python overhead. It was,
however, plagued by Nix vagaries and the classic environment
distribution issues that seem to follow “modern” build systems
everywhere. When it worked, it was blazing fast. The code is available
on GitHub for those brave enough to venture into the world of memory
safety and zero-cost abstractions.&lt;/p&gt;
&lt;figure&gt;
&lt;img
src=&quot;https://lh3.googleusercontent.com/pw/AP1GczP77n9taSH3s-N5lyr-Nugu6ZAGVJwQ560vymSJwgrs2b6xM0aD9lm3zw9ekTenydlUXmNrg5it30aXbWo9XcLwA9JJQAW2FJ2O-PF3BTaEXbDkx_5N0x3VMEVek2Upjndnr_g52HaQMnRoEgQ9587AnA=w1733-h1305-s-no-gm?authuser=0&quot;
alt=&quot;ODC Stac in Rust&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;ODC Stac in Rust&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3 id=&quot;ai-in-the-frontend---felix-palmer&quot;&gt;AI in the Frontend - Felix
Palmer&lt;/h3&gt;
&lt;p&gt;Felix Palmer showed off a cool Claude-enabled frontend to make
Deck.gl do things in response to free-text commands. Zooming and
searching is just the beginning; we can also do custom frontend
processing using the frontend equivalent of GEOS, Turf.js.&lt;/p&gt;
&lt;p&gt;I hit a snag here: I could not get my account activation SMS from
Claude while in NZ (roaming issues, I suspect). So, in true maker
fashion, I ported the code to work with AWS Bedrock instead. It’s a good
reminder that in the world of LLMs, being tied to a single API is a
recipe for frustration.&lt;/p&gt;
&lt;figure&gt;
&lt;img
src=&quot;https://lh3.googleusercontent.com/pw/AP1GczMiWdmQu9i4M9hF9JNuCZ0MPQfI0EqrHAjCEY92igXB7JHCRUy5tG9EdUf1v0-dUzxvtXA8H1J1D39DGjzIBOQk3Xi0xmJc8LjErBJEPtd37LsBVuSFRWgtRrc7dXsew_aQWpi4IjGMviZ4-pmYP3IGSg=w1733-h1305-s-no-gm?authuser=0&quot;
alt=&quot;Multi-lingual Map AI&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Multi-lingual Map AI&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3 id=&quot;reearth-flow---kyle-waite&quot;&gt;Re:earth Flow - Kyle Waite&lt;/h3&gt;
&lt;p&gt;This was perhaps the most interesting tutorial from an open-source
and national policy perspective. I often insist that science developers
learn programming, but sometimes for adoption, this is simply not a
feasible change. This is what creates room for numerous commercial and
open-source tooling for GUIs and no-code/low-code workflow systems like
FME, ESRI, and even the QGIS toolbox.&lt;/p&gt;
&lt;p&gt;As part of the Plateau project, the Japanese government is putting
together the “Flow” framework for prefectures to process and convert
their own 3D models. The intro to the UI tools was amazing, and in time,
it seems like it can challenge FME. The state management is done by
y.js, and we had a fun time getting multiple users to modify the flow
until it broke in spectacular fashion.&lt;/p&gt;
&lt;figure&gt;
&lt;img
src=&quot;https://lh3.googleusercontent.com/pw/AP1GczPFz1E0lx6ZjNs3biXR8u9R0Ft1aj5RN_VXN4W2sEdnMvwlitjfjjrPzac3ZYJ3vwZQ7KvzxlOQ1TuzeANUsYOO9XvAf3hqHbPwNOu5-1gaIA7_wGFDCMjkIFuAS3TBj-Hi8hXzIwU9LYL35-NZawI4zA=w1733-h1305-s-no-gm?authuser=0&quot;
alt=&quot;Re:Earth Flow Intro&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Re:Earth Flow Intro&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2
id=&quot;presentations-the-ones-that-stuck-with-me-among-many-excellent-ones&quot;&gt;Presentations:
The ones that stuck with me among many excellent ones&lt;/h2&gt;
&lt;p&gt;For the full roll of presentations check out the 150+ &lt;a
href=&quot;https://www.youtube.com/playlist?list=PLlZzWSPAR5GYPAGSgs1Z6ydhoVgL7CAHd&quot;&gt;youtube
playlist&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;the-java-geospatial-ecosystem---jody-garnett&quot;&gt;The Java
Geospatial Ecosystem - Jody Garnett&lt;/h3&gt;
&lt;p&gt;Jody Garnett gave a deep dive into the state of the art behind the
libraries doing the heavy lifting in the Java Geospatial ecosystem: JTS,
GeoTools, and the long journey behind getting the Java Imaging library
ported to an open-source equivalent supported by the Eclipse foundation.
It’s a reminder that while Python gets the hype, a lot of the world’s
spatial data still moves through Java pipes. I ended up also going to
his talk on Geoserver, which keeps being a force to reckon with in
serving GIS data at scale.&lt;/p&gt;
&lt;figure&gt;
&lt;img
src=&quot;https://lh3.googleusercontent.com/pw/AP1GczNtj9Fz6gOQZqKQ7T2pmE0-4mcpCyBhWQgXIo101v5oJFavoj5qLzoCD3OZQOyYRcqLue0AaXvTUwH7-_5gCOaz6nbQQoU_A-Uo3kK4KhU-zhNKY8CJ456qQMpUb0mb-c_xARI__90casLTtBYMJHxEUA=w1733-h1305-s-no-gm?authuser=0&quot;
alt=&quot;State of GeoTools, Geoserver and JTS&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;State of GeoTools, Geoserver and
JTS&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3 id=&quot;gpu-accelerated-zarr-loading---wei-ji&quot;&gt;GPU Accelerated Zarr
Loading - Wei Ji&lt;/h3&gt;
&lt;p&gt;Wei Ji’s presentation on GPU-native Zarr was a highlight. Optimizing
data throughput for large-scale geospatial ML workflows is the new
frontier, and moving the bottleneck from the CPU to the GPU is where the
real gains are.&lt;/p&gt;
&lt;figure&gt;
&lt;img
src=&quot;https://lh3.googleusercontent.com/pw/AP1GczNcOi8-mDuRtPPjVTsSwjq95KPqCA7VpT62RK7SG-26rdQi9hAxX-Rb_9jewiMyUOlGwZ0LjEoZvrkSlzPxgERMYqcFTNjTBG_nXdTRv2fSz5AmL3Fkuk_pXZcqRvowdioxJ69W_5g8Ub6bWooqF0DGdQ=w983-h1305-s-no-gm?authuser=0&quot;
alt=&quot;Zarr Accelerated by GPU&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Zarr Accelerated by GPU&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3 id=&quot;is-zarr-the-new-cog---jarrett-keifer-and-julia-signell&quot;&gt;Is Zarr
the new COG? - Jarrett Keifer and Julia Signell&lt;/h3&gt;
&lt;p&gt;An excellent presentation dispelling the hype around Zarr. The
takeaway? Given the same input and compression, the resulting content is
the same size. It’s the usage pattern and the “tyranny of chunking” that
really affects performance, along with the fine points about using
multiple files, shards, and inodes.&lt;/p&gt;
&lt;figure&gt;
&lt;img
src=&quot;https://lh3.googleusercontent.com/pw/AP1GczMr5Ceg5gRzzaLHmzQoje6kPWYv_0-q4dSkpSg8aQeM8a4GSRPECjN2eCkfRzQl4npxW6Sb6aO-DCH6ELLqbw4PztxCl0MVswxkFA055l-KMGvppSzRfu01LedKW4c0krKnuEOz3jx2Ta_ynX4smI1a9w=w1733-h1305-s-no-gm?authuser=0&quot;
alt=&quot;Zarr vs COG&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Zarr vs COG&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3 id=&quot;navara-web3d-engine---keiya-higuchi&quot;&gt;Navara Web3D Engine - Keiya
Higuchi&lt;/h3&gt;
&lt;p&gt;The Re:Earth folks returned with Navara, a re-imagined 3D engine for
the web using a modern stack including WebGPU. It aims to create more
options for realistic rendering and a functional separation between GIS
functions and visualization functions–which are often messily
intertwined in current offerings.&lt;/p&gt;
&lt;figure&gt;
&lt;img
src=&quot;https://lh3.googleusercontent.com/pw/AP1GczNccStdUfMhrk7dStuv2fujA4OiDB4-hSB5DbxuXIUgnQPB1PavtqRfo8wfyMvueZkhtx7iO0UZzcaWqjDtMXsMjbCg1SLW52x-B4e9Bge2TQU6gCwHx63pZ0CD3uEeZ63wvVkS-58i3oE2bzc3Kga32g=w1733-h1305-s-no-gm?authuser=0&quot;
alt=&quot;Navara 3D Web Viz&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Navara 3D Web Viz&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3 id=&quot;stac-adventures-with-matt-hanson&quot;&gt;STAC Adventures with Matt
Hanson&lt;/h3&gt;
&lt;p&gt;One of the most fun presentations was Matt Hanson’s “Choose Your Own
Adventure” session. He let the audience pick the path in D&amp;amp;D fashion
to learn more about the STAC ecosystem. I threw in my two cents on the
fact that “not all STAC is made equal” and the desperate need for
conformance checks on hosting services that claim to be STAC compliant
but fail in subtle ways that break downstream libraries.&lt;/p&gt;
&lt;figure&gt;
&lt;img
src=&quot;https://lh3.googleusercontent.com/pw/AP1GczP5rZfyQ_IhssnazaSWSfyBoVBziKYDG17bEcmjt4GO_rUmy4Qi9rviKP5Gw6SNKZEEp2e7cY9ucZVVv40yK9I3pvNKvt89mJVFqTiKl2AT3hM4YePpACjSz_RnRr_e0FyjIrBqphiugxrvNwEQGZYFIA=w1733-h1305-s-no-gm?authuser=0&quot;
alt=&quot;STAC Catalog&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;STAC Catalog&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3 id=&quot;esas-zarr-foray---james-banting-sparkgeo&quot;&gt;ESA’s Zarr Foray -
James Banting (SparkGeo)&lt;/h3&gt;
&lt;p&gt;ESA is restructuring the Sentinel satellite imagery archive into DGGS
/ Healpix Zarr format and publishing the EOPF toolkit. The SparkGeo
presentation showed the state of implementation of the user-facing
libraries and how they are being integrated into various tools.&lt;/p&gt;
&lt;figure&gt;
&lt;img
src=&quot;https://lh3.googleusercontent.com/pw/AP1GczM21hc7L_88T7CXCJ-LAgkCkQGRtbR8KKrHrj89a3na1hvVTUAu0YML6dU3YqwkdW1bVGPv_qLByLoILv12YHHsUysmMrG8WogwTMtqzEJxIWhbquEfCF65Q50xFjNEMOYOCI_XlT6_YatdI6_FYKBIow=w1733-h1305-s-no-gm?authuser=0&quot;
alt=&quot;Zarr in Action&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Zarr in Action&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;after-parties-hazy-hops-and-community&quot;&gt;After Parties: Hazy Hops
and Community&lt;/h2&gt;
&lt;p&gt;The conference after-parties at the pub are where most of the real
action happens. I spent my evenings hanging out with a mix of old
friends and new faces, trying the famous New Zealand hazy hops. There’s
something about a good IPA that makes discussing coordinate reference
systems much more bearable.&lt;/p&gt;
&lt;figure&gt;
&lt;img
src=&quot;https://lh3.googleusercontent.com/pw/AP1GczMqFeZBl0yV4OOkmH4seYUaQmTQJ5KafmeGJNuJKte8UpVIx_YHyIQdC2fAtZd1MzvDN3QG1ti_WRLkx3cjT57b_xvOzUbr1P2J1Dzh75vlEHQz4SJ70-N1lYS3XV3zUZMvvvYB7GEhaRvDMW7zg5EyFg=w1733-h1305-s-no-gm?authuser=0&quot;
alt=&quot;Beer offerings - NZ Hazy Hops&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Beer offerings - NZ Hazy
Hops&lt;/figcaption&gt;
&lt;/figure&gt;
</content><link rel='replies' type='application/atom+xml' href='http://whatnicklife.blogspot.com/feeds/4282903695964131183/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3220006345447041404/4282903695964131183' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3220006345447041404/posts/default/4282903695964131183'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3220006345447041404/posts/default/4282903695964131183'/><link rel='alternate' type='text/html' href='http://whatnicklife.blogspot.com/2025/11/foss4g-2025-auckland-hazy-hops-and.html' title='FOSS4G 2025 Auckland: Hazy Hops and Geospatial Heavy Lifting'/><author><name>Tisham Dhar</name><uri>http://www.blogger.com/profile/15154154153085427197</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://lh3.googleusercontent.com/pw/AP1GczO4yfiFrntpFvWikQ7ctSPWjOFhxseHa1wt9CKdp5duB9G2xdNDDZYcs7TIrBDcNpaPbFhGCLxWu9jh0hRUFvUPbeytR_6114voHZF2c2eO1xakqVI2uYwFz0C2Daa1WMgV7HWf1OLT_YPBZ8xrJyobuw=s72-w1733-h1305-s-c-no-gm?authuser=0" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3220006345447041404.post-322668621403864527</id><published>2022-11-05T06:23:00.006-07:00</published><updated>2022-11-05T06:27:54.703-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="community"/><category scheme="http://www.blogger.com/atom/ns#" term="electronics"/><category scheme="http://www.blogger.com/atom/ns#" term="pcb assembly"/><category scheme="http://www.blogger.com/atom/ns#" term="promotion"/><title type='text'>Drop shipping products from PCBWay</title><content type='html'>&lt;h1 id=&quot;drop-shipping-products-from-pcbway&quot;&gt;Drop shipping products from PCBWay&lt;/h1&gt;
&lt;p&gt;For a while I have been ordering PCB’s from &lt;a href=&quot;https://www.pcbway.com/project/shareproject/ATM90E36_Breakout_a7d8bccf.html&quot;&gt;PCBWay&lt;/a&gt; and parts from &lt;a href=&quot;https://au.mouser.com/&quot;&gt;Mouser&lt;/a&gt; and &lt;a href=&quot;https://www.digikey.com.au/&quot;&gt;Digikey&lt;/a&gt;, then hand assembling them at home. These have been very small scale cottage industry style runs and ultimately time consuming as I focus more on design and evaluation of new energy monitor ASIC’s such as the &lt;a href=&quot;&quot;&gt;V9261F&lt;/a&gt;. When PCBWay started offering to stock and drop ship my PCB’s directly from the factory using their extensive clout with DHL, I promptly signed up for the service.&lt;/p&gt;
&lt;p&gt;Recently I have been getting my &lt;a href=&quot;https://github.com/whatnick/ATM90E36_Breakout_KiCAD&quot;&gt;ATM90E36 Devkit&lt;/a&gt; PCB’s assembled there. The service has been excellent with concierge like parts choice and purchase. Followed by extremely helpful consultation on assembly progress and correctness.&lt;/p&gt;
&lt;p&gt;I received the following images after the first stage and confirmed the crystal and LED’s.&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNEY2otpCpvnRxLZn1ncbbgyeYG_vYzoyhFkhmeuszriHHgPmKGoPB-Obc7dVBd2UOy1B1amtHn6G4CczpNmh_kjPfuq1pFqEWwzVKTPOyYVIUHZBXNQN5ejFRygz2vcTfqHs62kUXQI5ROSdeLSUbroUzMX20QtUcyNMNq9lTzezSZMRwv1vzWDk2/s756/Q1-orientation%20confirmation.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;588&quot; data-original-width=&quot;756&quot; height=&quot;249&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNEY2otpCpvnRxLZn1ncbbgyeYG_vYzoyhFkhmeuszriHHgPmKGoPB-Obc7dVBd2UOy1B1amtHn6G4CczpNmh_kjPfuq1pFqEWwzVKTPOyYVIUHZBXNQN5ejFRygz2vcTfqHs62kUXQI5ROSdeLSUbroUzMX20QtUcyNMNq9lTzezSZMRwv1vzWDk2/s320/Q1-orientation%20confirmation.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhr0WFpmPB_hAMPU-LAaF9tI7vj5fXukcuMV1kHA8Wmt0s0paVi8DXw_bnyUablpp-s4CKky0eALKeV8MbGnppu7wCjps2qDAU2HRpxN82womh5jsvIhVhmR_kW2A0HY3xEXFoBTDtItx1Zu2_iMNhg89DUKkpa3jzqEldMlnS3jxh8QB-EjcMs82Iv/s4608/T-U137W51580A-01.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;3456&quot; data-original-width=&quot;4608&quot; height=&quot;240&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhr0WFpmPB_hAMPU-LAaF9tI7vj5fXukcuMV1kHA8Wmt0s0paVi8DXw_bnyUablpp-s4CKky0eALKeV8MbGnppu7wCjps2qDAU2HRpxN82womh5jsvIhVhmR_kW2A0HY3xEXFoBTDtItx1Zu2_iMNhg89DUKkpa3jzqEldMlnS3jxh8QB-EjcMs82Iv/s320/T-U137W51580A-01.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtTLEC_IIN7goJ-8qe-oW19of6SG2wGNKLsTohXeU33LP6G3ONawgaFCc-29YHHU8wUeGCy4t-_bGh2-bZl6b90NzZoSkdCecba2XN3YzbPaPK4BZQMky4Tlmjqwz9g1dRDz-tns8YB9kc_UmTc14-D8tKw_3fUBLwW5eIvpCmROKGBkprmOC57Pc8/s4608/T-U137W51580A-02.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;3456&quot; data-original-width=&quot;4608&quot; height=&quot;240&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtTLEC_IIN7goJ-8qe-oW19of6SG2wGNKLsTohXeU33LP6G3ONawgaFCc-29YHHU8wUeGCy4t-_bGh2-bZl6b90NzZoSkdCecba2XN3YzbPaPK4BZQMky4Tlmjqwz9g1dRDz-tns8YB9kc_UmTc14-D8tKw_3fUBLwW5eIvpCmROKGBkprmOC57Pc8/s320/T-U137W51580A-02.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXqXVbWMlGTlX_dnRcX8GMw9TusoGBZNk7OAILeNQB7FfPOcGVinDssJPwiQbLeAOSCb8zqy7Bu86s4YBliw_himCMkiUWYqgpRVG8gm5fwXh5mcltnEStU-wvmOJRl6xETiB1ix1WFpnHW19qu0ADWZr9guSksU62KjkBQSk79Z4f0WLN8V2oKiPZ/s876/The%20arrow%20indicates%20cathode%20.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;542&quot; data-original-width=&quot;876&quot; height=&quot;198&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXqXVbWMlGTlX_dnRcX8GMw9TusoGBZNk7OAILeNQB7FfPOcGVinDssJPwiQbLeAOSCb8zqy7Bu86s4YBliw_himCMkiUWYqgpRVG8gm5fwXh5mcltnEStU-wvmOJRl6xETiB1ix1WFpnHW19qu0ADWZr9guSksU62KjkBQSk79Z4f0WLN8V2oKiPZ/s320/The%20arrow%20indicates%20cathode%20.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;Then I received some more inspection photos to allay any doubts.&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4Z0nJ7s3SrPC1HJ_5M1LupeAIDz_FQB2ilhKbZcwgjKtgUUVxOL48JjfhaFWpJmdM0rGYxwYqNEQ3N37CU0bJi3XDiJE3ALYd5ycIm2_KsVTn0rEJ94lWGdKJqkoIxkdw2uXAtz2Fkv8sDb38t3I-OwXzIYvxxi25g_8KJu5Brn88-2zzRH29mEcL/s1052/T-U137W51580A-the%20arrow%20indicates%20cathode%20.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;835&quot; data-original-width=&quot;1052&quot; height=&quot;254&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4Z0nJ7s3SrPC1HJ_5M1LupeAIDz_FQB2ilhKbZcwgjKtgUUVxOL48JjfhaFWpJmdM0rGYxwYqNEQ3N37CU0bJi3XDiJE3ALYd5ycIm2_KsVTn0rEJ94lWGdKJqkoIxkdw2uXAtz2Fkv8sDb38t3I-OwXzIYvxxi25g_8KJu5Brn88-2zzRH29mEcL/s320/T-U137W51580A-the%20arrow%20indicates%20cathode%20.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfd_H5I90aNo-VAsTkuAzyxHQGZ_18AKuHTG2wKCXN3uyFh6eEti9p4UWawtqZ4UD6mzGnxUHffVVvR5nECOL4jOqFsh27BOlH4eHFWLyIYjLwZE4fNQEUnuPqmrTCx14tJpqtkrg6YkbHFP7jp0vs1Wlh4S35zD5pigFuQCutHRMbQsGFUC9jZXXh/s4624/Updated%20T-U137W51580A-01.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;3472&quot; data-original-width=&quot;4624&quot; height=&quot;240&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfd_H5I90aNo-VAsTkuAzyxHQGZ_18AKuHTG2wKCXN3uyFh6eEti9p4UWawtqZ4UD6mzGnxUHffVVvR5nECOL4jOqFsh27BOlH4eHFWLyIYjLwZE4fNQEUnuPqmrTCx14tJpqtkrg6YkbHFP7jp0vs1Wlh4S35zD5pigFuQCutHRMbQsGFUC9jZXXh/s320/Updated%20T-U137W51580A-01.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;Looking forward to the stock appearing on the &lt;a href=&quot;https://www.pcbway.com/project/gifts_detail/ATM90E26_FeatherWing.html&quot;&gt;shop front&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;NOTE: This is a paid promotion of PCBWay services&lt;/strong&gt;&lt;/p&gt;
</content><link rel='replies' type='application/atom+xml' href='http://whatnicklife.blogspot.com/feeds/322668621403864527/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3220006345447041404/322668621403864527' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3220006345447041404/posts/default/322668621403864527'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3220006345447041404/posts/default/322668621403864527'/><link rel='alternate' type='text/html' href='http://whatnicklife.blogspot.com/2022/11/drop-shipping-products-from-pcbway.html' title='Drop shipping products from PCBWay'/><author><name>Tisham Dhar</name><uri>http://www.blogger.com/profile/15154154153085427197</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNEY2otpCpvnRxLZn1ncbbgyeYG_vYzoyhFkhmeuszriHHgPmKGoPB-Obc7dVBd2UOy1B1amtHn6G4CczpNmh_kjPfuq1pFqEWwzVKTPOyYVIUHZBXNQN5ejFRygz2vcTfqHs62kUXQI5ROSdeLSUbroUzMX20QtUcyNMNq9lTzezSZMRwv1vzWDk2/s72-c/Q1-orientation%20confirmation.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3220006345447041404.post-6189276971715771251</id><published>2020-12-27T13:51:00.002-08:00</published><updated>2020-12-31T05:28:56.985-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Code Logistics"/><category scheme="http://www.blogger.com/atom/ns#" term="Design patterns"/><category scheme="http://www.blogger.com/atom/ns#" term="Software Architecture"/><title type='text'>Trucks vs Trains as an analogy for Microservices vs Monoliths</title><content type='html'>&lt;p&gt;2018 and 2019 was mostly spent obsessing over containers, trucks, trailers and hand written paper invoices for me. I was helping build out the technology stack and engineering team for &lt;a href=&quot;https://www.lorisystems.com/&quot;&gt;Lori Systems&lt;/a&gt;. Early in 2019 we made our first DevOps hire, getting &lt;a href=&quot;https://www.linkedin.com/in/cmakamara/&quot;&gt;Clive&lt;/a&gt; from Safaricom and getting started on migrating our handrolled Django monolith from EC2 to EKS. We would make jokes around shipping containers using containers. Clive even had a container shaped stressball with the EKS logo on it. This set me thinking on the parallels between shipping code and shipping goods, perhaps also led to the foundations of this post.&lt;/p&gt;
&lt;h2 id=&quot;intermodal-shipping-in-the-real-world-and-in-software&quot;&gt;Intermodal Shipping in the real-world and in software&lt;/h2&gt;
&lt;p&gt;Over the almost 2-years of work in Logistics I learnt a lot about how the global logistics system works. Almost like the life-blood of the planet. Large container ships abstract away contents and ship things from Taiwan to Timbukutu. The seminal book on this topic is perhaps, &lt;a href=&quot;https://doi.org/10.1515/9781400880751&quot;&gt;The BOX&lt;/a&gt;. Watching global shipping lanes in &lt;a href=&quot;https://www.marinetraffic.com/en/ais/home/centerx:-12.0/centery:25.0/zoom:4&quot;&gt;Marine Traffic&lt;/a&gt; and scraping &lt;a href=&quot;https://www.kpa.co.ke/Pages/14DaysList.aspx&quot;&gt;ships arriving in Mombasa&lt;/a&gt; from the KPA Sharepoint became a daily ritual. I digress, back to the original point on the importance for containerization in shipping code or machinery.&lt;/p&gt;
&lt;p&gt;Docker uses the ubiquitous whale/ship logo, most containers arrive at ports this way from the oceans of developers. I don&#39;t quite have an analogy here for the massive ships that land the containers at ports, some &lt;a href=&quot;https://en.wikipedia.org/wiki/Twenty-foot_equivalent_unit&quot;&gt;500 or 1000 TEU&#39;s&lt;/a&gt; at a time. The analogy here covers land transport aspects, somewhat related to how code runs in production and is typically served via datacenters / public clouds to users.&lt;/p&gt;
&lt;p&gt;Containers themselves make transfer of goods/code from development (ships) to production (trains/trucks) easy. However even containerized applications can demonstrate tight coupling similar to what a train has, in effect being a distributed monolith, instead of a true suite of microservices. In my opinion, any system that requires a release train approach for new features is most likely to be a distributed monolith masquarding as microservices. The real flexibility comes from the low coupling between containers and the freedom to release each clearly delineated service at its own cadence on the roads.&lt;/p&gt;
&lt;h2 id=&quot;trains-are-awesome&quot;&gt;Trains are awesome&lt;/h2&gt;
&lt;p&gt;My 5yo is currently obsessed with steam engines, even though they are from an era long gone. There is something magical about a powerful engine pulling everything along smoothly on a set of constraints (rails). It works nicely as long as no quick changes are needed in the carriages and everyone wants to get to the same destination. Trouble arises when something in the closely coupled chain of components goes awry and requires a quick change. I still don&#39;t understand the &lt;a href=&quot;https://www.denofgeek.com/tv/snowpiercer-episode-6-review-trouble-comes-sideways/&quot;&gt;scene in snow piercer&lt;/a&gt; where a few wagons were dumped in a siding at speed. If we can do that one neat trick perhaps monoliths would become much more maintainable. In early stages of a product monoliths are a &lt;a href=&quot;https://www.infoq.com/news/2019/04/monolith-vs-microservices/&quot;&gt;nice simple entry point&lt;/a&gt;, especially if the features are narrowly scoped and well coupled. On the reverse the monolith may be a very good idea for a mature product which is not changing rapidly and perhaps needs to be optimised for performance instead by reducing communication overhead between components by introducing tight coupling. In both cases a modular approach and service-oriented designs are still feasible, as long as the implementation and maintenance team is aware of the implications. People are still driving around in classic cars from the 1900&#39;s, where as steam locomotives from that era are languishing in museums.&lt;/p&gt;
&lt;h2 id=&quot;trucks-are-flexible&quot;&gt;Trucks are flexible&lt;/h2&gt;
&lt;p&gt;One of the killer advantages of trucks in the logistics business is their ability to deliver right to the factory or warehouse loading bay. It is simply not feasible to build train tracks to serve every address. Even in areas with great railway infrastructure, buffers (known as Inland container depots) have to be placed to cover the last few miles of transport from the rail to the industrial areas. This sort of mode can sometimes be seen in Microservices being layered on older monoliths to provide user facing services, especially in banking systems. The other great advantage trucks have is the ability overtake each other gradually along the road, this manifests itself in software systems as rolling deployment of new features. Such an approach requires careful management of the stateful parts of the system such as storage and database schemas. Otherwise it turns into a Fast and Furious game of stealing a container from a moving platform, aka the &lt;a href=&quot;https://www.eurogamer.net/articles/2020-12-07-gangs-are-hitting-lorries-on-the-run-to-steal-ps5s&quot;&gt;Romanian Rollover&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;this-analogy-is-not-new&quot;&gt;This analogy is not new&lt;/h2&gt;
&lt;p&gt;The logistics analogies are rife in software engineering, we &lt;code&gt;ship&lt;/code&gt; code, we &lt;code&gt;package&lt;/code&gt; things, we have &lt;code&gt;release trains&lt;/code&gt;. The largest real world container orchestration organization &lt;a href=&quot;https://www.maersk.com/&quot;&gt;Maersk&lt;/a&gt; uses a 7-point logo surprisingly similar to the most popular software container orchestration platform &lt;a href=&quot;https://kubernetes.io/&quot;&gt;Kubernetes&lt;/a&gt;. I will continue updating this post as more ideas and links come together.&lt;/p&gt;
&lt;p&gt;You can engage with article via comments or the twitter thread.&lt;/p&gt;
&lt;blockquote class=&quot;twitter-tweet&quot;&gt;
&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;
Random Roadtrip Rumination : Microservices vs Monotliths is Trucks vs Trains for shipping features.
&lt;/p&gt;
— Tisham Dhar (&lt;span class=&quot;citation&quot;&gt;@whatnick&lt;/span&gt;) &lt;a href=&quot;https://twitter.com/whatnick/status/1342654642736353281?ref_src=twsrc%5Etfw&quot;&gt;December 26, 2020&lt;/a&gt;
&lt;/blockquote&gt;
&lt;script async src=&quot;https://platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;
</content><link rel='replies' type='application/atom+xml' href='http://whatnicklife.blogspot.com/feeds/6189276971715771251/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3220006345447041404/6189276971715771251' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3220006345447041404/posts/default/6189276971715771251'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3220006345447041404/posts/default/6189276971715771251'/><link rel='alternate' type='text/html' href='http://whatnicklife.blogspot.com/2020/12/trucks-vs-trains-as-analogy-for.html' title='Trucks vs Trains as an analogy for Microservices vs Monoliths'/><author><name>Tisham Dhar</name><uri>http://www.blogger.com/profile/15154154153085427197</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3220006345447041404.post-2570676582312627632</id><published>2020-10-04T15:19:00.004-07:00</published><updated>2020-10-24T04:23:36.775-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="blender"/><category scheme="http://www.blogger.com/atom/ns#" term="FreeCAD"/><category scheme="http://www.blogger.com/atom/ns#" term="KiCAD"/><category scheme="http://www.blogger.com/atom/ns#" term="Open-Source"/><category scheme="http://www.blogger.com/atom/ns#" term="python"/><category scheme="http://www.blogger.com/atom/ns#" term="qgis"/><title type='text'>Desktop Software API&#39;s in Python (KiCAD, FreeCAD, Blender, QGIS)</title><content type='html'>&lt;h1 id=&quot;python-wraps-around-everything&quot;&gt;Python wraps around everything&lt;/h1&gt;
&lt;p&gt;For the last couple of years I have mostly written &lt;a href=&quot;https://github.com/GeoscienceAustralia/dea-notebooks&quot;&gt;Satellite Data Processing code&lt;/a&gt; in Python and plenty of &lt;a href=&quot;https://github.com/opendatacube/datacube-ows&quot;&gt;Flask/Django web services&lt;/a&gt;. However Python is also an excellent automation tool for GUI based applications allowing custom plugins to be written and functionality provided out of the box extended by users.&lt;/p&gt;
&lt;p&gt;The first desktop application I seriously looked at Python plugins for was QGIS. It was early days of learning how to wrap C++ code using &lt;a href=&quot;http://osgeo-org.1560.x6.nabble.com/GDAL-Python-Bindings-td4157607.html#a4157610&quot;&gt;SWIG/SIP&lt;/a&gt; etc. In the old mailing list you can find a much younger me making inane comments about mixing wrapper metaphors in QGIS with SWIG + SIP. We have come a long way since then and SIP based bindings are the mainstay of QGIS plugins.&lt;/p&gt;
&lt;h2 id=&quot;qgis&quot;&gt;QGIS&lt;/h2&gt;
&lt;p&gt;QGIS has so many Python plugins that they need &lt;a href=&quot;https://plugins.qgis.org/&quot;&gt;a registry&lt;/a&gt; of their own. Occasionally QGIS Python gets twisted around itself due to &lt;a href=&quot;https://github.com/qgis/QGIS/issues/37783&quot;&gt;multiple Pythons in the user enviroment&lt;/a&gt;. You can also flip the python API around and instead of building a plugin you can turn QGIS into a custom desktop application. Which is what I have done with my basic &lt;a href=&quot;https://github.com/whatnick/demo_qgis_app&quot;&gt;Airport Viewer&lt;/a&gt; demo.&lt;/p&gt;
&lt;p&gt;QGIS being a fairly extensive and complex C++ application which takes &lt;a href=&quot;https://whatnicklife.blogspot.com/2020/08/compiling-qgis-in-msvc-in-2020.html&quot;&gt;hours to compile&lt;/a&gt;, being able to make small quick changes in python is invaluable.&lt;/p&gt;
&lt;h2 id=&quot;kicad&quot;&gt;KiCAD&lt;/h2&gt;
&lt;p&gt;At the time of writing KiCAD has an extensive Python API for processing the automating the PCB layout part of the workflow and this has lead to many innovations in automating traditionally laborious hand layout or even performing complex simulations / optimization to set trace lengths. For example &lt;a href=&quot;https://twitter.com/_joshajohnson&quot;&gt;Josh Johnson&lt;/a&gt; has one for &lt;a href=&quot;https://github.com/joshajohnson/ecp5-mini/blob/master/breakouts/clock-test/circle-placement.py&quot;&gt;laying parts out in a circle&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/gregdavill&quot;&gt;Greg Davill&lt;/a&gt; has several for &lt;a href=&quot;https://github.com/gregdavill/ButterStick/blob/main/lib/bus_aware_length_matching_verification.py&quot;&gt;length matching&lt;/a&gt; and &lt;a href=&quot;https://github.com/gregdavill/kicadScripts&quot;&gt;rendering file generation&lt;/a&gt;. My personal favourite among the KiCAD scripts is the one for generation of &lt;a href=&quot;https://github.com/openscopeproject/InteractiveHtmlBom&quot;&gt;Interactive BOM&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I am really looking forward to Python script support in the &lt;a href=&quot;https://forum.kicad.info/t/plans-for-the-python-api-for-eeschema/1776&quot;&gt;Schematic Editor&lt;/a&gt;. Meanwhile programmatic Schematic generation tools like &lt;a href=&quot;https://github.com/xesscorp/skidl&quot;&gt;Skidl&lt;/a&gt; provide schematic oriented Python fun.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/pcbarts/stylized-blender-setup&quot;&gt;rendering&lt;/a&gt; of the PCB&#39;s is often done in Blender. Which has its own set of Python nicities.&lt;/p&gt;
&lt;h2 id=&quot;blender&quot;&gt;Blender&lt;/h2&gt;
&lt;p&gt;My first foray in creating a &lt;a href=&quot;https://docs.blender.org/api/current/index.html#&quot;&gt;Blender API&lt;/a&gt; based application was during the Kinect USB protocol hacking days. The data stream had just been decoded and I wanted an easy pipeline to a commonly installed / open-source 3D display software. The Python API is mature enough for people these days to quickly put together &lt;a href=&quot;https://github.com/moraell/KinectMocap4Blender&quot;&gt;motion capture plugins&lt;/a&gt; for Blender. This plugin however demonstrates the challenges for creating native plugins for blender, the &lt;a href=&quot;https://docs.python.org/3/faq/windows.html#is-a-pyd-file-the-same-as-a-dll&quot;&gt;.pyd&lt;/a&gt; files for Python have to be recreated for different versions of Blender for ABI compaitibility.&lt;/p&gt;
&lt;p&gt;Getting the binaries working has had me thrashing about and posting in &lt;a href=&quot;https://blenderartists.org/t/python-as-a-module-msvc2010-win64/552870&quot;&gt;forums&lt;/a&gt;, then sticking to a working Blender build with Python 2.7 for about 5 years since I did not want to touch it and break it. My integration actually reversed the &lt;a href=&quot;https://wiki.blender.org/wiki/Building_Blender/Other/BlenderAsPyModule&quot;&gt;embedding process&lt;/a&gt;, i.e. instead of using additional modules in the Blender embedded python I embedded Blender in a 3D GIS automation.&lt;/p&gt;
&lt;p&gt;Native plugin weirdness aside, Blender Python API is a really powerful tool for creating procedural objects from waves / &lt;a href=&quot;https://b3d.interplanety.org/en/fluid-simulation-in-blender-2-80/&quot;&gt;fluid simulation&lt;/a&gt; to astrophysics with &lt;a href=&quot;https://amuse.readthedocs.io/en/latest/tutorial/blender.html&quot;&gt;amuse&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;freecad&quot;&gt;FreeCAD&lt;/h2&gt;
&lt;p&gt;FreeCAD is sort of the third part of my physical electrical / mechnical design triumvirate. I occasionally design parts for KiCAD in FreeCAD, or bring multiple boards together to &lt;a href=&quot;https://archive.org/details/kicon_2019-MCAD_ECAD_For_DIN_Rail_Energy_Monitors&quot;&gt;test enclosure fit&lt;/a&gt;. FreeCAD also has an extensive python library which is leveraged by KiCAD part library maintainers to &lt;a href=&quot;https://github.com/easyw/kicad-3d-models-in-freecad&quot;&gt;parametrically generate parts&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The scripting in FreeCAD can be used much like the PCB layout scripts in KiCAD to create this with circular symmetry, like &lt;a href=&quot;https://wiki.freecadweb.org/Scripted_Parts:_Ball_Bearing_-_Part_1&quot;&gt;ball bearings&lt;/a&gt; which are difficult and repetitive to do by hand.&lt;/p&gt;
&lt;h1 id=&quot;final-words&quot;&gt;Final words&lt;/h1&gt;
&lt;p&gt;There are lots of other pieces of desktop software I have used that have started shipping with Python API&#39;s to address the never ending demand from users to easily automate repeated tasks. The live process for making this blogpost in somewhat recursive fashion can be found here.&lt;/p&gt;
&lt;blockquote class=&quot;twitter-tweet&quot;&gt;
&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;
Started a new blog post around &lt;a href=&quot;https://twitter.com/hashtag/python?src=hash&amp;amp;ref_src=twsrc%5Etfw&quot;&gt;#python&lt;/a&gt; wrapping around a bunch of desktop applications to ease automation / extension. Live updates here as I collate material to flesh it out. &lt;a href=&quot;https://t.co/zz8b29kHcO&quot;&gt;pic.twitter.com/zz8b29kHcO&lt;/a&gt;
&lt;/p&gt;
— Tisham Dhar (&lt;span class=&quot;citation&quot;&gt;@whatnick&lt;/span&gt;) &lt;a href=&quot;https://twitter.com/whatnick/status/1312880481470349312?ref_src=twsrc%5Etfw&quot;&gt;October 4, 2020&lt;/a&gt;
&lt;/blockquote&gt;
&lt;script async src=&quot;https://platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;
&lt;p&gt;I have even made videos withs a proprietary one, I will live that here for anyone interested in my attempts at a voiceover.&lt;/p&gt;
&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/YnppaRLpLWc&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen&gt;
&lt;/iframe&gt;
</content><link rel='replies' type='application/atom+xml' href='http://whatnicklife.blogspot.com/feeds/2570676582312627632/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3220006345447041404/2570676582312627632' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3220006345447041404/posts/default/2570676582312627632'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3220006345447041404/posts/default/2570676582312627632'/><link rel='alternate' type='text/html' href='http://whatnicklife.blogspot.com/2020/10/desktop-software-apis-in-python-kicad.html' title='Desktop Software API&#39;s in Python (KiCAD, FreeCAD, Blender, QGIS)'/><author><name>Tisham Dhar</name><uri>http://www.blogger.com/profile/15154154153085427197</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img.youtube.com/vi/YnppaRLpLWc/default.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3220006345447041404.post-53285416367457152</id><published>2020-08-30T00:12:00.004-07:00</published><updated>2020-10-02T02:27:15.389-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="c++"/><category scheme="http://www.blogger.com/atom/ns#" term="MSVC"/><category scheme="http://www.blogger.com/atom/ns#" term="Open-Source"/><category scheme="http://www.blogger.com/atom/ns#" term="qgis"/><title type='text'>Compiling QGIS in MSVC in 2020</title><content type='html'>&lt;h1 id=&quot;compiling-qgis-on-windows-in-200x&quot;&gt;Compiling QGIS on Windows in 200x&lt;/h1&gt;
&lt;p&gt;I don&#39;t quite remember when I decided to help compile QGIS on Windows. It was somewhere between compiling GDAL with ECW support for Photoshop on Windows and getting carried into Direct3D and C# land with NASA WorldWind. It was sometime in the 2000&#39;s while still working at Apogee Imaging in Lobethal.&lt;/p&gt;
&lt;p&gt;At that point I was manually building a database of the footprints of satellite imagery that filled up a wall cabinet with CD&#39;s and DVD&#39;s. The technique was something like open up the image, go around edges and trace a polygon. This was days before mature boolean thresholding and reliable/easy raster-to-vector logic.&lt;/p&gt;
&lt;p&gt;I hopped on IRC on #qgis in Freenode and chatted with luminaries like timlinux, frankw and gsherman. Listened to the automated notifications from &lt;strong&gt;sigq&lt;/strong&gt;, the commits bot. Things were heating up and instead of a Linux cross-compile to windows using MingW, something native to windows say using MSyS+MingW instead of Cygwin was desired. A lot of GDAL and Qt worked in MingW, so presumably QGIS would too. So I set myself to put together an MSYS environment with all the third-party dependencies that could be used to happily build QGIS. Eventually I built a release in NSIS as well.&lt;/p&gt;
&lt;p&gt;My MSYS environment got packed in a zip and shared via FTP/HTTP on a VPS I had back then to the rest of the community. I earned myself a pin in the QGIS core contributor map in Adelaide. Something I am very proud of to this day. Eventually the MingW build got deprecated and native MSVC builds were supported. That&#39;s how contributions work, nothing lasts forever. In my IRC days, I helped on-board Nathan Woodrow to QGIS, who in turn I believe helped on-board Nyall Dawson. Nyall has surpassed us all in feature contributions and work on QGIS.&lt;/p&gt;
&lt;blockquote class=&quot;twitter-tweet&quot;&gt;
&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;
Getting started on QGIS on MSVC blog article. Trying to add some historical perspective on my involvement. Found this acknowledgement in the docs. Thanks to &lt;a href=&quot;https://twitter.com/timlinux?ref_src=twsrc%5Etfw&quot;&gt;&lt;span class=&quot;citation&quot;&gt;@timlinux&lt;/span&gt;&lt;/a&gt; . Back in the days of sharing mingw zip files via FTP. &lt;a href=&quot;https://t.co/NTkQgU5ibN&quot;&gt;pic.twitter.com/NTkQgU5ibN&lt;/a&gt;
&lt;/p&gt;
— Tisham Dhar (&lt;span class=&quot;citation&quot;&gt;@whatnick&lt;/span&gt;) &lt;a href=&quot;https://twitter.com/whatnick/status/1299858242311315456?ref_src=twsrc%5Etfw&quot;&gt;August 29, 2020&lt;/a&gt;
&lt;/blockquote&gt;
&lt;script async src=&quot;https://platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;
&lt;h1 id=&quot;fast-forward-to-2020-compiling-qgis-in-msvc&quot;&gt;Fast forward to 2020, compiling QGIS in MSVC&lt;/h1&gt;
&lt;p&gt;I am getting back into doing lots of Open-source work after long hiatus in private industry with &lt;a href=&quot;https://twitter.com/aerometrex&quot;&gt;Aerometrex&lt;/a&gt; and start-up land with &lt;a href=&quot;https://twitter.com/lorisystems&quot;&gt;Lorisystems&lt;/a&gt;. It is great fun working on mostly in the open at &lt;a href=&quot;https://twitter.com/GeoscienceAus&quot;&gt;Geoscience Australia&lt;/a&gt;. There is actually a recently archived opendatacube + qgis repository &lt;a href=&quot;https://github.com/opendatacube/datacube-qgis&quot;&gt;here&lt;/a&gt;. Seeing that repo and speaking to &lt;a href=&quot;https://twitter.com/madmanwoo&quot;&gt;Nathan&lt;/a&gt; and LinuxConfAu inspired me to have a go and getting back into actively working on the Qgis code base. It has sprawled out, with lots and lots of new features. The build system is still familiar via CMake and actually much easier now with MSVC. I cast around for a recent guide and found &lt;a href=&quot;https://www.shaeffer.co/compiling-qgis-on-windows/&quot;&gt;this&lt;/a&gt;. The guide mostly works, however I made some refinements.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ditched &lt;code&gt;bison&lt;/code&gt; and &lt;code&gt;flex&lt;/code&gt; via Cygwin to using the one available via Msys2. These can be found &lt;a href=&quot;https://packages.msys2.org/package/bison&quot;&gt;here&lt;/a&gt;. Not needing the while Cygwin system helps in keeping the windows build system light. Simply download the binaries and add them to the Osgeo4W binaries directory.&lt;/li&gt;
&lt;li&gt;Captured my &lt;a href=&quot;https://gist.github.com/whatnick/6008597bffa427a733b7ccf6ba0f8fca&quot;&gt;CMakeCache.txt&lt;/a&gt; to make it easier to reproduce and debug the build environment for others.&lt;/li&gt;
&lt;li&gt;Used &lt;a href=&quot;https://www.incredibuild.com/&quot;&gt;Incredibuild&lt;/a&gt; in demo mode to use a few NUC&#39;s I have lying around to speed up the build. Recording while building failed the first time and worked the next. The whole build from scratch still tooks around 35minutes overall.&lt;/li&gt;
&lt;/ul&gt;
&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/zTW5DmO06b0&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen&gt;
&lt;/iframe&gt;
&lt;p&gt;I am planning to throw some of my day to day DevOps skills towards the QGIS project and start helping again with Raster enhancements and windows release management. Perhaps getting Incredibuild in the hands of the windows maintainers will help tighten up the iteration cycle and make testing easier.&lt;/p&gt;
&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/R8wq6D_kEjA&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen&gt;
&lt;/iframe&gt;
&lt;p&gt;The twitter thread/ stream of consciousness edition of this is available as well.&lt;/p&gt;
&lt;blockquote class=&quot;twitter-tweet&quot;&gt;
&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;
Moving from babun to msys2 to get flex and bison required for compiling QGIS from source. &lt;a href=&quot;https://t.co/W866AOM9Kt&quot;&gt;https://t.co/W866AOM9Kt&lt;/a&gt; &lt;a href=&quot;https://t.co/fUmqpa9YHY&quot;&gt;pic.twitter.com/fUmqpa9YHY&lt;/a&gt;
&lt;/p&gt;
— Tisham Dhar (&lt;span class=&quot;citation&quot;&gt;@whatnick&lt;/span&gt;) &lt;a href=&quot;https://twitter.com/whatnick/status/1276482732621565952?ref_src=twsrc%5Etfw&quot;&gt;June 26, 2020&lt;/a&gt;
&lt;/blockquote&gt;
&lt;script async src=&quot;https://platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;
</content><link rel='replies' type='application/atom+xml' href='http://whatnicklife.blogspot.com/feeds/53285416367457152/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3220006345447041404/53285416367457152' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3220006345447041404/posts/default/53285416367457152'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3220006345447041404/posts/default/53285416367457152'/><link rel='alternate' type='text/html' href='http://whatnicklife.blogspot.com/2020/08/compiling-qgis-in-msvc-in-2020.html' title='Compiling QGIS in MSVC in 2020'/><author><name>Tisham Dhar</name><uri>http://www.blogger.com/profile/15154154153085427197</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img.youtube.com/vi/zTW5DmO06b0/default.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3220006345447041404.post-8558429505813908133</id><published>2020-07-22T00:12:00.006-07:00</published><updated>2020-08-02T04:29:35.741-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="AWS"/><category scheme="http://www.blogger.com/atom/ns#" term="Design patterns"/><category scheme="http://www.blogger.com/atom/ns#" term="DevOps"/><category scheme="http://www.blogger.com/atom/ns#" term="python"/><title type='text'>Microservices the hard way - folders in EC2 Instance</title><content type='html'>&lt;p&gt;For day to day work I wrangle containers in EKS these days. However when doing personal projects EKS is a luxury (baseline cost being $70 or so per month). So I decided to do microservice development for the rain radar project using no Docker, no Kubernetes but using:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;multiple venvs&lt;/li&gt;
&lt;li&gt;multiple service folders&lt;/li&gt;
&lt;li&gt;environments in .env files (secrets in plain text)&lt;/li&gt;
&lt;li&gt;web service start using &lt;span class=&quot;citation&quot;&gt;@reboot&lt;/span&gt; in Cron&lt;/li&gt;
&lt;li&gt;scheduled services using ... ya Cron&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The whole thing started with noble intentions to use lambda&#39;s all the way however I got stuck in using S3-SNS to trigger the lambda and decided to scan the S3 bucket using timestamps to find latest files to process. More on the pitfalls of that later.&lt;/p&gt;
&lt;p&gt;The major microservices handle are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Raw radar data preparation using custom hand crafted algorithm, being ported to Rust &lt;a href=&quot;https://github.com/whatnick/crop_circle&quot;&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Inserting prepared data to DynamoDB as a &lt;a href=&quot;https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/bp-indexes-general-sparse-indexes.html&quot;&gt;sparse array&lt;/a&gt; and serving this via Flask.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/pySTEPS/pysteps&quot;&gt;Nowcasting&lt;/a&gt; using the timeseries of sparse array of rain observations also serving results via Flask.&lt;/li&gt;
&lt;li&gt;Capturing rain events and nowcasts and creating text and gif to send to &lt;a href=&quot;https://python-twitter.readthedocs.io/en/latest/&quot;&gt;twitter&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each of these applications consumes the other to some extent and is sort of separated in responsibility. I decided to deploy them with basic a folder per application on the &lt;code&gt;/home/ubuntu&lt;/code&gt; directory, with a venv per folder.&lt;/p&gt;
&lt;p&gt;I had it like this for a while. Then I got tired for sshing into the box and git pulling in each folder. So I decided to write a fabfile per application which would do this for me and created deployment keys which would be used to pull the code to this folder. Then I got tired of running multiple fabfiles and decided to setup a polled process which run the fabfiles and git synced the code from a &lt;a href=&quot;https://support.atlassian.com/bitbucket-cloud/docs/schedule-pipelines/&quot;&gt;master pipeline&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Eventually I got around to bootstrapping the whole VM using &lt;a href=&quot;https://www.packer.io/&quot;&gt;Packer&lt;/a&gt; + &lt;a href=&quot;https://www.packer.io/docs/provisioners/ansible.html&quot;&gt;Ansible&lt;/a&gt; playbooks. The development work for it was done locally using &lt;a href=&quot;https://www.vagrantup.com/&quot;&gt;Vagrant&lt;/a&gt; with Hyper-V as the VM provide to test the same &lt;a href=&quot;https://www.vagrantup.com/docs/provisioning/ansible&quot;&gt;Ansible&lt;/a&gt; playbooks. I will follow up on this with a few characters on twitter.&lt;/p&gt;
&lt;blockquote class=&quot;twitter-tweet&quot;&gt;
&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;
Wrangling VM&#39;s with Packer, Vagrant and Ansible all at the same time. Helped me figure out issues in Ansible docs and divergence between bento ubuntu box and AWS AMI. One calls ntp ntpd, the other ntp.service. &lt;a href=&quot;https://t.co/tSbaPuKtVB&quot;&gt;pic.twitter.com/tSbaPuKtVB&lt;/a&gt;
&lt;/p&gt;
— Tisham Dhar (&lt;span class=&quot;citation&quot;&gt;@whatnick&lt;/span&gt;) &lt;a href=&quot;https://twitter.com/whatnick/status/1284412192255733765?ref_src=twsrc%5Etfw&quot;&gt;July 18, 2020&lt;/a&gt;
&lt;/blockquote&gt;
&lt;script async src=&quot;https://platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;
&lt;p&gt;Once the initial Packer AMI is established the choice is to either keep building this image or to move away from the whole VM based old-school stuff to a more modern/fun Kubernetes way.&lt;/p&gt;
</content><link rel='replies' type='application/atom+xml' href='http://whatnicklife.blogspot.com/feeds/8558429505813908133/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3220006345447041404/8558429505813908133' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3220006345447041404/posts/default/8558429505813908133'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3220006345447041404/posts/default/8558429505813908133'/><link rel='alternate' type='text/html' href='http://whatnicklife.blogspot.com/2020/07/microservices-hard-way-folders-in-ec2.html' title='Microservices the hard way - folders in EC2 Instance'/><author><name>Tisham Dhar</name><uri>http://www.blogger.com/profile/15154154153085427197</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3220006345447041404.post-9038146343419407232</id><published>2020-06-01T06:59:00.005-07:00</published><updated>2020-06-06T02:40:49.675-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="AWS"/><category scheme="http://www.blogger.com/atom/ns#" term="RDS"/><category scheme="http://www.blogger.com/atom/ns#" term="Replication"/><category scheme="http://www.blogger.com/atom/ns#" term="Workarounds"/><title type='text'>Replicating Databases in RDS</title><content type='html'>&lt;p&gt;One Sunday in 2018 I sat for a whole day in Art Caffe at the ground floor of Yaya Centre in Nairobi on the phone to Norman at AWS Support in Cape Town discussing DMS for MSSQL servers. After a whole day of screen sharing and being on call we decided what we were trying to do was no achievable, but AWS was working on it. The next day AWS sent me an NDA (since expired).&lt;/p&gt;
&lt;p&gt;Data replication from on-prem Database instances or between cloud database instances is an issue that comes up all the time. I have hands on experience doing this a couple of times now. This post summarizes my 3 or so attempts at doing this with different sources and targets and lessons learnt.&lt;/p&gt;
&lt;h2 id=&quot;mssql-to-mssql-using-aws-dms&quot;&gt;MSSQL to MSSQL using AWS DMS&lt;/h2&gt;
&lt;p&gt;At the start-up I was working at we adopted a pre-built mini ERP, it covered logistics workflows and finance / billing aspects. It was built in the 2000&#39;s in .NET Classic and ran on IIS and MSSQL server. Quickly the MSSQL became the single point of lack of scalability in the system. Since AWS does not natively support read-replicas for MSSQL RDS instances I looked at DMS to create these replicas. DMS did not quite work as expected and led to the conversation alluded to above with Norman. I ended up performing replication using &lt;a href=&quot;https://cloudbasic.net/&quot;&gt;CloudBasic&lt;/a&gt; as the SaaS provider for managing the Change Tracking and handling schema changes in the source tables and propagating them to the target replicas. The replication was fine for single replicas, but quickly bogged the source database down as I added more replicas.&lt;/p&gt;
&lt;p&gt;As aside the same database was also being replicated to a Redshift cluster for BI usage using tooling provided by &lt;a href=&quot;https://www.sisense.com/product/data-teams/&quot;&gt;Periscope Data&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As part of this excercise I came to appreciate the advantage to write-only / append-only schemas in improving no-lock replication performance (at the cost of storage), also the need for timestamp columns such as &lt;code&gt;update_time&lt;/code&gt; to perform incremental data transfer. I spent a lot of time reading the &lt;a href=&quot;https://eng.uber.com/schemaless-part-one-mysql-datastore/&quot;&gt;Schemaless articles&lt;/a&gt; by Uber Eng around building Schemaless DB&#39;s on top of RDBMS&#39;s like MySQL. I don&#39;t 100% agree with their design choices but it adds interesting perspective. The bottomline &lt;strong&gt;CRUD at scale is HARD&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&quot;rds-postgresql-to-postgresql-using-dms&quot;&gt;RDS PostgreSQL to PostgreSQL using DMS&lt;/h2&gt;
&lt;p&gt;Fast forward a year or so, I am now working at Geoscience Australia, with the &lt;a href=&quot;http://www.ga.gov.au/dea&quot;&gt;Digital Earth Australia&lt;/a&gt;. Everything runs on Kubernetes and is highly scalable. Single point of lack of scalability is again the database. A pattern seems to be emerging here. We were performing cluster migration in Kubernetes and I offered to investigate DMS again.&lt;/p&gt;
&lt;p&gt;In the MSSQL scenario there is a small prologue, I had previously migrated around 1million cells from a massive Google Sheet to the MSSQL database at the start of my tenure at the startup, by the time we hit scalability issues in the single instance MSSQL we were at 10million rows in the largest append-only table. The PostgreSQL migration of the &lt;a href=&quot;https://www.opendatacube.org/&quot;&gt;datacube tables&lt;/a&gt; featured 8-9 million rows in the largest table. However the database also has lots of indexes and uses PostGIS for some applications, particularly &lt;a href=&quot;https://github.com/opendatacube/datacube-explorer&quot;&gt;Datacube Explorer&lt;/a&gt;. DMS fell down in support for the Geometry columns, however I learnt a lot in setting up DMS using Terraform IAC and fine tuning for JSON Blob columns, which in &lt;a href=&quot;https://github.com/opendatacube/datacube-core/releases/tag/datacube-1.8.0&quot;&gt;Datacube design in 1.8.x&lt;/a&gt; series can be upto 2MB in size. DMS migrates standard columns separately from LOB columns.&lt;/p&gt;
&lt;p&gt;Ultimately DMS was not feasible for datacube DB migration to a new RDS instance. However I believe core datacube can be migrated next time I try with applications depending on Materialized views and PostGIS setup afresh on new DB. Also by the time I try again Amazon may have better PostGIS support. For the cluster migration we ended up using a &lt;a href=&quot;https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_RestoreFromSnapshot.html&quot;&gt;snaphot&lt;/a&gt; of the last DB.&lt;/p&gt;
&lt;h2 id=&quot;on-prem-postgresql-to-rds-postgresql&quot;&gt;On-prem PostgreSQL to RDS PostgreSQL&lt;/h2&gt;
&lt;p&gt;There is a Datacube PostgreSQL DB instance at the NCI which needs to be regularly replicated to RDS. It powers the &lt;a href=&quot;https://explorer.dea.ga.gov.au/ls5_fc_albers&quot;&gt;Explorer Datacube&lt;/a&gt; application. However DB migration from one server without direct disk access to RDS where we also don&#39;t have disk access using &lt;a href=&quot;https://www.postgresql.org/docs/11/app-pgrestore.html&quot;&gt;pg_dump / pg_restore&lt;/a&gt; for a DB with largest tables being around 22 million rows and the compressed dump being around 11GB is a long running task. Ideally we sort something out that is &lt;a href=&quot;https://github.com/opendatacube/datacube-core/pull/951&quot;&gt;incremental&lt;/a&gt; using &lt;code&gt;update_time&lt;/code&gt; generated using triggers. The options explored so far are :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Using an &lt;a href=&quot;https://github.com/GeoscienceAustralia/dea-airflow/blob/develop/dags/k8s_db_sync.py&quot;&gt;Airflow DAG&lt;/a&gt; with Kubernetes Executors wrapped around pg_dump/restore with some application specific details.&lt;/li&gt;
&lt;li&gt;Using &lt;a href=&quot;https://aws.amazon.com/about-aws/whats-new/2019/06/amazon-aurora-with-postgresql-compatibility-supports-data-import-from-amazon-s3/&quot;&gt;COPY from S3&lt;/a&gt; support for Aurora PostgreSQL, CSV&#39;s restored using the COPY command are generated incrementally.&lt;/li&gt;
&lt;li&gt;Using PostgreSQL publish / subscribe and &lt;a href=&quot;https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/CHAP_PostgreSQL.html#PostgreSQL.Concepts.General.FeatureSupport.LogicalReplication&quot;&gt;Logical Replication&lt;/a&gt;. Networking over the internet to maintain connectivity securely to the on-prem instance via &lt;a href=&quot;https://www.postgresql.org/docs/11/ssh-tunnels.html&quot;&gt;SSH Tunnels&lt;/a&gt; and to the RDS instance via &lt;a href=&quot;https://kubernetes.io/docs/tasks/access-application-cluster/port-forward-access-application-cluster/&quot;&gt;EKS port-forwarding&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
</content><link rel='replies' type='application/atom+xml' href='http://whatnicklife.blogspot.com/feeds/9038146343419407232/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3220006345447041404/9038146343419407232' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3220006345447041404/posts/default/9038146343419407232'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3220006345447041404/posts/default/9038146343419407232'/><link rel='alternate' type='text/html' href='http://whatnicklife.blogspot.com/2020/06/replicating-databases-in-rds.html' title='Replicating Databases in RDS'/><author><name>Tisham Dhar</name><uri>http://www.blogger.com/profile/15154154153085427197</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3220006345447041404.post-8580824782511599889</id><published>2020-05-07T15:11:00.002-07:00</published><updated>2020-05-09T00:39:47.381-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Analog Devices"/><category scheme="http://www.blogger.com/atom/ns#" term="electronics"/><category scheme="http://www.blogger.com/atom/ns#" term="energy monitor"/><title type='text'>ADE7816 Energy Monitor</title><content type='html'>&lt;p&gt;I have been meaning to try out the &lt;a href=&quot;https://www.analog.com/en/products/ade7816.html&quot;&gt;ADE7816&lt;/a&gt; Single-phase 6 current channels energy monitor for a while. However time has been lacking for the last couple of years. Finally I have a working version with successful board bring-up and a semi-working &lt;a href=&quot;https://github.com/whatnick/ADE7816_Micropython&quot;&gt;Micropython driver&lt;/a&gt;, with an &lt;a href=&quot;https://github.com/whatnick/ADE7816_Arduino&quot;&gt;Arduino driver&lt;/a&gt; in the works.&lt;/p&gt;
&lt;h2 id=&quot;pcb-design&quot;&gt;PCB Design&lt;/h2&gt;
&lt;p&gt;The PCB design process for this was not easy mostly due to a footprint choice mistake on my part. I had placed the 5x5mm QFN part instead of the 6x6mm QFN part in KiCAD. This made the DRC fail everywhere in standard settings. However it ended up being a collaboration opportunity with Greg Davill who loves to practice and photograph bodging stuff. So I now have a work of art at hand instead of a non-functional board.&lt;/p&gt;
&lt;blockquote class=&quot;twitter-tweet&quot;&gt;
&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;
Practising my bodge skills&lt;br&gt;&lt;br&gt;This is a QFN where the footprint on the PCB was incorrect.&lt;br&gt;&lt;br&gt;Just a couple more bodge wires to add. &lt;a href=&quot;https://t.co/AmZ1CsWqC3&quot;&gt;pic.twitter.com/AmZ1CsWqC3&lt;/a&gt;
&lt;/p&gt;
— Greg (&lt;span class=&quot;citation&quot;&gt;@GregDavill&lt;/span&gt;) &lt;a href=&quot;https://twitter.com/GregDavill/status/1252870227584356352?ref_src=twsrc%5Etfw&quot;&gt;April 22, 2020&lt;/a&gt;
&lt;/blockquote&gt;
&lt;script async src=&quot;https://platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;
&lt;p&gt;I am even debating whether to place the rest of the parts and possibly take away from the dead-bug awesomeness. Next time need to order parts in advance and make sure I do &lt;a href=&quot;https://forum.kicad.info/t/how-to-print-a-pcb-from-pcbnew-in-kicad-5-0/11924/5&quot;&gt;1-1 prints&lt;/a&gt; to verify footprints before pulling the trigger on PCB&#39;s.&lt;/p&gt;
&lt;h2 id=&quot;energy-montor-details&quot;&gt;Energy Montor Details&lt;/h2&gt;
&lt;p&gt;Now to more about the energy monitor. This ASIC features 3 single-ended and 3 differential current inputs and a single-phase voltage input, all in very compact 40-pin &lt;strong&gt;6x6mm&lt;/strong&gt; QFN package. In fact the PCB is large on purpose to accomodate ease of use with stereo-jack type current clamps. The main usage would be in standard households where there are typically 3-4 lighting circuits, 1-2 socket circuits and dedicated Air Conditioning circuit. A single energy monitor could be built to monitor all channels using a single-ASIC and leave out fancy NILM stuff from worrying about the lights. The socket circuits could have anything plugged into them and can potentially have point-of-load monitoring instead of breaker board based monitoring. All this translates to more data being generated for IoT platforms and some sensible firmware work needs to be done to handle that.&lt;/p&gt;
&lt;h2 id=&quot;ade7816-driver-development&quot;&gt;ADE7816 Driver Development&lt;/h2&gt;
&lt;p&gt;This is still work in progress. I have done some initial exploration to find prior art. Nothing exists yet from Arduino however there is some register lists from a &lt;a href=&quot;https://github.com/tadakado/smart-meter/tree/master/Soft&quot;&gt;Javascript driver&lt;/a&gt; written for the now defunct Intel Edison.&lt;/p&gt;
&lt;p&gt;Intel never quite had the maker market pinned right to market that board, it makes me sad to think of all the engineering ours sunk into a now defunct platform. Open-source software / hardware helps us salvage some of that. I also sped up the register listing by copy-pasting the ubquitous table from the ADE7816 datasheet and dropping it into a Jupyter notebook to parse all the registers, not as fancy as the Pdf parser I had built before, but much more reliable.&lt;/p&gt;
&lt;blockquote class=&quot;twitter-tweet&quot;&gt;
&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;
My &lt;a href=&quot;https://twitter.com/adafruit?ref_src=twsrc%5Etfw&quot;&gt;&lt;span class=&quot;citation&quot;&gt;@adafruit&lt;/span&gt;&lt;/a&gt; &lt;a href=&quot;https://twitter.com/hashtag/ESP32?src=hash&amp;amp;ref_src=twsrc%5Etfw&quot;&gt;#ESP32&lt;/a&gt; + Logic Analyzer test rig. Due in the background is just to keep cables tidy. The ESP32 runs micropython so that I can iterate on SPI modes quickly and use the excellent struct functions to pack/unpack bytes. &lt;a href=&quot;https://t.co/0pQgAO1Cgl&quot;&gt;https://t.co/0pQgAO1Cgl&lt;/a&gt; &lt;a href=&quot;https://t.co/R2imRukrpT&quot;&gt;pic.twitter.com/R2imRukrpT&lt;/a&gt;
&lt;/p&gt;
— Tisham Dhar (&lt;span class=&quot;citation&quot;&gt;@whatnick&lt;/span&gt;) &lt;a href=&quot;https://twitter.com/whatnick/status/1250199028828008448?ref_src=twsrc%5Etfw&quot;&gt;April 14, 2020&lt;/a&gt;
&lt;/blockquote&gt;
&lt;script async src=&quot;https://platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;
&lt;p&gt;My driver development follwed the now tried and tested Micropython + Jupyter Notebook + Logic Analyzer path. I used an ESP32 feather as host processor with standard micropython loaded and probed the SPI bus with read-write packets for known registers until the protocol gave in and started responding with some values. The ASIC is super versatile in supported protocols - I2C Slave, SPI Master and SPI Slave modes are all viable. So developing a fully functional driver supporting all the possible modes will take a while. The initial work so far is on the SPI slave mode since all my other work in DIN rail and Featherwing formats is linked to the SPI bus, however the I2C mode can be really interesting for host-processors with fewer pins and flaky SPI support (while having solid I2C support - like the Onion).&lt;/p&gt;
&lt;p&gt;If anyone is interested in driver development I am happy to send you a board or you can get one yourself from &lt;a href=&quot;https://oshpark.com/shared_projects/oovHySXk&quot;&gt;Oshpark&lt;/a&gt;, &lt;a href=&quot;https://aisler.net/whatnick/playground/ade7816-breakout&quot;&gt;Aisler&lt;/a&gt; or &lt;a href=&quot;https://www.pcbway.com/project/shareproject/Breakout_Board_for_ADE7816_6_Channel_Energy_Monitor_ASIC.html&quot;&gt;PCBWay&lt;/a&gt;. Once the drivers mature I will list it for a wider audience on Tindie.&lt;/p&gt;
</content><link rel='replies' type='application/atom+xml' href='http://whatnicklife.blogspot.com/feeds/8580824782511599889/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3220006345447041404/8580824782511599889' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3220006345447041404/posts/default/8580824782511599889'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3220006345447041404/posts/default/8580824782511599889'/><link rel='alternate' type='text/html' href='http://whatnicklife.blogspot.com/2020/05/ade7816-energy-monitor.html' title='ADE7816 Energy Monitor'/><author><name>Tisham Dhar</name><uri>http://www.blogger.com/profile/15154154153085427197</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3220006345447041404.post-1021191518707358530</id><published>2020-04-04T00:12:00.006-07:00</published><updated>2020-04-04T06:02:14.704-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="AWS"/><category scheme="http://www.blogger.com/atom/ns#" term="Design patterns"/><category scheme="http://www.blogger.com/atom/ns#" term="python"/><title type='text'>Distributed Locking from Python while running on AWS</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
In the day and age of eventually consistent web-scale applications the concept of locking may seem very archaic. However in some instances attempting to obtain a lock and failing to do so within a limited window can prevent dogpile effects for expensive server side operations or prevent over-write of already executing long running tasks such as ETL processes.&lt;br /&gt;
I have used 3-basic approaches to create distributed locks on AWS with the help of built-in services and accessed them via Python which is what I build most of my sofware in.&lt;br /&gt;
&lt;h2 id=&quot;file-locks-upgraded-to-efs&quot;&gt;
File locks upgraded to EFS&lt;/h2&gt;
File based locks in UNIX file-systems are very common. They are typically created using the flock command, avalaible in Python under os-specific &lt;a href=&quot;https://docs.python.org/3/library/fcntl.html#fcntl.flock&quot;&gt;flock&lt;/a&gt; API. Also checkout the platform independent &lt;a href=&quot;https://pypi.org/project/filelock/&quot;&gt;filelock&lt;/a&gt;. This is well and good for a VM or single application instance. For distributed locking, we will need &lt;a href=&quot;https://aws.amazon.com/efs/&quot;&gt;EFS&lt;/a&gt; as the filesystem on which these locks are held, Linux-Kernel and NFS will use &lt;a href=&quot;https://github.com/torvalds/linux/commit/55725513b5ef9d462aa3e18527658a0362aaae83&quot;&gt;byte-range locks&lt;/a&gt; to help simulate locally attached file system type locks. However if the client loses connectivity the NFS lock-state cannot be determined, better run that EFS with enough replicas to ensure connectivity.&lt;br /&gt;
File locking this way is very useful if we are using EFS for holding large file and processing data anyway.&lt;br /&gt;
&lt;h2 id=&quot;redis-locks-upgraded-to-elasticache&quot;&gt;
Redis locks upgraded to ElastiCache&lt;/h2&gt;
Another popular pattern for holding locks in Python is using Redis. This can be upgraded in the cloud-hosted scenario to &lt;a href=&quot;https://aws.amazon.com/elasticache/redis/&quot;&gt;Redis-Elasticache&lt;/a&gt;, This pairs well with the &lt;a href=&quot;https://pypi.org/project/python-redis-lock/&quot;&gt;redis-lock&lt;/a&gt; library.&lt;br /&gt;
Using redis requires a bit of setup and is subject to similar network vagaries and EFS. It makes sense when using Redis already as an in-memory cache for accelration or as a broker/results mechanism for &lt;a href=&quot;https://docs.celeryproject.org/en/latest/getting-started/brokers/redis.html&quot;&gt;Celery&lt;/a&gt;. Having data encrypted at rest and transit may require running an &lt;a href=&quot;https://www.stunnel.org/&quot;&gt;Stunnel Proxy&lt;/a&gt;.&lt;br /&gt;
&lt;h2 id=&quot;an-aws-only-method---dynamodb&quot;&gt;
An AWS only Method - DynamoDB&lt;/h2&gt;
A while ago AWS published &lt;a href=&quot;https://aws.amazon.com/blogs/database/building-distributed-locks-with-the-dynamodb-lock-client/&quot;&gt;an article&lt;/a&gt; for creating and holding locks on DynamoDB using a Java lock client. This client creates the lock and holds it live using heart-beats while the relevant code section executes. Since then it has been ported to &lt;a href=&quot;https://pypi.org/project/python-dynamodb-lock/&quot;&gt;Python&lt;/a&gt; and I am maintaining my own &lt;a href=&quot;https://github.com/whatnick/python_dynamodb_lock&quot;&gt;fork&lt;/a&gt;.&lt;br /&gt;
It works well and helps scale-out singleton processes run as Lambdas to multiple lambdas in a serverless fashion, with a given lambda quickly skipping over a task another lambda is holding a lock on. I have also used it on EC2 based stuff where I was already using DynamoDB for other purposes. This is possibly the easiest and cheapest method for achieving distributed locking. Locally testing this technique is also quite easy using &lt;a href=&quot;https://hub.docker.com/r/amazon/dynamodb-local/&quot;&gt;local-dynamodb&lt;/a&gt; in a docker container.&lt;br /&gt;
Feel free to ping me other distributed locking solutions that work well on AWS and I will try them out.&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://whatnicklife.blogspot.com/feeds/1021191518707358530/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3220006345447041404/1021191518707358530' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3220006345447041404/posts/default/1021191518707358530'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3220006345447041404/posts/default/1021191518707358530'/><link rel='alternate' type='text/html' href='http://whatnicklife.blogspot.com/2020/04/distributed-locking-from-python-while.html' title='Distributed Locking from Python while running on AWS'/><author><name>Tisham Dhar</name><uri>http://www.blogger.com/profile/15154154153085427197</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3220006345447041404.post-5946366589254569308</id><published>2020-01-24T05:48:00.001-08:00</published><updated>2020-01-24T06:35:58.289-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ecp5"/><category scheme="http://www.blogger.com/atom/ns#" term="electronics"/><category scheme="http://www.blogger.com/atom/ns#" term="fpga"/><category scheme="http://www.blogger.com/atom/ns#" term="open hardware"/><title type='text'>Testing the OrangeCrab r0.1</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
After hassling &lt;a href=&quot;https://twitter.com/GregDavill&quot;&gt;Greg Davill&lt;/a&gt; for a while on twitter and admiring his OrangeCrab hardware I managed to catch up with him in person in Adelaide. I have been away in Nairobi till October last year, then I spent a brief few days in Adelaide before coming over to Canberra to take up a position in Geoscience Australia. The new gig is much less time commitment than the start-up world and hopefully will allow more time for blogging and board bring-ups like this one.&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHtvrvNVcFg-ZvLpiSwNMcmTSTlHfzBRV-SSi87hoCt7ry1AhRbXUaCpuDgj-dc8Ml7K-ouPznJAxKEM0Q0zXTLHVjfNtHTOqSbyXCEKZDYDamZgLy8Qo3U7wdYeLzz3lYTSsXGxAMVjA/s1600/PANO_20191015_182101.vr.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;698&quot; data-original-width=&quot;1600&quot; height=&quot;173&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHtvrvNVcFg-ZvLpiSwNMcmTSTlHfzBRV-SSi87hoCt7ry1AhRbXUaCpuDgj-dc8Ml7K-ouPznJAxKEM0Q0zXTLHVjfNtHTOqSbyXCEKZDYDamZgLy8Qo3U7wdYeLzz3lYTSsXGxAMVjA/s400/PANO_20191015_182101.vr.jpg&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
I caught up with Greg at a Japanese restaurant in Rundle mall and was treated to his now trademark led cube and led icosahedron. They are insanely detailed pieces of work and deserve staring at. However I am most grateful for the care package he left me, an OrangeCrab v0.1. This is an ECP5 board in feather form factor with an ADC built in to respect the Analog In pins on the feather. My aim for this board is to host some energy monitoring code on the FPGA with a fast 4mbps or so ADC and perform power/energy calculation on some parts of LUT&#39;s/DSP and have a &lt;a href=&quot;https://github.com/riscv/riscv-cores-list&quot;&gt;softcpu&lt;/a&gt; push data out.&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgmWDzWZ_ImBjAsDSHnUdkRS_q-inNApnz8_mUXO6O7gG5tRQCPl7LCvubKfq5wgOaDt050vBGhfw2cMSeQvFnIpuk9ZxHdPIhO8GaxtxH9fjor9KYVkQQcQGvasGccM4GP7ulygBZIaA0/s1600/IMG_20191205_203704.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;1600&quot; data-original-width=&quot;1200&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgmWDzWZ_ImBjAsDSHnUdkRS_q-inNApnz8_mUXO6O7gG5tRQCPl7LCvubKfq5wgOaDt050vBGhfw2cMSeQvFnIpuk9ZxHdPIhO8GaxtxH9fjor9KYVkQQcQGvasGccM4GP7ulygBZIaA0/s320/IMG_20191205_203704.jpg&quot; width=&quot;240&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
Greg also left me a home-made FTDI based board to use a JTAG programmer. The whole setup requires 3 USB cables:&lt;br /&gt;
&lt;br /&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;&amp;nbsp;To plugin and power the FPGA board (eventually it should be alos programmable via this port)&amp;nbsp;&lt;/li&gt;
&lt;li&gt;To attach a USB-Serial converter and watch the console when the gateware comes up&amp;nbsp;&lt;/li&gt;
&lt;li&gt;To program the board over JTAG using an FTDI chip&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;br /&gt;
Getting firmware compiled these days is getting easier, but Greg had done his initial testing with &lt;a href=&quot;https://ycnrg.org/lattice-diamond-on-ubuntu-16-04/&quot;&gt;Lattice Diamond&lt;/a&gt;. I managed to installed it in WSL and promptly ran into a tonne of issues. The weirdest being close coupling to bash, Ubuntu actually uses &lt;a href=&quot;https://askubuntu.com/questions/976485/what-is-the-point-of-sh-being-linked-to-dash&quot;&gt;dash&lt;/a&gt; as its default shell. You can get a Diamond &lt;a href=&quot;http://www.latticesemi.com/Support/Licensing/&quot;&gt;licence&lt;/a&gt; and help support integration of diamond in &lt;a href=&quot;https://github.com/timvideos/litex-buildenv&quot;&gt;litex-buildenv&lt;/a&gt;.&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQScjLeWw8mV3m6PJMrGpi11_qhyBSNEIPvblvqwDS2Lvn3-6T5L5vpGEosuy2_-bFsNaaFHmysFAR_mrsrl2u5UjZH85aTxjLo-0FLa-Roz0In1xvXcGrUYe5XtUvqjgs0xAZ0E0h_94/s1600/RAM_Test_pass.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;834&quot; data-original-width=&quot;1600&quot; height=&quot;166&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQScjLeWw8mV3m6PJMrGpi11_qhyBSNEIPvblvqwDS2Lvn3-6T5L5vpGEosuy2_-bFsNaaFHmysFAR_mrsrl2u5UjZH85aTxjLo-0FLa-Roz0In1xvXcGrUYe5XtUvqjgs0xAZ0E0h_94/s320/RAM_Test_pass.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
I was about to give up then Greg got it working with the opensource toolchain and [NextPNR-ECP5&lt;a href=&quot;https://github.com/YosysHQ/nextpnr/tree/master/ecp5&quot;&gt;&lt;/a&gt;. I had by then setup litex-buildenv to support the orangecrab. So getting some gateware on was relatively easy. Then I got stuck on &lt;a href=&quot;https://github.com/enjoy-digital/litedram/issues/103&quot;&gt;RAM timing bug&lt;/a&gt; in Litex till a few hours ago when I tested out some &lt;a href=&quot;https://gist.github.com/gregdavill/e7644319dcc3b8015758171067d37b98&quot;&gt;new gateware&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Also Checkout out Greg&#39;s &lt;a href=&quot;https://github.com/gregdavill/foboot/tree/OrangeCrab-ECP5&quot;&gt;foboot fork&lt;/a&gt; and help make programming over the USB possible and reduce 1 USB cable. More work on this including getting &lt;a href=&quot;https://github.com/antonblanchard/microwatt&quot;&gt;MicroWatt&lt;/a&gt; running coming soon.&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://whatnicklife.blogspot.com/feeds/5946366589254569308/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3220006345447041404/5946366589254569308' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3220006345447041404/posts/default/5946366589254569308'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3220006345447041404/posts/default/5946366589254569308'/><link rel='alternate' type='text/html' href='http://whatnicklife.blogspot.com/2020/01/testing-orangecrab-r01.html' title='Testing the OrangeCrab r0.1'/><author><name>Tisham Dhar</name><uri>http://www.blogger.com/profile/15154154153085427197</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHtvrvNVcFg-ZvLpiSwNMcmTSTlHfzBRV-SSi87hoCt7ry1AhRbXUaCpuDgj-dc8Ml7K-ouPznJAxKEM0Q0zXTLHVjfNtHTOqSbyXCEKZDYDamZgLy8Qo3U7wdYeLzz3lYTSsXGxAMVjA/s72-c/PANO_20191015_182101.vr.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3220006345447041404.post-6499711979795037696</id><published>2019-10-06T06:43:00.000-07:00</published><updated>2019-10-06T06:43:29.367-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="beer"/><category scheme="http://www.blogger.com/atom/ns#" term="golf"/><category scheme="http://www.blogger.com/atom/ns#" term="kenya"/><category scheme="http://www.blogger.com/atom/ns#" term="start-ups"/><category scheme="http://www.blogger.com/atom/ns#" term="travel"/><category scheme="http://www.blogger.com/atom/ns#" term="weather"/><title type='text'>Around Kenya in 4 days and a year ( part 2)</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;The New Year adventure continued past the sad mercury laden mines of Migori to the Tanzania border , Isebania in particular. We met up with professor &lt;a href=&quot;https://www.linkedin.com/in/sangaimohochi/&quot;&gt;Sangai Mohochi&lt;/a&gt;&amp;nbsp;and had a brief gander into Tanzania ( Serere) for a beer. Later we had some&amp;nbsp;&lt;span style=&quot;background-color: #f8f9fa; color: #222222;&quot;&gt;Orokore Beer made from millet, we sat around a car tyre sipping still fermenting beer from straws.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiBBPkforLahyphenhyphenezAH13LkmXA9LmkUBJM93lRPUOmCnoeLBGQFkGlbCj5t2yygGIiC1DA88rXIwRnvt0-jlqjK-Vj7955EtXYiU1m9a_lUx0ypywaB02_cpTG4u8d6EF7Zxdr7dtrw6zD04/s1600/IMG_20181230_131006.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;1600&quot; data-original-width=&quot;1200&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiBBPkforLahyphenhyphenezAH13LkmXA9LmkUBJM93lRPUOmCnoeLBGQFkGlbCj5t2yygGIiC1DA88rXIwRnvt0-jlqjK-Vj7955EtXYiU1m9a_lUx0ypywaB02_cpTG4u8d6EF7Zxdr7dtrw6zD04/s320/IMG_20181230_131006.jpg&quot; width=&quot;240&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
We took our leave from the professor and had a long drive out to Rusinga island. A beautiful place without much of the tourist trappings lakeside places have. The Suba culture is being revived with &lt;a href=&quot;https://en.wikipedia.org/wiki/Rusinga_(Cultural)_Festival&quot;&gt;festivals&lt;/a&gt;. We woke up early and did a trip around Rusinga Island and visited &lt;a href=&quot;https://kisumucitycouncil.wordpress.com/2013/01/02/kisumus-heritagetom-mboya-mausoleum/&quot;&gt;Tom Mboya&#39;s Mausoleum&lt;/a&gt;. One of my high school&#39;s illustrious alumni.&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOPjZXNojgf84lr9x1Hb5hAt37je-nfhd9qVqCz9plvx-VjZG-m86QNeVc3hdnHa8QZFlXIrFXS0nKOSNlWroGa7ooC6HxAHU8Bs-2E22xgxBx1hgbVxn8k4YrB9qDfiqkg-vn6GqSd2w/s1600/PANO_20181231_064431.vr.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;546&quot; data-original-width=&quot;1600&quot; height=&quot;109&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOPjZXNojgf84lr9x1Hb5hAt37je-nfhd9qVqCz9plvx-VjZG-m86QNeVc3hdnHa8QZFlXIrFXS0nKOSNlWroGa7ooC6HxAHU8Bs-2E22xgxBx1hgbVxn8k4YrB9qDfiqkg-vn6GqSd2w/s320/PANO_20181231_064431.vr.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjeeO0oSO1TBjRRGHJAjP_X7ZJN8iUewKeMnA0uNKQkrFjvFtFUem6kLTxBvZhe0bevOvbmuv9EhOBlaxSiRJJQRRfkeoZI_RmuJnaNrMGbbnRDSAQs6uuQyqDjfZwe3A1uX5l4g7h1IYw/s1600/IMG_20181231_094230.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;1200&quot; data-original-width=&quot;1600&quot; height=&quot;240&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjeeO0oSO1TBjRRGHJAjP_X7ZJN8iUewKeMnA0uNKQkrFjvFtFUem6kLTxBvZhe0bevOvbmuv9EhOBlaxSiRJJQRRfkeoZI_RmuJnaNrMGbbnRDSAQs6uuQyqDjfZwe3A1uX5l4g7h1IYw/s320/IMG_20181231_094230.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
After another long day of driving and some fiddling with charging phones directly from a car battery ( another story on how many engineers does it take to charge a phone), we ended up in &lt;a href=&quot;http://www.naiberi.com/&quot;&gt;Naiberi River Campsite&lt;/a&gt;. It is more like a glamping spot and ideal for a quiet New Year&#39;s celebration around a fire in the main hall.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5jfWVrty6gv4I7Pbjo4DNckgKP7eDuzE-beA8fmOG_RSOK002FRNM_AKnCZlzQO7BOlIA2X8Nhw0aOLXIivBx3dV4iefymWaPuVxxPimnrmw3U9aWiI86r-YHuBSIrsHNIPifCdnpvLA/s1600/PANO_20190101_082453.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;800&quot; data-original-width=&quot;1600&quot; height=&quot;160&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5jfWVrty6gv4I7Pbjo4DNckgKP7eDuzE-beA8fmOG_RSOK002FRNM_AKnCZlzQO7BOlIA2X8Nhw0aOLXIivBx3dV4iefymWaPuVxxPimnrmw3U9aWiI86r-YHuBSIrsHNIPifCdnpvLA/s320/PANO_20190101_082453.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhvFEL_xXShanVIK_qP9_O32w7s3EkkxmJju0kFzIBTkBYzW0SZQVL_zGbGQvZg2vqvVdbWrp2TYf72qAetNFCqr94fkzjatG7t3yrrgWG-Zt8JzkpoJzZ8RWx2waRvYo1QFzUW8m5Uj7E/s1600/IMG_20190101_154526.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;1200&quot; data-original-width=&quot;1600&quot; height=&quot;240&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhvFEL_xXShanVIK_qP9_O32w7s3EkkxmJju0kFzIBTkBYzW0SZQVL_zGbGQvZg2vqvVdbWrp2TYf72qAetNFCqr94fkzjatG7t3yrrgWG-Zt8JzkpoJzZ8RWx2waRvYo1QFzUW8m5Uj7E/s320/IMG_20190101_154526.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
A late lunch/early dinner at Rift Valley Lodge Golf Club. We went for a post dinner walk on the greens and ran into herds of zebras and antelopes. No wonder this golf club is classed as one of the best in the Africa. All the excitement was followed by an uneventful drive back to Nairobi.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiuDahZykfvQrIrf5jpmcelEFRTi3mPMS6gU-gslligrtHsmDQfLIei6vPdFW0yK0WaIqGi0hpXsGeAmq6BA2PiOOHY-hYdbwoSlMUmJvFsReGY_YmBAb53Ov3MUmr4klu7tVN_9CxEfGM/s1600/IMG_20190101_185322.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;1200&quot; data-original-width=&quot;1600&quot; height=&quot;240&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiuDahZykfvQrIrf5jpmcelEFRTi3mPMS6gU-gslligrtHsmDQfLIei6vPdFW0yK0WaIqGi0hpXsGeAmq6BA2PiOOHY-hYdbwoSlMUmJvFsReGY_YmBAb53Ov3MUmr4klu7tVN_9CxEfGM/s320/IMG_20190101_185322.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
We arrived tired but energized the beauty and possibilities in Kenya. The roads need to be built, electricity needs to be channeled to houses, there is a lot to do. We look forward to hanging around and getting it done. Eric is heading back to his PhD at &lt;a href=&quot;https://www.seas.harvard.edu/directory/mibuari&quot;&gt;Harvard&lt;/a&gt;, Gichini will be doing something about the weather prediction and I have helped put &lt;a href=&quot;https://www.lorisystems.com/&quot;&gt;Lori Systems&lt;/a&gt; on a solid technical footing and change the Logistics landscape.&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://whatnicklife.blogspot.com/feeds/6499711979795037696/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3220006345447041404/6499711979795037696' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3220006345447041404/posts/default/6499711979795037696'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3220006345447041404/posts/default/6499711979795037696'/><link rel='alternate' type='text/html' href='http://whatnicklife.blogspot.com/2019/10/around-kenya-in-4-days-and-year-part-2.html' title='Around Kenya in 4 days and a year ( part 2)'/><author><name>Tisham Dhar</name><uri>http://www.blogger.com/profile/15154154153085427197</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiBBPkforLahyphenhyphenezAH13LkmXA9LmkUBJM93lRPUOmCnoeLBGQFkGlbCj5t2yygGIiC1DA88rXIwRnvt0-jlqjK-Vj7955EtXYiU1m9a_lUx0ypywaB02_cpTG4u8d6EF7Zxdr7dtrw6zD04/s72-c/IMG_20181230_131006.jpg" height="72" width="72"/><thr:total>0</thr:total><georss:featurename>Nairobi, Kenya</georss:featurename><georss:point>-1.2920659 36.821946199999957</georss:point><georss:box>-1.5460584000000002 36.499222699999955 -1.0380734 37.144669699999959</georss:box></entry><entry><id>tag:blogger.com,1999:blog-3220006345447041404.post-2164081328991902443</id><published>2019-08-14T14:20:00.003-07:00</published><updated>2019-08-15T18:54:00.722-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="javascript"/><category scheme="http://www.blogger.com/atom/ns#" term="open source"/><category scheme="http://www.blogger.com/atom/ns#" term="python"/><title type='text'>Open-source Sustainability (The tale of 2 package managers)</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
Last weekend I had the priviledge to attend the 10th PyconAU and listen to some amazing speakers. I went with my &lt;strong&gt;I will write markdown on the fly and make a blog-post at the end of the day&lt;/strong&gt; mindset. Even though I did write a lot of markdown on the fly, I haven&#39;t gathered the courage to push these unedited notes into a public post. Excellent examples of live-blogging from conferences &lt;a href=&quot;https://jmckew.com/2019/08/07/pycon-au-2019-sunday-in-summary/&quot;&gt;here&lt;/a&gt;.&lt;br /&gt;
What did happen was that the niggling doubts I had around how open-source works in the real world outside of just the code crystallized. This was as a result of 2 very good talks , one about how the &lt;a href=&quot;https://2019.pycon-au.org/talks/building-a-sustainable-python-package-index&quot;&gt;PyPi project works&lt;/a&gt; and another around &lt;a href=&quot;https://2019.pycon-au.org/talks/vicky&quot;&gt;Open-source sustainability beyond money&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
For the last year I have been writing and reviewing a lot of React Frontend, Python backend (Flask/Django) and Notebooks code. Both frameworks are super easy to buy batteries for where the included ones are running out of juice. Simply via &lt;em&gt;pip install&lt;/em&gt; and &lt;em&gt;npm install&lt;/em&gt; you can climb onto the shoulders of giants who are library maintainers and the life-blood of lean start-ups everywhere. However the &lt;a href=&quot;https://techcrunch.com/2018/06/23/open-source-sustainability/&quot;&gt;maintainer burnout&lt;/a&gt; is a thing and start-ups when building their stack should be highly cognizant of this. Package repository burnout is also a thing. In my time in the software industry I have seen Maven &lt;a href=&quot;https://maven.apache.org/repository/guide-central-repository-upload.html&quot;&gt;repositories disappear&lt;/a&gt;. More recently NPM go through an identity crisis and &lt;a href=&quot;https://www.techrepublic.com/article/why-its-finally-time-for-developers-to-address-the-chaos-of-node-js-and-npm/&quot;&gt;the left-pad incident&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
The PyPi talk gave me great background on a tool I use every single-hour without too much thought. It takes some dedicated volunteers to keep the dream alive. Who according to &lt;a href=&quot;https://dustingram.com/&quot;&gt;Dustin Ingram&lt;/a&gt; are :&lt;br /&gt;
&lt;br /&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;Unemployed and bored and poor (but super talented)&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Paid for by their employer (thanks employers who support FOSS)&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Not getting enough sleep (or in my case time with the family)&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLzJwEr6FHcm5-PXl2IRYW5KM78dZ2b7G46WWi73cb73l0_ALErBPY8BjhusRICg1dXt2qCjlzjooiR1TV2qLqS_kwNVrabTJOSSt5C6Sfdyw2l6yuWMtd1h9kaGsKi9mmyHqEdeL-a0o/s1600/IMG_20190804_103201.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;1200&quot; data-original-width=&quot;1600&quot; height=&quot;240&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLzJwEr6FHcm5-PXl2IRYW5KM78dZ2b7G46WWi73cb73l0_ALErBPY8BjhusRICg1dXt2qCjlzjooiR1TV2qLqS_kwNVrabTJOSSt5C6Sfdyw2l6yuWMtd1h9kaGsKi9mmyHqEdeL-a0o/s320/IMG_20190804_103201.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Vicky&#39;s talk covers another aspect. Developers and maintainers need more than money to keep going, they need back-up. The community need insurance against the &lt;a href=&quot;https://en.wikipedia.org/wiki/Bus_factor&quot;&gt;bus-factor&lt;/a&gt; and burn-out. I have been guilty of this myself, putting a few dollars behind features I would like to see in BountySource instead of diving in. This has become more so as I have progressed in my career and become increasingly time-poor. Talking about this would anyone at VSCode like to claim the few dollars we put &lt;a href=&quot;https://www.bountysource.com/issues/51511113-find-and-utilise-wsl-python-environments&quot;&gt;here&lt;/a&gt; ?&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEidbNgjQ5ywb2okfbKPFVi0E6lt-wxiPXvWBicBxbxUMb3xbG8fzKLdFria4_pOLmBPcBALKpST7eOi75zNqH6cg2XlFO5lVxskQJEtIxTeJCIRgmBB3KrKe8d6MvwOR8a-GSF-SLRk1qo/s1600/IMG_20190804_094158.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;1200&quot; data-original-width=&quot;1600&quot; height=&quot;240&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEidbNgjQ5ywb2okfbKPFVi0E6lt-wxiPXvWBicBxbxUMb3xbG8fzKLdFria4_pOLmBPcBALKpST7eOi75zNqH6cg2XlFO5lVxskQJEtIxTeJCIRgmBB3KrKe8d6MvwOR8a-GSF-SLRk1qo/s320/IMG_20190804_094158.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
I love the longevity and discipline of &lt;a href=&quot;https://warehouse.pypa.io/&quot;&gt;project warehouse&lt;/a&gt; and will find some time to contribute to it. I also look forward to a similar alternative to npm, rather than a &lt;a href=&quot;https://github.com/verdaccio/verdaccio&quot;&gt;caching proxy&lt;/a&gt; with community behind it.&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://whatnicklife.blogspot.com/feeds/2164081328991902443/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3220006345447041404/2164081328991902443' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3220006345447041404/posts/default/2164081328991902443'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3220006345447041404/posts/default/2164081328991902443'/><link rel='alternate' type='text/html' href='http://whatnicklife.blogspot.com/2019/08/open-source-sustainability-tale-of-2.html' title='Open-source Sustainability (The tale of 2 package managers)'/><author><name>Tisham Dhar</name><uri>http://www.blogger.com/profile/15154154153085427197</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLzJwEr6FHcm5-PXl2IRYW5KM78dZ2b7G46WWi73cb73l0_ALErBPY8BjhusRICg1dXt2qCjlzjooiR1TV2qLqS_kwNVrabTJOSSt5C6Sfdyw2l6yuWMtd1h9kaGsKi9mmyHqEdeL-a0o/s72-c/IMG_20190804_103201.jpg" height="72" width="72"/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3220006345447041404.post-5414069119147664413</id><published>2019-06-26T11:36:00.005-07:00</published><updated>2019-07-07T05:58:48.278-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="8051 CPU"/><category scheme="http://www.blogger.com/atom/ns#" term="electronics"/><category scheme="http://www.blogger.com/atom/ns#" term="family time"/><category scheme="http://www.blogger.com/atom/ns#" term="teardown"/><title type='text'>Sunbeam Coffee Maker Teardown</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgbOIFrEhfelajPNQYOnvXTCT_Ny6mIKBpUaXu4QFXgp06YZkka9bQiLRJy2hyphenhyphenBpvV4AEZuUdn11RPY7K2BUgZfBr_gJYXlvAHDDAu9rb4FPd5gkdlE5Ed-1L2mvRvjxZ-fzASxfli8Shw/s1600/IMG_20190618_184247.jpg&quot;&gt;&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgbOIFrEhfelajPNQYOnvXTCT_Ny6mIKBpUaXu4QFXgp06YZkka9bQiLRJy2hyphenhyphenBpvV4AEZuUdn11RPY7K2BUgZfBr_gJYXlvAHDDAu9rb4FPd5gkdlE5Ed-1L2mvRvjxZ-fzASxfli8Shw/s320/IMG_20190618_184247.jpg&quot; width=&quot;240&quot; height=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;The bad Kenyan grid has struck again. There is very little built in surge protection in the system, so all appliances plugged to the wall end up with in-house surge protectors. This time the victim was my beloved coffee machine which had served us well for more than a year.&lt;/p&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiEK1bx6qP_UWjlklxs86xgoCOuZ8jPLak7rCRl02hA5DicN4L1VPqg09JJP-jU5MqBbby4MUWov0G3VTPxxOsDKPohyphenhyphenMZ8Vv7dKqVRkIFDvXx4s1028IbnqhP2g_Ky9tdjWcXTmK7IESo/s1600/IMG_20190618_184303.jpg&quot;&gt;&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiEK1bx6qP_UWjlklxs86xgoCOuZ8jPLak7rCRl02hA5DicN4L1VPqg09JJP-jU5MqBbby4MUWov0G3VTPxxOsDKPohyphenhyphenMZ8Vv7dKqVRkIFDvXx4s1028IbnqhP2g_Ky9tdjWcXTmK7IESo/s320/IMG_20190618_184303.jpg&quot; width=&quot;240&quot; height=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;So I decided to take it home and spend some quality time with Pascal tearing it down. He is always curious about stuff and what is inside, so the Coffee machine is a complex beast capable of keeping him and myself occupied for hours on end. First we took of the top and looked at the heater and the electromechanical assembly controlling the hot-water head and frother was exposed. Also was exposed the heating tank with dual heating elements and a thermistor (I am assuming a thermistor rather than a thermocouple).&lt;/p&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj35E_l9oew38gi7qumrfO-S8D4mSjSC0yMIVeGHGCkxZ-i0dVQrMOU0sqayV6nfOrIDcGNFPNZFTExmD1XtMBximJdCXoXqBOIFKHtLFnRXXYIOeOkoZqDxlrqUhEJiNUPLLIOMVLGe5c/s1600/IMG_20190623_132023.jpg&quot;&gt;&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj35E_l9oew38gi7qumrfO-S8D4mSjSC0yMIVeGHGCkxZ-i0dVQrMOU0sqayV6nfOrIDcGNFPNZFTExmD1XtMBximJdCXoXqBOIFKHtLFnRXXYIOeOkoZqDxlrqUhEJiNUPLLIOMVLGe5c/s320/IMG_20190623_132023.jpg&quot; width=&quot;240&quot; height=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;When we took the back plate off we found the main controller board. There is to obvious transformer in the set-up so I assume to whole power supply is cap-drop. There is a giant heat-sink attached to a 3-pin device which I assume is a triac or SCR for controlling the heating elements.&lt;/p&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgdWGBnHMdHQph0_ElkFeP9F-ErxOh_WzGrKKZ92BvVFD6n-ZfKOEjjh0ZQkgjCRTwQ_4SEam0yCVQa-aRMBlNBYBU6iOjJmIr_VHdi05YAOg-hSFkD5ZSlCbiTe9kr_cFs411ss7jg6ak/s1600/IMG_20190623_132006.jpg&quot;&gt;&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgdWGBnHMdHQph0_ElkFeP9F-ErxOh_WzGrKKZ92BvVFD6n-ZfKOEjjh0ZQkgjCRTwQ_4SEam0yCVQa-aRMBlNBYBU6iOjJmIr_VHdi05YAOg-hSFkD5ZSlCbiTe9kr_cFs411ss7jg6ak/s320/IMG_20190623_132006.jpg&quot; width=&quot;240&quot; height=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;The bottom-left corner has a water pump with its own switching mechanism driven by relatively thin signal-wires from the main board.&lt;/p&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjR6D8ghGbVwpl3Hcpa5hED8w7JON8m8QmvQwfnWwBeSGHNhTguHvm8IO-sibRflsGxaS-IuC6297-tztEmNq805e1AiJLveZV7rzYTyfvrWri9EsfOT1GeThI4Bi40PAtkQi3OEjqdk5I/s1600/IMG_20190623_131725.jpg&quot;&gt;&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjR6D8ghGbVwpl3Hcpa5hED8w7JON8m8QmvQwfnWwBeSGHNhTguHvm8IO-sibRflsGxaS-IuC6297-tztEmNq805e1AiJLveZV7rzYTyfvrWri9EsfOT1GeThI4Bi40PAtkQi3OEjqdk5I/s320/IMG_20190623_131725.jpg&quot; width=&quot;240&quot; height=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;There are some more interesting details on the main processor board including thick high current traces driven by the silicon switch with exposed copper and extra solder on top to increase thickness and provide a lower current path.&lt;/p&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_oLalNXoszceIid9BEu7NkBFNa416TKkkn6bt8qJcI8O8pXs3k8HO5L_FN-YkpoA4k4Z2gG9GxDRQ2YI_dc1l7bmQL-grrsocBoqkFvPY_XCUd40PDEMEn3nceZcAMjmIRcHoim0Qpa8/s1600/IMG_20190623_131500.jpg&quot;&gt;&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_oLalNXoszceIid9BEu7NkBFNa416TKkkn6bt8qJcI8O8pXs3k8HO5L_FN-YkpoA4k4Z2gG9GxDRQ2YI_dc1l7bmQL-grrsocBoqkFvPY_XCUd40PDEMEn3nceZcAMjmIRcHoim0Qpa8/s320/IMG_20190623_131500.jpg&quot; width=&quot;240&quot; height=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;The main CPU is TQFP packaged micro-controller which is covered by the conformal coating the entire PCB is covered in. A macro image on twitter helped establish the lineage of the processor. It is a chinese 8051 variant with the datasheet &lt;a href=&quot;https://datasheetspdf.com/pdf/1252845/SINOWEALTH/SH79F1615/1&quot;&gt;here&lt;/a&gt;. Any help in translating it will be highly appreciated. But most of the schematic is legible.&lt;/p&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgqoBU6pd5X1603qtJQGY2nw3jV7FDRsFvdwf5efcyeJxn5aC4fW8Wc9qotEJn3ZE82OSHE0xyDen90h9NpViX4RebLSx5Naz0OAfCZSAML5ndUx8m6aoI_Jr5g2KZot3GZ84VQa5irl4M/s1600/IMG_20190623_130924.jpg&quot;&gt;&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgqoBU6pd5X1603qtJQGY2nw3jV7FDRsFvdwf5efcyeJxn5aC4fW8Wc9qotEJn3ZE82OSHE0xyDen90h9NpViX4RebLSx5Naz0OAfCZSAML5ndUx8m6aoI_Jr5g2KZot3GZ84VQa5irl4M/s320/IMG_20190623_130924.jpg&quot; width=&quot;240&quot; height=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Next up will be powering on the processor with a suitable 3.3v supply and examining the analog and digital buses. As well as powering on the whole thing to see why it turns of immediately on start. If the machine is unfixable I am planning to scavenge the thermistors, heating elements etc. to build a reflow mechanism.&lt;/p&gt;
&lt;p&gt;All the water circulation mechanism is really interesting as well and can possibly be shoe-horned into a water cooler for a 3D printing system.&lt;/p&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjbDi_yJecwNx-4upRxfAMtIy4jWeua4pqdc38I7c2muTKoj6MPxAg0UC56BYptS3G8Wk1o0avLND_q1YpZAYfeSvYaTfntB5LEovMH4vsQ6CXQEXMjYbdqeFY-x7RPsxCtVm4p-bjOEoI/s1600/IMG_20190623_130859.jpg&quot;&gt;&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjbDi_yJecwNx-4upRxfAMtIy4jWeua4pqdc38I7c2muTKoj6MPxAg0UC56BYptS3G8Wk1o0avLND_q1YpZAYfeSvYaTfntB5LEovMH4vsQ6CXQEXMjYbdqeFY-x7RPsxCtVm4p-bjOEoI/s320/IMG_20190623_130859.jpg&quot; width=&quot;240&quot; height=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://whatnicklife.blogspot.com/feeds/5414069119147664413/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3220006345447041404/5414069119147664413' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3220006345447041404/posts/default/5414069119147664413'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3220006345447041404/posts/default/5414069119147664413'/><link rel='alternate' type='text/html' href='http://whatnicklife.blogspot.com/2019/06/sunbeam-coffee-maker-teardown.html' title='Sunbeam Coffee Maker Teardown'/><author><name>Tisham Dhar</name><uri>http://www.blogger.com/profile/15154154153085427197</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgbOIFrEhfelajPNQYOnvXTCT_Ny6mIKBpUaXu4QFXgp06YZkka9bQiLRJy2hyphenhyphenBpvV4AEZuUdn11RPY7K2BUgZfBr_gJYXlvAHDDAu9rb4FPd5gkdlE5Ed-1L2mvRvjxZ-fzASxfli8Shw/s72-c/IMG_20190618_184247.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3220006345447041404.post-6861861209109067745</id><published>2019-06-22T10:58:00.005-07:00</published><updated>2019-06-22T14:45:21.670-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="community"/><category scheme="http://www.blogger.com/atom/ns#" term="electronics"/><category scheme="http://www.blogger.com/atom/ns#" term="meetup"/><category scheme="http://www.blogger.com/atom/ns#" term="open source"/><title type='text'>Nairobi 2nd OSHW meetup</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
After a many month hiatus we finally put together the 2nd &lt;a href=&quot;https://www.meetup.com/en-AU/Nairobi-Open-Source-Hardware-Meetup/&quot;&gt;Nairobi Open-source hardware meetup&lt;/a&gt;. This time we were at the &lt;a href=&quot;https://www.facebook.com/TheTavIrishPub/&quot;&gt;Tav Irish Pub&lt;/a&gt; near Nairobi Garage on Waiyaki way. The pub was chosen due to proximility to Nairobi garage and possible use of that venue. As it turned out none of us were memebers paying the $60 per-month fee so we ended up co-opting the pub in Chicago &lt;a href=&quot;https://www.meetup.com/Hardware-Happy-Hour-3H-Chicago/&quot;&gt;3H&lt;/a&gt; fashion.&lt;br /&gt;
&lt;div class=&quot;figure&quot;&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;img alt=&quot;PCB Lineup&quot; height=&quot;240&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5kgg-jDW3f4bAnFu-GQ4BGjgTJcZdSqwLj7fXKZFIVCJc8N7LaNZsQvyQ4rS74vir9gEhshzddydHgpRgZpl3k4crwtlfAMHKFcVhK85HV7i8NxIxV1_lYzCDzW38cza4npnGGgBBIk0/s320/IMG_20190608_152150.jpg&quot; style=&quot;margin-left: auto; margin-right: auto;&quot; width=&quot;320&quot; /&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;PCB Lineup&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
I had collected PCB&#39;s over the last few month from &lt;a href=&quot;https://aisler.net/&quot;&gt;Aisler&lt;/a&gt;, &lt;a href=&quot;http://oshpark.com/&quot;&gt;OSHPark&lt;/a&gt; and &lt;a href=&quot;https://www.pcbway.com/&quot;&gt;PCBWay&lt;/a&gt; all shipped to Kenya from Germany, US and China respectively. So we lined up to try various soldering techniques on 0603 Jellybeans and some 20pin TSSOP IC&#39;s.&lt;br /&gt;
&lt;div class=&quot;figure&quot;&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;img alt=&quot;Soldering demo&quot; height=&quot;240&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEifYbZ7Gm5N8sLo_jsIozhbJWdPqtaIAMohLZsSOPM6G5KlsDxszJokg83YzAiSVMVY8CVimueiz4j1VHfIpbXxbSM6jlhkmHAW5QFLeG5T-VK1n1UYCpcpKbW1MpJhGs7wEKC2vaUlGsM/s320/IMG_20190608_155321.jpg&quot; style=&quot;margin-left: auto; margin-right: auto;&quot; width=&quot;320&quot; /&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Soldering Demo&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
The techniques we we tried were the tack, finish and reflow one using the iron and an experimental one with paste and dry-iron I had picked up recently. I didn&#39;t have a temperature profile controller for the dry-iron method. So we were just going to wing it by the eye.&lt;br /&gt;
&lt;div class=&quot;figure&quot;&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;img alt=&quot;Part Placement&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj4Fe-ZB0TPlL8NsBO1GGz7dDCGzyae2KXCiSfiMl6jjIRE0XDWum8wDAW774R3HlDy3e3UAvqEQyGAHhDv0MH_VvHMTJevTEegxlo2fWtZ0n89qcwu_TPctpA2qQuRs6_I5vBY1k7vHuw/s320/IMG_20190608_160645.jpg&quot; style=&quot;margin-left: auto; margin-right: auto;&quot; width=&quot;240&quot; /&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Part Placement&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
We pasted up the boards using screwdrivers and tweezers. Started the reflow till the parts settled. Then simply turned off the iron. I am sourcing a K-Type thermocouple and SSR from &lt;a href=&quot;https://ktechnics.com/&quot;&gt;KTechnics&lt;/a&gt; to get a better handle on this for next time. However the dry-iron does reach sufficient temperature for leaded solder reflow.&lt;br /&gt;
&lt;div class=&quot;figure&quot;&gt;
&lt;img alt=&quot;Dry iron reflow&quot; height=&quot;240&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiR3XCKDe8whllY3ygHtB-hB6tbGJBATP_t6BHMC5ezKVQnMUEh_vT0zkvKPc5tiDdsUu6-QFMneE3KI5q_jN6wupMnZdfK9bJTgotB65gid0BRx5kiOE4qXeYVy9CX34b6Q5u-R7YQKF8/s320/IMG_20190608_171403.jpg&quot; width=&quot;320&quot; /&gt;
&lt;br /&gt;
&lt;div class=&quot;caption&quot;&gt;
Dry iron reflow&lt;/div&gt;
&lt;/div&gt;
By the end of the session we had assembled x2 &lt;a href=&quot;https://github.com/whatnick/CS5464_Breakout&quot;&gt;CS5464 Breakouts&lt;/a&gt;. Next step from here will be suitable MicroPython and Arduino drivers to ensure these things actually work. We had a lot of fun over the meetup and I hope to continue having these sessions. Next time one of the participants has promised to bring his Weighbridge Automation and IoT set-up.&lt;br /&gt;
&lt;div class=&quot;figure&quot;&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;img alt=&quot;Scavenging Coffee Machine&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWOonUtBs_JrYqV4qn3dkRcMHEqcW23AH9o5Zv7vOAbxBJcMIaklznwGelekZ1l4FWqBlcYExfbM5lK0VclryzkLwJD4FESvKVEtfSAq0hJYeNpuAdskoNXN0sZj4JsoZuNiN_LGcd47A/s320/IMG_20190618_184303.jpg&quot; style=&quot;margin-left: auto; margin-right: auto;&quot; width=&quot;240&quot; /&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Scavenging a Coffee Machine&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
Following the meetup I have been hunting for accessories to make the dry-iron reflow less of a fire hazard and more controllable. (Un)fortunately the coffee machine at work has been fried by the spikes prevalent in the grid in Kenya (especially during the rainy season), so I have a spare K-type thermocouple I can work into the build. I have also co-opted a tissue holder we had on our dining table to stabilize the inverted iron during reflow.&lt;br /&gt;
&lt;div class=&quot;figure&quot;&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;img alt=&quot;A stand of opportunity&quot; height=&quot;240&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3pNmvEXxFklqXnYkuvaJEZhpMVTNiTF6LNrffxE0Alh441TUzUP5LHAy9yeJcLBl9H1hzPWN8qSo4IZPCCzBVY5lHwMnp1gArXdjsTLZ5N0nJyZfZCeRJF0-DMWBmu8l2hIH1qMWM5Wo/s320/IMG_20190619_084415.jpg&quot; style=&quot;margin-left: auto; margin-right: auto;&quot; width=&quot;320&quot; /&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Stand of opportunity&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
Onwards to the next Meetup.&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://whatnicklife.blogspot.com/feeds/6861861209109067745/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3220006345447041404/6861861209109067745' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3220006345447041404/posts/default/6861861209109067745'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3220006345447041404/posts/default/6861861209109067745'/><link rel='alternate' type='text/html' href='http://whatnicklife.blogspot.com/2019/06/nairobi-2nd-oshw-meetup.html' title='Nairobi 2nd OSHW meetup'/><author><name>Tisham Dhar</name><uri>http://www.blogger.com/profile/15154154153085427197</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5kgg-jDW3f4bAnFu-GQ4BGjgTJcZdSqwLj7fXKZFIVCJc8N7LaNZsQvyQ4rS74vir9gEhshzddydHgpRgZpl3k4crwtlfAMHKFcVhK85HV7i8NxIxV1_lYzCDzW38cza4npnGGgBBIk0/s72-c/IMG_20190608_152150.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3220006345447041404.post-6811258733255406469</id><published>2019-06-22T10:57:00.005-07:00</published><updated>2019-08-15T19:04:22.058-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="chicago"/><category scheme="http://www.blogger.com/atom/ns#" term="conference"/><category scheme="http://www.blogger.com/atom/ns#" term="electronics"/><category scheme="http://www.blogger.com/atom/ns#" term="KiCAD"/><category scheme="http://www.blogger.com/atom/ns#" term="travel"/><title type='text'>KiCon 2019 - Chicago in a weekend</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
Getting away from a fast paced &lt;a href=&quot;https://www.lorisystems.com/&quot;&gt;start-up&lt;/a&gt; to attend conferences is a hard ask. However I managed to get away for a few days to attend the inaugural KiCad conference in Chicago a few weeks ago.&lt;br /&gt;
&lt;div class=&quot;figure&quot;&gt;
&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYhOWZpaJVK-w5sUxKO9tO0WffqhZCM2XGCVi8EnCJfq_nVJAR56vM95JQIa75M8yh07VO7OdjlzVbj8h16ouIzHrd4Y377kwoKqh8WSVzMIkbnBkz3tnQo7_f2tJS7l8a72Dr5w_sROY/s320/IMG_20190425_163912.jpg&quot; /&gt;

&lt;/div&gt;
The pace has been such that only after about a month I am getting a chance to write it all up. The first night I managed to attend the &lt;a href=&quot;https://www.meetup.com/en-AU/Hardware-Happy-Hour-3H-Chicago/&quot;&gt;Hardware Happy Hour&lt;/a&gt; at the Ballast Point. I got to see some amazing stuff including pneumatics for an autoplaying piano using layers of PCB.&lt;br /&gt;
&lt;div class=&quot;figure&quot;&gt;
&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg83cmvSnPOLMiNVtJHwBOW_dVAG1_bkyEGaRLWp1fnr5ZSVbBeXSU2dPwmP0USP7zUloBI_9j2xwlUiatTpcpUrxFnJv1c_r-1AWhzZxIlx2tbCC2y-XaETPHVNMR7HZBW00xvdpiSDds/s320/IMG_20190425_204023.jpg&quot; /&gt;

&lt;/div&gt;
The huge selection of beers and the chicago dogs were definitely unexpected bonuses.&lt;br /&gt;
&lt;div class=&quot;figure&quot;&gt;
&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj3xxgcA28-N8nnskph03SI_k5GsbPHtS7hJX5mNFZ-8NmAmbr7pOekSzpr-b3UjxhB3P7TruBQl3ekLLIbv34zarZ8vKZwavyJcnauXYrTS5CXdDHw8TqLHmUYxU8oLbbLNGkVI9z1TKQ/s400/IMG_20190425_221646.jpg&quot; /&gt;

&lt;/div&gt;
Tour of &lt;a href=&quot;https://mhubchicago.com/&quot;&gt;MHub&lt;/a&gt; assembly area with pick and place machine and large Molex sign. Also got to see &lt;a href=&quot;https://twitter.com/Chris_Gammell&quot;&gt;Chris Gammell&lt;/a&gt;&#39;s desk and pick up some Amazon and Mouser shopping to bring back to Nairobi.&lt;br /&gt;
&lt;div class=&quot;figure&quot;&gt;
&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiKN2y08T-6dQmZ-ON-ejMNGhhFOuxi1MSB_Mr6fQaMzUXCnb_amNBJJmosyjHeSO632UgyJBuxOO8oNOk-TO7NY286NZivMrrGD6Eu2-7fGtvYhb1Z7ihWAi8i5tiIxyZ7sxfXjGaxc0w/s320/IMG_20190426_133456.jpg&quot; /&gt;

&lt;/div&gt;
I could definitely use the pick-n-place machine in my house and I hope Chris makes use of it whenever he can.&lt;br /&gt;
&lt;div class=&quot;figure&quot;&gt;
&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhLIAPa5Ksgk8g4U56pbJ4eoj7DzWfAedLQDQEr7G76LDxwR24X2f_hSMNer8X2LSRvdFDu8nb5uuRLIhHOvI68pYbbavIHpn34Ly6RImyicK8XufQz34fYjmYtCvc9N71LkMRGgKGhmjI/s320/IMG_20190426_133627.jpg&quot; /&gt;

&lt;/div&gt;
I also got to speak to some companies I have worked with remotely but not met the principles and representatives in person, including &lt;a href=&quot;https://www.crowdsupply.com/whatnick/atm90e26-energy-monitor-kits&quot;&gt;CrowdSupply&lt;/a&gt;, &lt;a href=&quot;https://aisler.net/&quot;&gt;Aisler&lt;/a&gt;, &lt;a href=&quot;https://www.snapeda.com/home/&quot;&gt;SnapEDA&lt;/a&gt;, &lt;a href=&quot;https://hologram.io/&quot;&gt;Hologram&lt;/a&gt; and of course DigiKey. It was great to speak to the KiCAD dev team as well, perhaps I can contribute on the &lt;a href=&quot;http://docs.kicad-pcb.org/doxygen/md_Documentation_development_compiling.html#build_windows&quot;&gt;MSVC windows&lt;/a&gt; native build. I also managed to score credits freebies from all the sources.&lt;br /&gt;
&lt;div class=&quot;figure&quot;&gt;
&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjCh_KUvENZ94-h-yAtmZ4H8jHSGuHb_hJUmK9sLPF-TL0KZJW2ffXvGhldueO-elllOmHZzf4yy819PdGKz6suEhAdWyin1JoqsqpaYyFsrzsrCnbYyrEs4IH6bezrJywQ82opNqDFcmc/s320/IMG_20190428_171944.jpg&quot; /&gt;

&lt;/div&gt;
Here are pure notes to self on various topics that I picked up on 2-days of super varied and dense conferencing. Some are commands I would like to run some, are techniques I learnt and some are pure stories I picked up.&lt;br /&gt;
&lt;h2 id=&quot;schematics-are-a-drug-use-code-instead&quot;&gt;
Schematics are a drug, use code instead&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;pip install skidl&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;auto-routers-are-evil-but-useful&quot;&gt;
Auto-routers are evil but useful&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Triangles (Topological/ Using TIN mesh)&lt;/li&gt;
&lt;li&gt;Maze solving&lt;/li&gt;
&lt;li&gt;Shape based ( Rectangles)&lt;/li&gt;
&lt;li&gt;Channel Based&lt;/li&gt;
&lt;li&gt;FreeRouting&lt;/li&gt;
&lt;li&gt;Adaptive heuristics using deep learning&lt;/li&gt;
&lt;li&gt;Linear increase in PCB complexity&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;high-frequency-simulation-in-ghz-range-for-pcbs&quot;&gt;
High-frequency simulation (in GhZ range) for PCB&#39;s&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;OpenEMS ( MEEP)&lt;/li&gt;
&lt;li&gt;Wilkinson filter&lt;/li&gt;
&lt;li&gt;Important in Radar Design&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;prototyping-in-a-few-hours&quot;&gt;
Prototyping in a few hours&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Isolation milling&lt;/li&gt;
&lt;li&gt;Midwest Circuit Technologies&lt;/li&gt;
&lt;li&gt;Bantam tools. Binary save.&lt;/li&gt;
&lt;li&gt;1/32&quot; end mill 0.8mm tool&lt;/li&gt;
&lt;li&gt;10 mill trace&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;rendering-photorealistic-pcbs&quot;&gt;
Rendering photorealistic PCB&#39;s&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Render layers to image texture&lt;/li&gt;
&lt;li&gt;Use Blender cycles based render with bump maps for silk-screen and traces&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;contributing-to-kicad&quot;&gt;
Contributing to KiCAD&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Development in LaunchPad + Github&lt;/li&gt;
&lt;li&gt;Starter bugs are available&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;more-hf-pcbs&quot;&gt;
More HF PCB&#39;s&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;30MHz to 3Ghz, with narrow bins&lt;/li&gt;
&lt;li&gt;5.6GSPS digitizer&lt;/li&gt;
&lt;li&gt;Tuned lines. Right angles create problems.&lt;/li&gt;
&lt;li&gt;Use footprint, Arc or Trace around edge cuts.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;figure&quot;&gt;
&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0IxIvx0_m6sW8yKF13UdHanRQrkEpN7EafoE93BvMM8pCo0mSPtu5hzBvSvXiLHKuUzjpvQUAxihF78b6G-ZUYSB2KunpptMu_76LASaVeYd-5MIh7i6JQhh0f083dYAxKotVtzV6FLI/s320/IMG_20190427_195235.jpg&quot; /&gt;

&lt;/div&gt;
I woke up pretty early on Saturday morning and walked around and almost hopped on a fire-engine tour. Always wanted to do that. Then I checked the radar, another thing missing in Nairobi, and a huge snowstorm was inbound. Snowstorms at this time in Chicago are atypical, but hey everyone stays in for the coference. By the time the conference finished and I headed home from the after-party everything was covered in snow.&lt;br /&gt;
&lt;div class=&quot;figure&quot;&gt;
&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj65kB_EXon_Nc-nedBCnhklyDjX-cfCQtbm9kEmm9TLWTkfl0LAjoAJqtM-z0Y0SIst71ki1vvLMXJUE5EFHFRerPFx11NhWU-_HGy9zfF_g0e-GwtjxBXPWzIGD3ad7diqX-3MY-11JA/s320/IMG_20190427_084518.jpg&quot; /&gt;

&lt;/div&gt;
&lt;div class=&quot;figure&quot;&gt;
&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjnANL7AcM-SypbBq3RAEsiGiPd_yLnUivEJdA5JYuN45FlaUDjKWWWL_Fblqmn-CtRAeuE-_1e6IrINJKI9fLgA7hcUZxdM2aJMqJKwNyfepQoz5QR8MvJX5VToWaZKJmpjKeSSCn5xPk/s320/IMG_20190427_084438_1.jpg&quot; /&gt;

&lt;/div&gt;
The last day (Sunday) was spent taking an Uber Pool , a novelty for me, to a Vietnamese grocery and spending around 2 hours getting additional exotic food-supplies to bring back to Nairobi&lt;br /&gt;
&lt;div class=&quot;figure&quot;&gt;
&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUCiKzbV0RLjP6MQvlKXa0k-GHYvYaGDGSfVbycHhTnfNypGbTkOLslEEP8EQm04bEcJtqsMLqM-aaEFwP7j3n5yvZWMDA6wZZV5oAwxoFesqtHrcElhcNFZTpiQ9zWO0h03lZeNP0HHg/s320/IMG_20190428_083426.jpg&quot; /&gt;

&lt;/div&gt;
I saw a Harvey milk tail fin and took to the skies back to hop across the Atlantic and Mediterrnean to Nairobi. Flying 40 hrs to conference for 48 hours and shop for 6 is a real pain. Will have to bring the KiCAD movement back home to Nairobi and pour more effort into the local hardware scene.&lt;br /&gt;
&lt;div class=&quot;figure&quot;&gt;
&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgx902gDazMtfE_9dCmNraeO-xwrnOg2DMQI6Ffwk7LpVEfDbr1v5oMPUqxO0RRLhhSv2N0tIu3kUjvO5K7wSlJ0jB79_pkWkLvTnsdHtzy2l_6jdmj5IggmJPxTM_UF2g4SBDdRCLwgDQ/s320/IMG_20190428_191432.jpg&quot; /&gt;

&lt;/div&gt;
So long Chicago, see you next conference.&lt;br /&gt;
&lt;div class=&quot;figure&quot;&gt;
&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjW_LXjUmHtFfkiiXd-74pOS8GTSgfBUEs_uzU0CdS2NHFN01tT8P1IhqdbWDcgxBMGU5qri1DznwGMgWdU2zq41b6UhX2Wt35EI6pd1e4qPLmQlGLnTaC3Y5gQ-42vpfLT5Dv6UGtCmsw/s320/IMG_20190428_194525.jpg&quot; /&gt;

&lt;/div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://whatnicklife.blogspot.com/feeds/6811258733255406469/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3220006345447041404/6811258733255406469' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3220006345447041404/posts/default/6811258733255406469'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3220006345447041404/posts/default/6811258733255406469'/><link rel='alternate' type='text/html' href='http://whatnicklife.blogspot.com/2019/06/kicon-2019-chicago-in-weekend.html' title='KiCon 2019 - Chicago in a weekend'/><author><name>Tisham Dhar</name><uri>http://www.blogger.com/profile/15154154153085427197</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYhOWZpaJVK-w5sUxKO9tO0WffqhZCM2XGCVi8EnCJfq_nVJAR56vM95JQIa75M8yh07VO7OdjlzVbj8h16ouIzHrd4Y377kwoKqh8WSVzMIkbnBkz3tnQo7_f2tJS7l8a72Dr5w_sROY/s72-c/IMG_20190425_163912.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3220006345447041404.post-773024729656002394</id><published>2019-03-03T07:28:00.001-08:00</published><updated>2019-03-03T07:28:24.417-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="electronics"/><category scheme="http://www.blogger.com/atom/ns#" term="energy monitor"/><category scheme="http://www.blogger.com/atom/ns#" term="kogan"/><category scheme="http://www.blogger.com/atom/ns#" term="teardown"/><title type='text'>Kogan Energy Monitor Teardown - Sonoff-Pow in a wall plug</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
After doing a tear-down on the &lt;a href=&quot;https://whatnicklife.blogspot.com/2018/11/tplink-smart-plug-teardown.html&quot;&gt;TPLink Wall Plug&lt;/a&gt; energy monitor I found mentions in Australia of the much cheaper &lt;a href=&quot;https://www.kogan.com/au/buy/kogan-smarterhome-smart-plug-energy-meter/&quot;&gt;Kogan Alternative&lt;/a&gt;. So I decided to get a couple of them see what makes them tick as well.&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiXlV_vLbQjMccvR8MFQWtdp7hCbJntHOtplDCIweSwQo6oZxsfVvIPvZptewycSgp0ekAbikIbHUK9zknxeGfcb1fCruVlEFr0ls5Lt4GqipYjACHrgE3eN2qmgxbuGkTxtcqiakM9-n0/s1600/general_assembly.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;1600&quot; data-original-width=&quot;1465&quot; height=&quot;400&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiXlV_vLbQjMccvR8MFQWtdp7hCbJntHOtplDCIweSwQo6oZxsfVvIPvZptewycSgp0ekAbikIbHUK9zknxeGfcb1fCruVlEFr0ls5Lt4GqipYjACHrgE3eN2qmgxbuGkTxtcqiakM9-n0/s400/general_assembly.png&quot; width=&quot;366&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;General Assembly of the whole unit&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
&lt;div&gt;
&lt;b&gt;TL;DR&lt;/b&gt; - The Kogan one is cheaper because it uses a bare metal (non-linux capable) CPU and a PWM output type energy monitor (without intricacies of a SPI protocol and calibration). It is essentially a repackaged &lt;a href=&quot;https://www.itead.cc/sonoff-pow.html&quot;&gt;Sonoff Pow&lt;/a&gt;.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
The details of the build are packages in sections as I discovered them.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
&lt;b&gt;LV and Buck converter&lt;/b&gt;&lt;/h3&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
The LV section consists of two separate cricuits:&lt;/div&gt;
&lt;div&gt;
&lt;ol style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;Relay to switch the load&lt;/li&gt;
&lt;li&gt;Buck converter to rectify and convert 240v to 5v to power electronics&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;
The diagram below presents both of these sections. The Buck converter is basically the toplogy found in many &lt;a href=&quot;https://www.aliexpress.com/item/5V-700mA-3-5W-AC-DC-Precision-Buck-Converter-AC-220v-to-5v-DC-step-down/32649591757.html&quot;&gt;aliexpress products&lt;/a&gt;. Perhaps with the difference of being unisolated (notice no slots). The relay is rated at 15A which is nice compared the TPLink product which uses x2 - 5A relays in parallel to achieve 10A.&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjraDFTUlGPPujzN08jwTjMEymNn2oWuXx-XGlTFrRxu8Nz8I5f8rJ3mnGCqaWQfLvynXF1zRYzuTd-oVDKxVeq1W601hrvhaZ-PTZCQapZYkRlcxCydjtrGvSrUVA2Ww2LxsoeXh6Ms_0/s1600/lv_section.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;957&quot; data-original-width=&quot;1600&quot; height=&quot;238&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjraDFTUlGPPujzN08jwTjMEymNn2oWuXx-XGlTFrRxu8Nz8I5f8rJ3mnGCqaWQfLvynXF1zRYzuTd-oVDKxVeq1W601hrvhaZ-PTZCQapZYkRlcxCydjtrGvSrUVA2Ww2LxsoeXh6Ms_0/s400/lv_section.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Low Voltage (240v) Circuitry&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;div&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Energy Monitor and LDO&lt;/h3&gt;
&lt;/div&gt;
&lt;div&gt;
This a 3.3v operated section which uses the super low-cost PWM output energy monitor IC made popular by the Sonoff the measure instantaneous voltage, current and hence power. The pulses are channeled to the main processor for forwarding to whatever backend Kogan has put together.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRJPOQZ6ZoKR6nM7oHPtUo58g5xwWbRSIY7rgic2o4Nm7O3f_bqKkZMg-uK2gJ2Dqm0_r8Odx-Ix7j-Vq_BzpkxNTu5v1CXVkQCCUaXyGqEA6mBgBgRGaNvZV4ScoVOIeuWMmeE5fiXjE/s1600/metering_ldo.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;1286&quot; data-original-width=&quot;1600&quot; height=&quot;257&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRJPOQZ6ZoKR6nM7oHPtUo58g5xwWbRSIY7rgic2o4Nm7O3f_bqKkZMg-uK2gJ2Dqm0_r8Odx-Ix7j-Vq_BzpkxNTu5v1CXVkQCCUaXyGqEA6mBgBgRGaNvZV4ScoVOIeuWMmeE5fiXjE/s320/metering_ldo.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Metering and LDO&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Main Processor&lt;/h3&gt;
&lt;div&gt;
The design seems to have taken a standard ESP module and planted it on a basic PCB to fit in the power-plug form factor, sideways. The carries board has lots of markings and test-points making the task of reverse engineering and putting new firmware on this board almost too easy.&lt;/div&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhI2OC4OYOH0NfoU0nYZhx23-kAlcjYODyZo3sKyyfGymjSX7QrfUhppBfWP1wfEMLzlFg2fWNyboqz7y38c5Fm99IVBYgve3u8Rsh81Tuzmdj1PVyPbJCkYa17ZzPEuQ5E93Rq-jpAENI/s1600/IMG_20190209_171506.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;1600&quot; data-original-width=&quot;1200&quot; height=&quot;400&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhI2OC4OYOH0NfoU0nYZhx23-kAlcjYODyZo3sKyyfGymjSX7QrfUhppBfWP1wfEMLzlFg2fWNyboqz7y38c5Fm99IVBYgve3u8Rsh81Tuzmdj1PVyPbJCkYa17ZzPEuQ5E93Rq-jpAENI/s400/IMG_20190209_171506.jpg&quot; width=&quot;300&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Processor module adapter&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgxKw6cTCH8Ti_3hLeq7RzlG6ZfRvVHC4a0XVyHVegj2i24tGWGYnp-7JkUOyVhBrQ75p0Fql4fP8p63nG5mngksNeIgZ8RpuEhXpdS30VYRDWTCNG4a1t1mvKqb2-fkzfUdBnFtbmJsm4/s1600/IMG_20190209_171519.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;1600&quot; data-original-width=&quot;1200&quot; height=&quot;400&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgxKw6cTCH8Ti_3hLeq7RzlG6ZfRvVHC4a0XVyHVegj2i24tGWGYnp-7JkUOyVhBrQ75p0Fql4fP8p63nG5mngksNeIgZ8RpuEhXpdS30VYRDWTCNG4a1t1mvKqb2-fkzfUdBnFtbmJsm4/s400/IMG_20190209_171519.jpg&quot; width=&quot;300&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Marked bottom test pads of processor carrier PCB&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
Over all this looks like a nice certified unit which you can run your own firmware on thanks with the help of the right triangular security bit.&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://whatnicklife.blogspot.com/feeds/773024729656002394/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3220006345447041404/773024729656002394' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3220006345447041404/posts/default/773024729656002394'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3220006345447041404/posts/default/773024729656002394'/><link rel='alternate' type='text/html' href='http://whatnicklife.blogspot.com/2019/03/kogan-energy-monitor-teardown-sonoff.html' title='Kogan Energy Monitor Teardown - Sonoff-Pow in a wall plug'/><author><name>Tisham Dhar</name><uri>http://www.blogger.com/profile/15154154153085427197</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiXlV_vLbQjMccvR8MFQWtdp7hCbJntHOtplDCIweSwQo6oZxsfVvIPvZptewycSgp0ekAbikIbHUK9zknxeGfcb1fCruVlEFr0ls5Lt4GqipYjACHrgE3eN2qmgxbuGkTxtcqiakM9-n0/s72-c/general_assembly.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3220006345447041404.post-9026837520301515018</id><published>2019-01-23T11:21:00.000-08:00</published><updated>2019-01-23T11:22:35.761-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="kenya"/><category scheme="http://www.blogger.com/atom/ns#" term="mercury"/><category scheme="http://www.blogger.com/atom/ns#" term="mining"/><category scheme="http://www.blogger.com/atom/ns#" term="travel"/><title type='text'>Around Kenya in 4 days and a year ( part 1)</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
2018 was a year on making impromptu decisions and hopping on random flights heading for adventure. In the beginning of the year I left &lt;a href=&quot;http://aerometrex.com.au/&quot;&gt;Aerometrex&lt;/a&gt; to explore new opportunities at &lt;a href=&quot;https://www.lorisystems.com/&quot;&gt;Lori&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
It turned out I finished the year in similar markovian motion travelling around Kenya with a couple of high school friends. Thank you so much &lt;a href=&quot;https://www.linkedin.com/in/eric-mibuari-bb24044/&quot;&gt;Eric&lt;/a&gt; for driving and showing us the beautiful country.&lt;br /&gt;
&lt;br /&gt;
I received a call late on the 29th December proposing the trip. I booked a ticket of &lt;a href=&quot;https://www.flysafarilink.com/en&quot;&gt;Safarilink&lt;/a&gt; and went to bed.&amp;nbsp; Flying out of Wilson Airport is magnitudes easier than flying out of Jomo Kenyatta International. I almost missed the flight, but the empty Christmas streets in Nairobi and low access overheads in Wilson meant I flew into Kisumu with zero dramas. I hopped in a Probox from Kisumu to catch up with the other 2 in Kericho. The &lt;a href=&quot;https://www.nation.co.ke/lifestyle/dn2/Probox-It-will-kill-your-image-but-build-your-business-/957860-1243940-11y6l53z/index.html&quot;&gt;Probox&lt;/a&gt; are known for being death machines, but is a super cheap and fast way to get around. There is another article somewhere revolving around the impact of the Probox on transport in Kenya.&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEir1Qi3k3XyTm5BxCmKhZy-FSluP2XdcQ1Ro5yxpEVZWkSdkvG1ifkkzFmkb0Axd79wQziXaI9lXyU3P8V1sx97T0WDsrZe66IkU-gWuBessyapgFUxkgQaFQElxUv8ckuzzDJ9fPvm0Ck/s1600/IMG_20181229_081444.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;1200&quot; data-original-width=&quot;1600&quot; height=&quot;240&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEir1Qi3k3XyTm5BxCmKhZy-FSluP2XdcQ1Ro5yxpEVZWkSdkvG1ifkkzFmkb0Axd79wQziXaI9lXyU3P8V1sx97T0WDsrZe66IkU-gWuBessyapgFUxkgQaFQElxUv8ckuzzDJ9fPvm0Ck/s320/IMG_20181229_081444.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Tiny Kisumu Airport&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiOR8ySoLTB9CSY81uvnPE97D-9sjHl-SXCQ26mOjUvOzf_h70gMMuuAjTIcFVWT7uPzNbQ9HBzurDfkRgBqEoGkmONLVYwgXSDQksXerQorUYhoE5qcPVwD737mLqOsf-wH_K096zBQk4/s1600/IMG_20181229_081417.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;1200&quot; data-original-width=&quot;1600&quot; height=&quot;240&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiOR8ySoLTB9CSY81uvnPE97D-9sjHl-SXCQ26mOjUvOzf_h70gMMuuAjTIcFVWT7uPzNbQ9HBzurDfkRgBqEoGkmONLVYwgXSDQksXerQorUYhoE5qcPVwD737mLqOsf-wH_K096zBQk4/s320/IMG_20181229_081417.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Safarilink Flight (Turboprop)&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
We then travelled via some roads still being built from the tea-gardens of Kericho to the lush sugarcame farms of Awendo. In sections the road meandered into farms and cars had to go in a single file and often backup into fields when a truck came by from the other side.&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjuuF3Kli_qCJyMmshzLtWol-wI9IH9Um2aA8_L_CniJns7iDNOy1QeUPTZEciKa6JsndjrJlZ8vLSR6SGMGTxJ5VdXsBGL7wxX-n-dHMzU2lAl7aMvj0ChNZTg8PosUUoftBGjJDncss/s1600/IMG_20181229_163236.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;1212&quot; data-original-width=&quot;1600&quot; height=&quot;242&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjuuF3Kli_qCJyMmshzLtWol-wI9IH9Um2aA8_L_CniJns7iDNOy1QeUPTZEciKa6JsndjrJlZ8vLSR6SGMGTxJ5VdXsBGL7wxX-n-dHMzU2lAl7aMvj0ChNZTg8PosUUoftBGjJDncss/s320/IMG_20181229_163236.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Road through Kisii&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
It was a great night of going out to watch football match in Ulanda town and staying at Owuor&#39;s &lt;a href=&quot;https://archive.macleki.org/items/show/2759&quot;&gt;Simba&lt;/a&gt;. The road from &lt;a href=&quot;https://en.wikipedia.org/wiki/Awendo&quot;&gt;Awendo&lt;/a&gt; to Ulanda is awesome. The sugar cane is a mass scale project and produces a lot of &lt;a href=&quot;https://en.wikipedia.org/wiki/Bagasse&quot;&gt;bagasse&lt;/a&gt; which can be recycled into paper tissue and other products with the right infrastructure.&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhalcHxWaHOSx0KHBR9nH3HKWcOo-MVGifBlmo-_UBCdt2kOVnfzyPmJvYSRPpYzMd4h2BmiGUewTKAyMe9c8oKrg4u-oJiBuWWKH8cGIkF53PVpI3tM-4taDdLQUbtH8fBAYYzN_4inws/s1600/IMG_20181230_112631.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;1200&quot; data-original-width=&quot;1600&quot; height=&quot;240&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhalcHxWaHOSx0KHBR9nH3HKWcOo-MVGifBlmo-_UBCdt2kOVnfzyPmJvYSRPpYzMd4h2BmiGUewTKAyMe9c8oKrg4u-oJiBuWWKH8cGIkF53PVpI3tM-4taDdLQUbtH8fBAYYzN_4inws/s320/IMG_20181230_112631.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Mercury laden waters used to extract gold nodules&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXoKnyFznHM-WFvIOlok3CGw5EXmsfBUp5C7wvE3YWz4IJQtm-8Hkv9KjuW4RzcWYspMINjPgrW_81yQbx3iuG1wU9ZToD4aMmFcxQW0I9OeZh268M2yD_SlobSkCKFdGK3CmPzXHkHa4/s1600/IMG_20181230_111820.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;1200&quot; data-original-width=&quot;1600&quot; height=&quot;240&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXoKnyFznHM-WFvIOlok3CGw5EXmsfBUp5C7wvE3YWz4IJQtm-8Hkv9KjuW4RzcWYspMINjPgrW_81yQbx3iuG1wU9ZToD4aMmFcxQW0I9OeZh268M2yD_SlobSkCKFdGK3CmPzXHkHa4/s320/IMG_20181230_111820.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Sheds housing diesel engines and rock crushers for mining&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
Next day we took a side trip to Macalder gold mines. It was in interesting experience what people will do to earn a living in far flung places in the country. &lt;a href=&quot;http://cejadkenya.org/mercury-and-minamata-convention/mercury-use-in-artisanal-and-small-scale-gold-mining-asgm/&quot;&gt;Migori county&lt;/a&gt; is known for its high concentration of mercury in water. The operations here clearly explain why. Rocks are dug up from underground gold mine and manually broken up into smaller chunks and ground into dust using diesel operated octagonal drum crushers. The whole place is noisy. The dust is then filtered to remove solubles and then mixed with mercury to form &lt;a href=&quot;https://en.wikipedia.org/wiki/Amalgam_(chemistry)#Gold_amalgam&quot;&gt;gold amalgam&lt;/a&gt; nodule, women (some of whom were pregnant) then stir the mixture by hand to find gold bits. Mercury is then recovered by retorting in small ovens and reused. At least some work is being done to raise awareness of the harm from Mercury, hopefully sanity will prevail over economic incentives.&lt;br /&gt;
&lt;br /&gt;
We then continued our trip south towards Kenya Tanzania border and I will continue the story in another post.&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://whatnicklife.blogspot.com/feeds/9026837520301515018/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/3220006345447041404/9026837520301515018' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3220006345447041404/posts/default/9026837520301515018'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3220006345447041404/posts/default/9026837520301515018'/><link rel='alternate' type='text/html' href='http://whatnicklife.blogspot.com/2019/01/around-kenya-in-4-days-and-year.html' title='Around Kenya in 4 days and a year ( part 1)'/><author><name>Tisham Dhar</name><uri>http://www.blogger.com/profile/15154154153085427197</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEir1Qi3k3XyTm5BxCmKhZy-FSluP2XdcQ1Ro5yxpEVZWkSdkvG1ifkkzFmkb0Axd79wQziXaI9lXyU3P8V1sx97T0WDsrZe66IkU-gWuBessyapgFUxkgQaFQElxUv8ckuzzDJ9fPvm0Ck/s72-c/IMG_20181229_081444.jpg" height="72" width="72"/><thr:total>0</thr:total><georss:featurename>Christchurch, New Zealand</georss:featurename><georss:point>-43.5320544 172.63622540000006</georss:point><georss:box>-43.9005494 171.99077840000007 -43.1635594 173.28167240000005</georss:box></entry></feed>