<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Henri Bergius</title>
    <description>Hacker and an occasional adventurer. Author of Create.js and NoFlo, founder of Flowhub UG. Decoupling software, one piece at a time. This blog tells the story of that.</description>
    <link>https://bergie.iki.fi</link>
    <language>en</language>
    <lastBuildDate>Tue, 05 May 2026 19:17:08 +0000</lastBuildDate>
    
    <item>
      
      <title>Rigging-suspended installation of a marine wind generator</title>
      <description>&lt;p&gt;We cruise on a small boat, a &lt;a href=&quot;https://lille-oe.de/boat/&quot;&gt;31ft double-ender&lt;/a&gt;. As we’re off-grid the vast majority of the time, all electricity needs to be produced from renewable sources. Solar produces a lion’s share, but other sources are needed for overcast days. We don’t have space for a permanently mounted wind generator, so we converted a &lt;a href=&quot;https://www.superwind.com/en/&quot;&gt;Superwind 350&lt;/a&gt; to rigging-suspended.&lt;/p&gt;

&lt;h2 id=&quot;why-wind&quot;&gt;Why wind?&lt;/h2&gt;

&lt;p&gt;As our &lt;a href=&quot;https://lille-oe.de/2024/&quot;&gt;2024 cruise&lt;/a&gt; to the not-so-sunny Scotland demonstrated, there would still be place for wind power in the renewables mix of a long-distance sailboat. My &lt;a href=&quot;https://gist.github.com/bergie/d0eda471e3774b0cb3b49e33853394d1&quot;&gt;energy production simulations&lt;/a&gt; from 2023 also showed a lot of promise for wind power.&lt;/p&gt;

&lt;p&gt;Our boat has a canoe stern and dual aft stays, meaning that there is not much space in the back of the boat.
We had a conversation with Superwind back in 2022, and they were of the opinion that there simply isn’t a good space for installing one.
And so we &lt;a href=&quot;https://lille-oe.de/2023-04-14/&quot;&gt;installed a hydrogenerator&lt;/a&gt; and decided that we’d go sailing if we ran out of power.&lt;/p&gt;

&lt;p&gt;But the interest in wind generators remained.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://d2vqpl3tx84ay5.cloudfront.net/800x/20250125_172524.jpg&quot; alt=&quot;Ampair 100 at Sainte-Anne&quot; /&gt;&lt;/p&gt;

&lt;p&gt;And then one day, rowing around the Sainte-Anne anchorage in rainy Martinique, I saw a potential solution: one of the small cruising boats had a wind generator suspended from ropes in their foretriangle. I chatted a bit with the owners, and they confirmed that the system worked nicely. Time for some research!&lt;/p&gt;

&lt;h2 id=&quot;rigging-suspended-wind-generator&quot;&gt;Rigging-suspended wind generator&lt;/h2&gt;

&lt;p&gt;Rigging-suspended wind generators used to be common. Commercial models included the Ampair 100, WindBugger, and the Hamilton-Ferris. As solar power has become cheaper, wind generators in general have fallen out of favor. At the same time cruising boats have grown in size, enabling permanent mounting of a big wind turbine.&lt;/p&gt;

&lt;p&gt;These effects combined mean that there are currently no commercial manufacturers of rigging-suspended wind generators for boats.&lt;/p&gt;

&lt;p&gt;Of the models once manufactured, the Ampair 100 sounded especially promising. It was a modular system that could be used either as a rigging-suspended wind turbine, or as a “tow generator” for making power while under sail.&lt;/p&gt;

&lt;p&gt;This modularity is a big advantage of a rigging-suspended wind generator, especially for ease of stowing. They can also be a lot quieter than the pole-mounted ones, as any vibrations are dampened by the suspension ropes. And of course they don’t cause any windage or shading while stowed.&lt;/p&gt;

&lt;p&gt;I tried finding an Ampair for sale online with no luck. The second-hand chandlery in Grenada – &lt;a href=&quot;https://treasuretrove.shop&quot;&gt;Treasure Trove&lt;/a&gt; – had two units, but couldn’t locate the wind blades.&lt;/p&gt;

&lt;p&gt;However, the wind generator market has evolved quite a bit. There are several good wind generators intended for permanent mounting. &lt;a href=&quot;https://www.superwind.com/en/applications/sailing&quot;&gt;Superwind&lt;/a&gt; and the &lt;a href=&quot;https://eclectic-energy.co.uk/products/d400-wind-generator/&quot;&gt;D400&lt;/a&gt; provide the best alternatives, but are very expensive. On the cheap end, there are numerous Chinese wind generators from companies like &lt;a href=&quot;https://www.pikasola.com&quot;&gt;Pikasola&lt;/a&gt; and &lt;a href=&quot;https://www.vevor.com/s/wind-turbine&quot;&gt;Vevor&lt;/a&gt; starting at around $250.&lt;/p&gt;

&lt;p&gt;Maybe I could design a bracket to convert one of these for rigging-suspended installation?&lt;/p&gt;

&lt;h2 id=&quot;building-the-bracket&quot;&gt;Building the bracket&lt;/h2&gt;

&lt;p&gt;Sitting in the windy anchorage at Spanish Water this idea started sounding more and more interesting. After some paper brainstorming, I grabbed &lt;a href=&quot;https://www.freecad.org&quot;&gt;FreeCAD&lt;/a&gt; and made an initial design.&lt;/p&gt;

&lt;p&gt;The design parameters were:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Can be built somewhat cheaply by a local metal fabricator&lt;/li&gt;
  &lt;li&gt;Can facilitate the most common fixed-mount wind generators&lt;/li&gt;
  &lt;li&gt;Poles to keep the rigging lines clear of the propellers&lt;/li&gt;
  &lt;li&gt;Wind generator is held in place and the whole assembly turns into the wind&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My original idea was a neat stainless ring around the wind generator body. However, different wind generators are of different height, and so in interests of both manufacturing cost and adaptability, I went with two brackets connected by threaded rod.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://d2vqpl3tx84ay5.cloudfront.net/800x/wind-bracket.png&quot; alt=&quot;Wind turbine bracket design&quot; /&gt;&lt;/p&gt;

&lt;p&gt;It took a couple of months to actually get a quote from a local fabricator, but now we finally have the finished brackets for ourselves and a neighboring boat.&lt;/p&gt;

&lt;p&gt;You can find the FreeCAD file &lt;a href=&quot;https://github.com/meri-imperiumi/lille-oe/raw/refs/heads/main/hardware/Windgenerator%20bracket.FCStd&quot;&gt;on GitHub&lt;/a&gt;. There are also STEP files for the &lt;a href=&quot;https://github.com/meri-imperiumi/lille-oe/blob/main/hardware/Windgenerator%20bracket-AssemblyBracket%20top.step&quot;&gt;top bracket&lt;/a&gt; and the &lt;a href=&quot;https://github.com/meri-imperiumi/lille-oe/blob/main/hardware/Windgenerator%20bracket-AssemblyBracket%20bottom.step&quot;&gt;bottom bracket&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;installation&quot;&gt;Installation&lt;/h2&gt;

&lt;p&gt;Our neighbor installed a 400W Pikasola wind generator on theirs. That mounted on the bracket without any other adapting except for some rubber mat to isolate the stainless parts from the aluminium wind turbine body.&lt;/p&gt;

&lt;p&gt;We had bought an old Superwind 350 from another boat, and so for us a small connecting piece (140mm long aluminium pipe with 55mm inner diameter) was needed to make that fit.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://d2vqpl3tx84ay5.cloudfront.net/800x/20250807_125654.jpg&quot; alt=&quot;Wind generator bracket adapted for Superwind 350&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The wind generator is hoisted using our spinnaker pole topping lift, with a short strop riding on the inner forestay. Stabilization is with a three rope bridle connected to pad eyes on the deck.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://d2vqpl3tx84ay5.cloudfront.net/800x/20250809_085537.jpg&quot; alt=&quot;Deployed rigging-suspended Superwind 350&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We have wires running from the bottom bracket to the deck level, where they connect via MC4 connectors to to cables running to inside the boat. This way we can easily disconnect the wind turbine as needed. We are adding a stop/run switch soon as well to aid deployment.&lt;/p&gt;

&lt;p&gt;Deployment is already documented &lt;a href=&quot;https://handbook.lille-oe.de/systems/electrics/#superwind&quot;&gt;in our boat handbook&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;We only got the Superwind deployed yesterday evening, and so we are gathering the early experiences. However, right now we’re on track to producing about 0.6kWh on the first day. This is measured with a dedicated Victron SmartShunt wired to the wind generator regulator and logging into our time series database.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://d2vqpl3tx84ay5.cloudfront.net/800x/wind-generator-venus.jpg&quot; alt=&quot;Wind generator as seen in Venus OS&quot; /&gt;&lt;/p&gt;

&lt;p&gt;That 0.6kWh per day is like a whole second solar arch!&lt;/p&gt;

&lt;p&gt;Noise levels are not too bad at all. Inside the boat you can’t hear anything. In cockpit, you can hear a slight whirr from the generator, but it is a lot quieter than one of the popular pole-mounted wind turbines on neighboring boat, heard from few hundred meters away.&lt;/p&gt;

&lt;p&gt;Durability and handling of heavier winds will remain to be seen. As will the practicality of stowing and deploying when changing anchorages. Though we already do similar things with the mast-hoisted solar panels and the &lt;a href=&quot;https://lille-oe.de/dinghy/&quot;&gt;nesting dinghy&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Especially when going with one of the cheap Chinese models, this rigging-suspended method can be the way to add wind power to a boat in an affordable way. We calculated the total price for the Pikasola installation to be around the same as what marine wind generator manufacturers ask for just a mounting pole!&lt;/p&gt;

&lt;p&gt;The &lt;a href=&quot;https://github.com/meri-imperiumi/lille-oe/tree/main/hardware&quot;&gt;hardware design&lt;/a&gt; should be quite easy to manufacture anywhere where you can find a stainless steel welder. After all, we were able to get ours fabricated on a tropical island.&lt;/p&gt;

&lt;p&gt;For us the new wind generator can be seen as completing the circle of our deployable renewable options:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;When under sail, power is generated with the hydrogenerator&lt;/li&gt;
  &lt;li&gt;When anchored in light winds, power is generated with the mast-hoisted &lt;a href=&quot;https://flin-solar.com&quot;&gt;FLINsail&lt;/a&gt; solar array&lt;/li&gt;
  &lt;li&gt;When anchored in heavier winds, power is generated by the rigging-suspended Superwind&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On top of these we have the fixed solar panels.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://d2vqpl3tx84ay5.cloudfront.net/800x/20250807_200722.jpg&quot; alt=&quot;Lille Ø at anchor&quot; /&gt;&lt;/p&gt;
</description>
      <pubDate>Sat, 09 Aug 2025 00:00:00 +0000</pubDate>
      <atom:link rel="payment" href="https://flattr.com/submit/auto?url=https%3A%2F%2Fbergie.iki.fi%2Fblog%2Frigging-suspended-wind-generator%2F&amp;user_id=bergie" type="text/html" />
      <link>https://bergie.iki.fi/blog/rigging-suspended-wind-generator/</link>
      <guid isPermaLink="true">https://bergie.iki.fi/blog/rigging-suspended-wind-generator/</guid>
      <author>henri.bergius@iki.fi (Henri Bergius)</author>
    </item>
  
    <item>
      
      <title>Mobile blogging, the past and the future</title>
      <description>&lt;p&gt;This blog has been running more or less continuously since mid-nineties. The site has existed in multiple forms, and with different ways to publish. But what’s common is that at almost all points there was a mechanism to publish while on the move.&lt;/p&gt;

&lt;h2 id=&quot;psion-documents-over-ftp&quot;&gt;Psion, documents over FTP&lt;/h2&gt;

&lt;p&gt;In the early 2000s we were into adventure motorcycling. To be able to share our adventures, we implemented a way to publish blogs while on the go. The device that enabled this was the &lt;a href=&quot;https://en.wikipedia.org/wiki/Psion_Series_5&quot;&gt;Psion Series 5&lt;/a&gt;, a handheld computer that was very much a device ahead of its time.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://d2vqpl3tx84ay5.cloudfront.net/psions5.jpg&quot; alt=&quot;Psion S5, also known as the Ancestor&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The Psion had a reasonably sized keyboard and a good native word processing app. And battery life good for weeks of usage. Writing while underway was easy. The Psion could use a mobile phone as a modem over an infrared connection, and with that we could upload the documents to a server over FTP.&lt;/p&gt;

&lt;p&gt;Server-side, a cron job would grab the new documents, converting them to HTML and adding them to our CMS.&lt;/p&gt;

&lt;p&gt;In the early days of GPRS, getting this to work while roaming was quite tricky. But the system served us well for years.&lt;/p&gt;

&lt;p&gt;If we wanted to include photos to the stories, we’d have to find an Internet cafe.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://bergie.iki.fi/blog/to-to-alps/&quot;&gt;To the Alps&lt;/a&gt; is a post from these times. Lots more in the &lt;a href=&quot;http://bergie.iki.fi/blog/category/motorcycles/&quot;&gt;motorcycling category&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;sms-and-mms&quot;&gt;SMS and MMS&lt;/h2&gt;

&lt;p&gt;For an even more mobile setup, I implemented an SMS-based blogging system. We had an old phone connected to a computer back in the office, and I could write to my blog by simply sending a text. These would automatically end up as a new paragraph in the latest post. If I started the text with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NEWPOST&lt;/code&gt;, an empty blog post would be created with the rest of that message’s text as the title.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://bergie.iki.fi/blog/in-the-caucasus/&quot;&gt;In the Caucasus&lt;/a&gt; is a good example of a post from this era&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As I got into &lt;a href=&quot;http://bergie.iki.fi/blog/category/geo/&quot;&gt;neogeography&lt;/a&gt;, I could also send a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NEWPOSITION&lt;/code&gt; message. This would update my position on the map, connecting weather metadata to the posts.&lt;/p&gt;

&lt;p&gt;As camera phones became available, we wanted to do pictures too. For the Death Monkey rally where we rode minimotorcycles from Helsinki to Gibraltar, we implemented an MMS-based system. With that the entries could include both text and pictures. But for that you needed a gateway, which was really only realistic for an event with sponsors.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://web.archive.org/web/20061013183009/http://www.deathmonkey.org/view/mystery-of-the-missing-monkey.html&quot;&gt;Mystery of the Missing Monkey&lt;/a&gt; is typical. Some more in &lt;a href=&quot;https://web.archive.org/web/20060804205237/http://www.deathmonkey.org/&quot;&gt;Internet Archive&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;photos-over-email&quot;&gt;Photos over email&lt;/h2&gt;

&lt;p&gt;A much easier setup than MMS was to slightly come back to the old Psion setup, but instead of word documents, sending email with picture attachments. This was something that the new breed of (pre-iPhone) smartphones were capable of. And by now the roaming question was mostly sorted.&lt;/p&gt;

&lt;p&gt;And so my blog included a new “moblog” section. This is where I could share my daily activities as poor-quality pictures. Sort of how people would use Instagram a few years later.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://d2vqpl3tx84ay5.cloudfront.net/bergie_layout_2006.jpg&quot; alt=&quot;My blog from that era&quot; /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://web.archive.org/web/20110604011733/http://bergie.iki.fi/moblog&quot;&gt;Internet Archive has some of my old moblogs&lt;/a&gt; but nowadays, I post similar stuff &lt;a href=&quot;https://pixelfed.de/bergie&quot;&gt;on Pixelfed&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;pause&quot;&gt;Pause&lt;/h2&gt;

&lt;p&gt;Then there was sort of a long pause in mobile blogging advancements. Modern smartphones, data roaming, and WiFi hotspots had become ubiquitous.&lt;/p&gt;

&lt;p&gt;In the meanwhile the blog also got &lt;a href=&quot;http://bergie.iki.fi/blog/blog-2012-edition/&quot;&gt;migrated to a Jekyll-based system&lt;/a&gt; hosted on AWS. That means the old Midgard-based integrations were off the table.&lt;/p&gt;

&lt;p&gt;And I traveled off-the-grid rarely enough that it didn’t make sense to develop a system.&lt;/p&gt;

&lt;p&gt;But now that we’re &lt;a href=&quot;https://lille-oe.de&quot;&gt;sailing offshore&lt;/a&gt;, that has changed. Time for new systems and new ideas. Or maybe just a rehash of the old ones?&lt;/p&gt;

&lt;h2 id=&quot;starlink-internet-from-outer-space&quot;&gt;Starlink, Internet from Outer Space&lt;/h2&gt;

&lt;p&gt;Most cruising boats - ours included - now run the Starlink satellite broadband system. This enables full Internet, even in the middle of an ocean, even video calls! With this, we can use normal blogging tools. The usual one for us is &lt;a href=&quot;https://gitjournal.io&quot;&gt;GitJournal&lt;/a&gt;, which makes it easy to write Jekyll-style Markdown posts and push them to GitHub.&lt;/p&gt;

&lt;p&gt;However, Starlink is a complicated, energy-hungry, and fragile system on an offshore boat. The policies might change at any time preventing our way of using it, and also the dishy itself, or the way we power it may fail.&lt;/p&gt;

&lt;p&gt;But despite what you’d think, even on a nerdy boat like ours, loss of Internet connectivity is not an emergency. And this is where the old-style mobile blogging mechanisms come handy.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Any of the &lt;a href=&quot;https://lille-oe.de/2025/&quot;&gt;2025 Atlantic crossing posts&lt;/a&gt; is a good example of this setup in action&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;inreach-texting-with-the-cloud&quot;&gt;Inreach, texting with the cloud&lt;/h2&gt;

&lt;p&gt;Our backup system to Starlink is the Garmin Inreach. This is a tiny battery-powered device that connects to the Iridium satellite constellation. It allows tracking as well as basic text messaging.&lt;/p&gt;

&lt;p&gt;When we head offshore we always enable tracking on the Inreach. This allows both our blog and our friends ashore to follow our progress.&lt;/p&gt;

&lt;p&gt;I also made a simple integration where text updates sent to &lt;a href=&quot;https://share.garmin.com/home&quot;&gt;Garmin MapShare&lt;/a&gt; get fetched and published on our blog. Right now this is just plain text-based entries, but one could easily implement a command system similar to what I had over SMS back in the day.&lt;/p&gt;

&lt;p&gt;One benefit of the Inreach is that we can also take it with us when we go on land adventures. And it’d even enable rudimentary communications if we found ourselves in a liferaft.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;There are &lt;a href=&quot;https://github.com/tabeaeggler/MarineGRIB-InReach-Transmitter&quot;&gt;various InReach integration hacks&lt;/a&gt; that could be used for more sophisticated data transfer&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;sailmail-and-email-over-hf-radio&quot;&gt;Sailmail and email over HF radio&lt;/h2&gt;

&lt;p&gt;The other potential backup for Starlink failures would be to go seriously old-school. It is possible to get email access via a SSB radio and a Pactor (or &lt;a href=&quot;https://rosmodem.wordpress.com&quot;&gt;Vara&lt;/a&gt;) modem.&lt;/p&gt;

&lt;p&gt;Our boat is already equipped with an isolated aft stay that can be used as an antenna. And with the popularity of Starlink, many cruisers are offloading their old HF radios.&lt;/p&gt;

&lt;p&gt;Licensing-wise this system could be used either as a marine HF radio (requiring a Long Range Certificate), or amateur radio. So that part is something I need to work on. Thankfully post-COVID, radio amateur license exams can be done online.&lt;/p&gt;

&lt;p&gt;With this setup we could send and receive text-based email. The &lt;a href=&quot;https://sailmail.com&quot;&gt;Airmail&lt;/a&gt; application used for this can even do some automatic templating for position reports. We’d then need a mailbox that can receive these mails, and some automation to fetch and publish.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.sailblogs.com/wiki/index.php/Using_SailBlogs_Remote&quot;&gt;Sailmail&lt;/a&gt; and &lt;a href=&quot;https://www.noforeignland.com/help/boat/move-email&quot;&gt;No Foreign Land&lt;/a&gt; support structured data via email to update position. Their formats could be useful inspiration&lt;/li&gt;
&lt;/ul&gt;
</description>
      <pubDate>Thu, 05 Jun 2025 00:00:00 +0000</pubDate>
      <atom:link rel="payment" href="https://flattr.com/submit/auto?url=https%3A%2F%2Fbergie.iki.fi%2Fblog%2Fmobile-blogging%2F&amp;user_id=bergie" type="text/html" />
      <link>https://bergie.iki.fi/blog/mobile-blogging/</link>
      <guid isPermaLink="true">https://bergie.iki.fi/blog/mobile-blogging/</guid>
      <author>henri.bergius@iki.fi (Henri Bergius)</author>
    </item>
  
    <item>
      
      <title>Flow-Based Programming, a way for AI and humans to develop together</title>
      <description>&lt;p&gt;I think by now everybody reading this will have seen how the new generation of &lt;a href=&quot;https://en.wikipedia.org/wiki/Large_language_model&quot;&gt;Large Language Models&lt;/a&gt; like ChatGPT are able to produce &lt;a href=&quot;https://tylerglaiel.substack.com/p/can-gpt-4-actually-write-code&quot;&gt;somewhat useful code&lt;/a&gt;. Like any advance in software development—from IDEs to high-level languages—this has generated some discussion on the future employment prospects in our field.&lt;/p&gt;

&lt;p&gt;This made me think about how these new tools could fit the world of &lt;a href=&quot;https://en.wikipedia.org/wiki/Flow-based_programming&quot;&gt;Flow-Based Programming&lt;/a&gt;, a software development technique I’ve been involved with for quite a while. In Flow-Based Programming these is a very strict boundary between reusable “library code” (called &lt;em&gt;Components&lt;/em&gt;) and the “application logic” (called the &lt;em&gt;Graph&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;Here’s what the late &lt;a href=&quot;https://jpaulm.github.io&quot;&gt;J. Paul Morrison&lt;/a&gt; wrote on the subject in his seminal work, &lt;em&gt;Flow-Based Programming: A New Approach to Application Development&lt;/em&gt; (2010):&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Just as in the preparation and consumption of food there are the two roles of cook and diner, in FBP application development there are two distinct roles: the component builder and the component user or application designer.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;…The application designer builds applications using already existing components, or where satisfactory ones do not exist s/he will specify a new component, and then see about getting it built.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Remembering that passage made me wonder, could I get one of the LLMs to produce useful &lt;a href=&quot;https://noflojs.org&quot;&gt;NoFlo&lt;/a&gt; components? Armed with &lt;a href=&quot;https://www.bing.com/new&quot;&gt;New Bing&lt;/a&gt;, I set out to explore.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://d2vqpl3tx84ay5.cloudfront.net/800x/b8c302b0-c698-11ed-8b42-09bd596b6d87Robot%20software.png&quot; alt=&quot;AI and humans working together&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The first attempt was specifying a pretty simple component:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://d2vqpl3tx84ay5.cloudfront.net/800x/new-bing-noflo-component.png&quot; alt=&quot;New Bing writing a component&quot; /&gt;&lt;/p&gt;

&lt;p&gt;That actually looks quite reasonable! I also tried asking New Bing to make the component less verbose, as well as generating TypeScript and CoffeeScript variants of the same. All seemed to produce workable things! Sure, there might be some tidying to do, but this could remove a lot of the tedium of component creation.&lt;/p&gt;

&lt;p&gt;In addition to this trivial math component I was able to generate some that to call external REST APIs etc. Bing was even able to switch between HTTP libraries as requested.&lt;/p&gt;

&lt;p&gt;What was even cooler was that it actually &lt;em&gt;suggested&lt;/em&gt; to ask it how to &lt;em&gt;test the component&lt;/em&gt;. Doing as I was told, the result was quite astonishing:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://d2vqpl3tx84ay5.cloudfront.net/800x/new-bing-fbp-spec.png&quot; alt=&quot;New Bing writing fbp-spec tests&quot; /&gt;&lt;/p&gt;

&lt;p&gt;That’s &lt;a href=&quot;https://github.com/flowbased/fbp-spec&quot;&gt;fbp-spec&lt;/a&gt;! The declarative testing tool we came up with! Definitely the nicest way to test NoFlo (or any other FBP framework) components.&lt;/p&gt;

&lt;p&gt;Based on my results, you’ll definitely want to check the generated components and tests before running them. But what you get out is not bad at all.&lt;/p&gt;

&lt;p&gt;I of course also tried to get Bing to produce NoFlo graphs for me. This is where it stumbled quite a bit. Interestingly the results were better in the &lt;a href=&quot;https://github.com/flowbased/fbp#language-for-flow-based-programming&quot;&gt;fbp language&lt;/a&gt; than in the JSON graph format. But maybe that even more enforces that the &lt;em&gt;sweet spot would be AI writing components and a human creating the graphs that run those&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://d2vqpl3tx84ay5.cloudfront.net/800x/28a14660-c698-11ed-8b42-09bd596b6d87Robot%20software.png&quot; alt=&quot;AI and humans working together&quot; /&gt;&lt;/p&gt;

&lt;p&gt;As I’m not working at the moment, I don’t have a current use case for this way of collaborating. But I believe this could be a huge productivity booster for any (and especially Flow-Based) application development, and expect to try it in whatever my next gig ends up being.&lt;/p&gt;

&lt;p&gt;&lt;small&gt;Illustrations: MidJourney, from prompt &lt;em&gt;Robot software developer working with a software architect. Floating flowcharts in the background&lt;/em&gt;&lt;/small&gt;&lt;/p&gt;
</description>
      <pubDate>Mon, 20 Mar 2023 00:00:00 +0000</pubDate>
      <atom:link rel="payment" href="https://flattr.com/submit/auto?url=https%3A%2F%2Fbergie.iki.fi%2Fblog%2Ffbp-ai-human-collaboration%2F&amp;user_id=bergie" type="text/html" />
      <link>https://bergie.iki.fi/blog/fbp-ai-human-collaboration/</link>
      <guid isPermaLink="true">https://bergie.iki.fi/blog/fbp-ai-human-collaboration/</guid>
      <author>henri.bergius@iki.fi (Henri Bergius)</author>
    </item>
  
    <item>
      
      <title>Keeping a semi-automatic electronic ship's logbook</title>
      <description>&lt;p&gt;Maintaining a proper &lt;a href=&quot;https://en.wikipedia.org/wiki/Logbook_(nautical)&quot;&gt;ship’s logbook&lt;/a&gt; is something that most boats should do, for practical, as well as legal and traditional reasons. The logbook can serve as a record of proper maintenance and operation of the vessel, which is potentially useful when selling the boat or handling an insurance claim. It can be a fun record of journeys made to look back to. And it can be a crucial aid for getting home if the ship’s electronics or GNSS get disrupted.&lt;/p&gt;

&lt;p&gt;Like probably most operators of a small boat, &lt;a href=&quot;https://lille-oe.de&quot;&gt;on &lt;em&gt;Lille Ø&lt;/em&gt;&lt;/a&gt; our logbook practices have been quite varying. We’ve been good at recording engine maintenance, as well as keeping the traditional navigation log while offshore. But in the more hectic pace of coastal cruising or daysailing this has often fallen on the wayside. And as such, a lot of the events and history of the boat is unavailable.&lt;/p&gt;

&lt;p&gt;To redeem this I’ve developed &lt;a href=&quot;https://www.npmjs.com/package/@meri-imperiumi/signalk-logbook&quot;&gt;signalk-logbook&lt;/a&gt;, a semi-automatic electronic logbook for vessels running the &lt;a href=&quot;https://signalk.org&quot;&gt;Signal K&lt;/a&gt; marine data server.&lt;/p&gt;

&lt;p&gt;This allows logbook entries to be produced both manually and automatically. The can be viewed and edited using any web-capable device on board, meaning that you can write a log entry on your phone, and maybe later analyse and print them on your laptop.&lt;/p&gt;

&lt;h2 id=&quot;why-signal-k&quot;&gt;Why Signal K&lt;/h2&gt;

&lt;p&gt;Signal K is a marine data server that has integrations with almost any relevant marine electronics system. If you have an older NMEA0183 or Seatalk system, Signal K can communicate with it. Same with NMEA2000. If you already have your navigational data on the boat WiFi, Signal K can use and enrich it.&lt;/p&gt;

&lt;p&gt;This means that by making the logbook a Signal K plugin, I didn’t have to do any work to make it work with existing boat systems. Signal K even provides a user interface framework.&lt;/p&gt;

&lt;p&gt;This means that to make the electronic logbook happen, I only had to produce &lt;a href=&quot;https://github.com/meri-imperiumi/signalk-logbook/tree/main/plugin&quot;&gt;some plugin JavaScript&lt;/a&gt;, and then build a user interface. As I don’t do front-end development that frequently, this gave me a chance to dive into modern &lt;a href=&quot;https://reactjs.org/docs/hooks-intro.html&quot;&gt;React with hooks&lt;/a&gt; for the first time. What better to do after being laid off?&lt;/p&gt;

&lt;p&gt;Signal K also has very good integration with &lt;a href=&quot;https://www.influxdata.com/&quot;&gt;Influx&lt;/a&gt; and &lt;a href=&quot;https://grafana.com&quot;&gt;Grafana&lt;/a&gt;. These can record vessel telemetry in a high resolution. So why bother with a logbook on the side? In my view, a separate logbook is still valuable for storing the comments and observations not available in a marine sensor network. It can also be a lot more durable and archivable than a time series database. On &lt;a href=&quot;https://lille-oe.de&quot;&gt;&lt;em&gt;Lille Ø&lt;/em&gt;&lt;/a&gt; we run both.&lt;/p&gt;

&lt;h2 id=&quot;user-interface&quot;&gt;User interface&lt;/h2&gt;

&lt;p&gt;The signalk-logbook comes with a reasonably simple web-based user interface that is integrated in the Signal K administration UI. You can find it in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Web apps&lt;/code&gt; → &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Logbook&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The primary view is a timeline. Sort of “Twitter for your boat” kind of view that allows quick browsing of entries on both desktop and mobile.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://d2vqpl3tx84ay5.cloudfront.net/800x/logbook-timeline.png&quot; alt=&quot;Logbook timeline view&quot; /&gt;&lt;/p&gt;

&lt;p&gt;There is also the more traditional tabular view, best utilized on bigger screens:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://d2vqpl3tx84ay5.cloudfront.net/800x/logbook-logbook.png&quot; alt=&quot;Logbook timeline view&quot; /&gt;&lt;/p&gt;

&lt;p&gt;While the system can produce a lot of the entries automatically, it is also easy to create manual entries:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://d2vqpl3tx84ay5.cloudfront.net/800x/logbook-new.png&quot; alt=&quot;Adding an entry&quot; /&gt;&lt;/p&gt;

&lt;p&gt;These entries can also include weather observations. Those using celestial navigation can also record manual fixes with these entries! Entries can be categorized to separate things like navigational entries from radio or maintenance logs.&lt;/p&gt;

&lt;p&gt;If you have the &lt;a href=&quot;https://www.npmjs.com/package/@signalk/sailsconfiguration&quot;&gt;sailsconfiguration plugin&lt;/a&gt; installed, you can also log sail changes in a machine-readable format:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://d2vqpl3tx84ay5.cloudfront.net/800x/logbook-sails.png&quot; alt=&quot;Sail changes editor&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Since the log format is machine readable, the map view allows browsing entries spatially:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://d2vqpl3tx84ay5.cloudfront.net/800x/logbook-map.png&quot; alt=&quot;Log entries on a map&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;electronic-vs-paper&quot;&gt;Electronic vs. paper&lt;/h2&gt;

&lt;p&gt;The big benefits of an electronic logbook are automation and availability. The logbook can create entries by itself based on what’s happening with the vessel telemetry. You can read and create log entries anywhere on the boat, using the electronic devices you carry with you. Off-vessel backups are also both possible, and quite easy, assuming that the vessel has a reasonably constant Internet connection.&lt;/p&gt;

&lt;p&gt;With paper logbooks, the main benefit is that they’re fully independent of the vessel’s electronic system. In case of power failure, you can still see the last recoded position, heading, etc. They are also a lot more durable in the sense that paper logbooks from centuries ago are still fully readable. Though obviously that carries a strong &lt;a href=&quot;https://en.wikipedia.org/wiki/Survivorship_bias&quot;&gt;survivorship bias&lt;/a&gt;. I would guess the vast majority of logbooks, especially on smaller non-commercial vessels, don’t survive more than a couple of years.&lt;/p&gt;

&lt;p&gt;So, how to benefit from the positive aspects of electronic logbooks, while reducing the negatives when compared to paper? Here are some ideas:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;em&gt;Mark your position on a paper chart&lt;/em&gt;. Even though most boats navigate with only electronic charts, it is a good idea to have at least a planning chart available on paper. When offshore, plot your hourly or daily position on it. This will produce the navigation aid of last resort if all electronics fail. And marked charts are pretty!&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Have an off-vessel backup of your electronic logs&lt;/em&gt;. The signalk-logbook uses &lt;a href=&quot;https://github.com/meri-imperiumi/signalk-logbook#data-storage-and-format&quot;&gt;a very simple plain text format&lt;/a&gt; for its entries exactly for this reason. The logs are easy to back up, and can also be utilized without the software itself. This means that with a bit of care your log entries shouls stay readable for many many years to come. On Lille Ø we store them &lt;a href=&quot;https://github.com/meri-imperiumi/log/tree/main/_data/logbook&quot;&gt;on GitHub&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Print your logs&lt;/em&gt;. With something like a cheap receipt printer, it would be possible to print your log entries periodically, maybe daily or after each trip. Then you can have an archival copy that doesn’t rely on electronics. &lt;a href=&quot;https://github.com/meri-imperiumi/logbook-printer&quot;&gt;Here is a repository&lt;/a&gt; implementing just that&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;api&quot;&gt;API&lt;/h2&gt;

&lt;p&gt;In addition to providing a web-based user interface, signalk-logbook &lt;a href=&quot;https://editor.swagger.io/?url=https://raw.githubusercontent.com/meri-imperiumi/signalk-logbook/main/schema/openapi.yaml&quot;&gt;provides a REST API&lt;/a&gt;. This allows software developers to create new integrations with the logbook. For example, these could include:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Automations to generate log entries for some events via &lt;a href=&quot;https://nodered.org/&quot;&gt;node-red&lt;/a&gt; or &lt;a href=&quot;https://noflojs.org&quot;&gt;NoFlo&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Copying the log entries to a cloud service&lt;/li&gt;
  &lt;li&gt;Exporting the logs to another format, like &lt;a href=&quot;https://en.wikipedia.org/wiki/GPS_Exchange_Format&quot;&gt;GPX&lt;/a&gt; or a spreadsheet&lt;/li&gt;
  &lt;li&gt;Other, maybe non-web-based user interfaces for browsing and creating log entries&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;getting-started&quot;&gt;Getting started&lt;/h2&gt;

&lt;p&gt;To utilize this electronic logbook, you need a working installation of &lt;a href=&quot;https://signalk.org&quot;&gt;Signal K&lt;/a&gt; on your boat. The common way to do this is by having a &lt;a href=&quot;https://www.raspberrypi.com&quot;&gt;Raspberry Pi&lt;/a&gt; powered by the boat’s electrical system and connected to the various on-board instruments.&lt;/p&gt;

&lt;p&gt;There are some nice solutions for this:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://shop.hatlabs.fi/products/sh-rpi&quot;&gt;Sailor Hat for Raspberry Pi&lt;/a&gt; allows powering a Raspberry Pi from the boat’s 12V system. It also handles shutdowns in a clean way, protecting the memory card from data corruption&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://seabits.com/nmea-2000-powered-raspberry-pi/&quot;&gt;Pican-M&lt;/a&gt; both connects a Raspberry Pi to a NMEA2000 bus, and powers it through that&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can of course also do a more custom setup, like we &lt;a href=&quot;https://bergie.iki.fi/blog/signalk-boat-iot/&quot;&gt;did on our old boat&lt;/a&gt;, &lt;em&gt;Curiosity&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;For the actual software setup, &lt;a href=&quot;https://github.com/tkurki/marinepi-provisioning&quot;&gt;marinepi-provisioning&lt;/a&gt; gives a nice Ansible playbook for getting everything going. &lt;a href=&quot;https://bareboat-necessities.github.io&quot;&gt;Bareboat Necessities&lt;/a&gt; is a “Marine OS for Raspberry Pi” that comes with everything included.&lt;/p&gt;

&lt;p&gt;If you have a Victron GX device (for example Cerbo GX), you can also &lt;a href=&quot;https://www.victronenergy.com/live/venus-os:large&quot;&gt;install Signal K on that&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once Signal K is running, just look up &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;signalk-logbook&lt;/code&gt; in the Signal K app store. You’ll also want to install the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;signalk-autostate&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sailsconfiguration&lt;/code&gt; plugins to enable some of the automations.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://d2vqpl3tx84ay5.cloudfront.net/800x/logbook-appstore.png&quot; alt=&quot;Signal K appstore&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Then just restart Signal K, log in, and start logging!&lt;/p&gt;
</description>
      <pubDate>Mon, 06 Mar 2023 00:00:00 +0000</pubDate>
      <atom:link rel="payment" href="https://flattr.com/submit/auto?url=https%3A%2F%2Fbergie.iki.fi%2Fblog%2Felectronic-logbook%2F&amp;user_id=bergie" type="text/html" />
      <link>https://bergie.iki.fi/blog/electronic-logbook/</link>
      <guid isPermaLink="true">https://bergie.iki.fi/blog/electronic-logbook/</guid>
      <author>henri.bergius@iki.fi (Henri Bergius)</author>
    </item>
  
    <item>
      
      <title>Shakedown cruise on the Baltic Sea</title>
      <description>&lt;p&gt;Just in time for a new cruising season to start, the story of our &lt;a href=&quot;https://meri-imperiumi.github.io/log/2021/&quot;&gt;2021 Baltic shakedown cruise&lt;/a&gt; is now online.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://d2vqpl3tx84ay5.cloudfront.net/500x/20210827_105504.jpg&quot; alt=&quot;In Swedish archipelago&quot; /&gt; &lt;img src=&quot;https://d2vqpl3tx84ay5.cloudfront.net/500x/20210903_140900.jpg&quot; alt=&quot;Sailing in the Baltic&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This was a 666NM trip that we did on our new-to-us &lt;a href=&quot;https://meri-imperiumi.github.io/log/boat/&quot;&gt;Amigo 40 cruising boat&lt;/a&gt; in August-September 2021. Apart from engine trouble in the beginning, this was a very enjoyable little adventure on the coasts of Sweden and Bornholm.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://d2vqpl3tx84ay5.cloudfront.net/800x/baltic-sea-shakedown-2021.jpg&quot; alt=&quot;Trip route&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The trip even earned us the first prize in the cruising log contest of &lt;a href=&quot;https://scgothia.de&quot;&gt;our sailing club&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://d2vqpl3tx84ay5.cloudfront.net/500x/20220406_123935.jpg&quot; alt=&quot;Fartenseglerpreise&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://meri-imperiumi.github.io/log/2021/&quot;&gt;Read the story now&lt;/a&gt;.&lt;/p&gt;
</description>
      <pubDate>Thu, 07 Apr 2022 00:00:00 +0000</pubDate>
      <atom:link rel="payment" href="https://flattr.com/submit/auto?url=https%3A%2F%2Fbergie.iki.fi%2Fblog%2Fbaltic-shakedown-cruise%2F&amp;user_id=bergie" type="text/html" />
      <link>https://bergie.iki.fi/blog/baltic-shakedown-cruise/</link>
      <guid isPermaLink="true">https://bergie.iki.fi/blog/baltic-shakedown-cruise/</guid>
      <author>henri.bergius@iki.fi (Henri Bergius)</author>
    </item>
  
    <item>
      
      <title>Cruising sailboat electronics setup with Signal K</title>
      <description>&lt;p&gt;I haven’t mentioned this on the blog earlier, but in the end of 2018 we bought a small cruising sailboat. After some looking, we went with a &lt;a href=&quot;http://www.stadtdesign.com/&quot;&gt;Van de Stadt&lt;/a&gt; designed &lt;a href=&quot;https://sailboatdata.com/sailboat/oceaan-25&quot;&gt;Oceaan 25&lt;/a&gt;, a Dutch pocket cruiser from the early 1980s. &lt;em&gt;S/Y Curiosity&lt;/em&gt; is an affordable and comfortable boat for cruising with 2-4 people, but also needed major maintenance work.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://d2vqpl3tx84ay5.cloudfront.net/800x/curiosity-sailing-royal-louise.jpg&quot; alt=&quot;Curiosity sailing on Havel with Royal Louise&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The refit has so far included osmosis repair, some fixes to the standing rigging, engine maintenance, and many structural improvements. But this post will focus on the electronics and navigation aspects of the project.&lt;/p&gt;

&lt;h2 id=&quot;12v-power&quot;&gt;12V power&lt;/h2&gt;

&lt;p&gt;When we got it, the boat’s electrics setup was quite barebones. There was a small lead-acid battery, charged only when running the outboard. Light control was pretty much all-or-nothing, either we were running inside and navigation lights, or not. Everything was wired with 80s spec components, using energy-inefficient lightbulbs.&lt;/p&gt;

&lt;p&gt;Looking at the state of the setup, it was also unclear when the electrics had been used for anything else than starting the engine last time.&lt;/p&gt;

&lt;p&gt;Before going further with the electronics setup, all of this would have to be rebuilt. We made a plan, and scheduled two weekends in summer 2019 for rewiring and upgrading the electricity setup of the boat.&lt;/p&gt;

&lt;p&gt;First step was to test all existing wiring with a multimeter, and label and document all of it. Surprisingly, there were only couple of bad connections from the main distribution panel to consumers, so for most part we decided to reuse that wiring, but just with a modern terminal block setup.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://d2vqpl3tx84ay5.cloudfront.net/800x/curiosity-rewiring-terminal.jpg&quot; alt=&quot;All wires labeled and being reconnected&quot; /&gt;&lt;/p&gt;

&lt;p&gt;For most part we used a dymo label printer, with the labels covered with a transparent heat shrink.&lt;/p&gt;

&lt;p&gt;We replaced the old main control panel with a modern one with the capability to power different parts of the boat separately, and added some 12V and USB sockets next to it.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://d2vqpl3tx84ay5.cloudfront.net/800x/curiosity-battery-charger.jpg&quot; alt=&quot;New battery charger and voltmeter&quot; /&gt;&lt;/p&gt;

&lt;p&gt;All internal lighting was replaced with energy-efficient LEDs, and we added the option of using red lights all through the cabin for preserving night vision. A car charger was added to the system for easier battery charging while in harbour.&lt;/p&gt;

&lt;h3 id=&quot;next-steps-for-power&quot;&gt;Next steps for power&lt;/h3&gt;

&lt;p&gt;With this, we had a workable lighting and power setup for overnight sailing. But next obvious step will be to increase the range of our boat.&lt;/p&gt;

&lt;p&gt;For that, we’re adding a solar panel. We already have most parts for the setup, but are still waiting for the customized &lt;a href=&quot;http://www.noa.se/en/&quot;&gt;NOA mounting hardware&lt;/a&gt; to arrive. And of course the current &lt;a href=&quot;https://allaboutberlin.com/guides/coronavirus&quot;&gt;COVID-19 curfews&lt;/a&gt; need to lift before we can install it.&lt;/p&gt;

&lt;p&gt;Until we have actual data from our &lt;a href=&quot;https://www.victronenergy.com/solar-charge-controllers/smartsolar-mppt-75-10-75-15-100-15-100-20&quot;&gt;Victron MPPT&lt;/a&gt; charge controller, I’ve run some simulations using NASA’s insolation data for Berlin on how much the panel ought to increase our cruising range.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://d2vqpl3tx84ay5.cloudfront.net/800x/curiosity-100w-solar-estimate.png&quot; alt=&quot;Range estimates for Curiosity solar setup&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;navigation-system&quot;&gt;Navigation system&lt;/h2&gt;

&lt;p&gt;The basis for boat navigation is still the combination of a clock, a compass, and a paper chart (as well as a sextant on the open ocean). However, most modern cruising boats utilize some electrical tools to aid the process of running the boat. These typically come in form a chartplotter and a set of sensors to get things like GPS position, speed, and the water depth.&lt;/p&gt;

&lt;p&gt;Commercial marine navigation equipment is a bit like computer networking in the 90s - everything is expensive, and you pretty much have to buy the whole kit from a single vendor to make it work. Standards like &lt;a href=&quot;https://en.wikipedia.org/wiki/NMEA_0183&quot;&gt;NMEA 0183&lt;/a&gt; exist, but “embrace and extend” is typical vendor behaviour.&lt;/p&gt;

&lt;h3 id=&quot;signal-k&quot;&gt;Signal K&lt;/h3&gt;

&lt;p&gt;Being open source &lt;a href=&quot;https://c-base.org/&quot;&gt;hackerspace&lt;/a&gt; people, that was obviously not the way we wanted to do things. Instead of getting locked into an expensive proprietary single-vendor marine instrumentation setup, we decided to roll our own using off-the-shelf IoT components. To serve as the heart of the system, we picked &lt;a href=&quot;http://signalk.org/&quot;&gt;Signal K&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Signal K is first of all &lt;a href=&quot;https://signalk.org/specification/1.4.0/doc/&quot;&gt;a specification&lt;/a&gt; on how marine instruments can exchange data. It also has an open source implementation in Node.js. This allows piping in data from all of the relevant marine data buses, as well as setting up custom data providers. Signal K then harmonizes the data, and makes it available both via modern web APIs, and in traditional NMEA formats. This enables instruments like chartplotters also to utilize the Signal K enriched data.&lt;/p&gt;

&lt;p&gt;We’re running Signal K on a Raspberry Pi 3B+ powered by the boat battery. With a GPS dongle, this was already enough to give some basic navigation capabilities like charts and anchor watch. We also added a WiFi hotspot with a LTE uplink to the boat.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://d2vqpl3tx84ay5.cloudfront.net/800x/curiosity-doughnuts-signalk.png&quot; alt=&quot;Tracking some basic sailing exercises via Signal K&quot; /&gt;&lt;/p&gt;

&lt;p&gt;To make the system robust, installation is automated via Ansible, and easy to reproduce. &lt;a href=&quot;https://github.com/meri-imperiumi/curiosity&quot;&gt;Our boat GitHub repo&lt;/a&gt; also has the needed functionality to run a clone of our boat’s setup on our laptops via Docker, which is great when developing new features.&lt;/p&gt;

&lt;p&gt;Signal K has a very &lt;a href=&quot;http://slack-invite.signalk.org/&quot;&gt;active developer community&lt;/a&gt;, which has been great for figuring out how the extend the capabilities of our system.&lt;/p&gt;

&lt;h3 id=&quot;chartplotter&quot;&gt;Chartplotter&lt;/h3&gt;

&lt;p&gt;We’re using regular tablets for navigation. The main chartplotter is a cheap old waterproof &lt;a href=&quot;https://www.samsung.com/us/business/support/owners/product/galaxy-tab-active-8-0-wi-fi/&quot;&gt;Samsung Galaxy Tab Active 8.0&lt;/a&gt; tablet that can show both the &lt;a href=&quot;https://github.com/SignalK/freeboard-sk&quot;&gt;Freeboard&lt;/a&gt; web-based chartplotter with &lt;a href=&quot;https://map.openseamap.org/&quot;&gt;OpenSeaMap charts&lt;/a&gt;, and run the &lt;a href=&quot;https://www.navionics.com/usa/apps/navionics-boating&quot;&gt;Navionics Boating app&lt;/a&gt; to display commercial charts. Navionics is also able to receive some Signal K data over the boat WiFi to show things like &lt;a href=&quot;https://www.navionics.com/usa/features/ais&quot;&gt;AIS targets&lt;/a&gt;, and to utilize the boat GPS.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://d2vqpl3tx84ay5.cloudfront.net/800x/curiosity-samsung-tablet.jpg&quot; alt=&quot;Samsung T360 with Curiosity logo&quot; /&gt;&lt;/p&gt;

&lt;p&gt;As a backup we have our personal smartphones and tablets.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://d2vqpl3tx84ay5.cloudfront.net/800x/curiosity-freeboard-anchorwatch.jpg&quot; alt=&quot;Anchor watch with Freeboard and a tablet&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Inside the cabin we also have an &lt;a href=&quot;https://www.waveshare.com/wiki/4.2inch_e-Paper_Module&quot;&gt;e-ink screen&lt;/a&gt; showing the primary statistics relevant to the current boat state.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://d2vqpl3tx84ay5.cloudfront.net/800x/curiosity-waveshare-eink.jpg&quot; alt=&quot;e-ink dashboard showing boat statistics&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;environmental-sensing&quot;&gt;Environmental sensing&lt;/h3&gt;

&lt;p&gt;Monitoring air pressure changes is important for dealing with the weather. For this, we added a cheap barometer-temperature-humidity sensor module wired to the Raspberry Pi, driven with the &lt;a href=&quot;https://github.com/jncarter123/signalk-raspberry-pi-bme280&quot;&gt;Signal K BME280 plugin&lt;/a&gt;. With this we were able to get all of this information from our cabin into Signal K.&lt;/p&gt;

&lt;p&gt;However, there was more environmental information we wanted to get. For instance, the outdoor temperature, the humidity in our foul weather gear locker, and the temperature of our icebox. For these we found the &lt;a href=&quot;https://ruuvi.com/&quot;&gt;Ruuvi tags&lt;/a&gt; produced by a Finnish startup. These are small weatherproofed Bluetooth environmental sensors that can run for years with a coin cell battery.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://d2vqpl3tx84ay5.cloudfront.net/500x/curiosity-ruuvi-tag.png&quot; alt=&quot;Ruuvi tags for Curiosity with handy pouches&quot; /&gt;&lt;/p&gt;

&lt;p&gt;With Ruuvi tags and the &lt;a href=&quot;https://github.com/vokkim/signalk-ruuvitag-plugin#readme&quot;&gt;Signal K Ruuvi tag plugin&lt;/a&gt; we were able to bring a rich set of environmental data from all around the boat into our dashboards.&lt;/p&gt;

&lt;h3 id=&quot;anchor-watch&quot;&gt;Anchor watch&lt;/h3&gt;

&lt;p&gt;Like every cruising boat, we spend quite a lot of nights at anchor. One important safety measure with a shorthanded crew is to run an automated anchor watch. This monitors the boat’s distance to the anchor, and raises an alarm if we start dragging.&lt;/p&gt;

&lt;p&gt;For this one, we’re using the Signal K &lt;a href=&quot;https://github.com/sbender9/signalk-anchoralarm-plugin&quot;&gt;anchor alarm plugin&lt;/a&gt;. We added a &lt;a href=&quot;https://www.jbl.com/bluetooth-speakers/JBL+GO+2.html&quot;&gt;Bluetooth speaker&lt;/a&gt; to get these alarms in an audible way.&lt;/p&gt;

&lt;p&gt;To make starting and stopping the anchor watch easier, I utilized a simple Bluetooth remote camera shutter button together with &lt;a href=&quot;https://github.com/meri-imperiumi/signalk-bluetooth-anchor-button&quot;&gt;some scripts&lt;/a&gt;. This way the person dropping the anchor can also start the anchor watch immediately from the bow.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://d2vqpl3tx84ay5.cloudfront.net/500x/curiosity-anchor-button.png&quot; alt=&quot;Camera shutter button for starting anchor watch&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;ais&quot;&gt;AIS&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Automatic_identification_system&quot;&gt;Automatic Identification System&lt;/a&gt; is a radio protocol used by most bigger vessels to tell others about their course and position. It can be used for collision avoidance. Having an active transponder on a small boat like Curiosity is a bit expensive, but we decided we’d at least want to see commercial traffic in our chartplotter in order to navigate safely.&lt;/p&gt;

&lt;p&gt;For this we bought an &lt;a href=&quot;https://www.rtl-sdr.com/&quot;&gt;RTL-SDR USB stick&lt;/a&gt; that can tune into the AIS frequency, and with the &lt;a href=&quot;https://github.com/dgiardini/rtl-ais&quot;&gt;rtl_ais software&lt;/a&gt;, receive and forward all AIS data into Signal K.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://d2vqpl3tx84ay5.cloudfront.net/800x/curiosity-ais-targets.png&quot; alt=&quot;Tracking AIS targets in Freeboard&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This setup is still quite new, so we haven’t been able to test it live yet. But it should allow us to see all nearby bigger ships in our chartplotter in realtime, assuming that we have a &lt;a href=&quot;http://muck-solutions.com/?p=1324&quot;&gt;good-enough antenna&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;putting-it-all-together&quot;&gt;Putting it all together&lt;/h3&gt;

&lt;p&gt;All together this is quite a lot of hardware. To house all of it, we built a custom backing plate with 3D-printed brackets to hold the various components. The whole setup is called &lt;em&gt;Voronoi-1 onboard computer&lt;/em&gt;. This is a setup that should be easy to duplicate on any small sailing vessel.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://d2vqpl3tx84ay5.cloudfront.net/800x/curiosity-voronoi.jpg&quot; alt=&quot;The Voronoi-1 onboard computer&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The total cost so far for the full boat navigation setup has been around 600€, which is less than just a commercial chartplotter would cost. And the system we have is both easy to extend, and to fix even on the go. And we get a set of capabilities that would normally require a whole suite of proprietary parts to put together.&lt;/p&gt;

&lt;h3 id=&quot;next-steps-for-navigation-setup&quot;&gt;Next steps for navigation setup&lt;/h3&gt;

&lt;p&gt;We of course have plenty of ideas on what to do next to improve the navigation setup. Here are some projects we’ll likely tackle over the coming year:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Adding a timeseries database and some &lt;a href=&quot;https://bergie.iki.fi/blog/nasa-openmct-iot-dashboard/&quot;&gt;data visualization&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;9 degrees of freedom sensor to track the compass course, as well as boat heel&lt;/li&gt;
  &lt;li&gt;Instrumenting our outboard motor to get RPMs into Signal K and track the engine running time&lt;/li&gt;
  &lt;li&gt;Wind sensor, either &lt;a href=&quot;https://open-boat-projects.org/de/diy-windsensor/&quot;&gt;open source&lt;/a&gt; or &lt;a href=&quot;https://calypsoinstruments.com/shop/product/ultrasonic-portable-7&quot;&gt;commercial&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you have ideas for suitable components or projects, please &lt;a href=&quot;mailto:henri.bergius@iki.fi&quot;&gt;get in touch&lt;/a&gt;!&lt;/p&gt;

&lt;h2 id=&quot;source-code&quot;&gt;Source code&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/meri-imperiumi/curiosity&quot;&gt;https://github.com/meri-imperiumi/curiosity&lt;/a&gt; contains the Ansible Signal K setup for Curiosity, as well as the CNC and 3D printing designs we’re using  on the boat&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/meri-imperiumi/dashboard&quot;&gt;https://github.com/meri-imperiumi/dashboard&lt;/a&gt; is the Python script we’re using to drive the e-ink dashboard in our cabin&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/meri-imperiumi/signalk-autostate&quot;&gt;https://github.com/meri-imperiumi/signalk-autostate&lt;/a&gt; is a Signal K plugin for determining the boat state from sensor data&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/meri-imperiumi/signalk-bluetooth-anchor-button&quot;&gt;https://github.com/meri-imperiumi/signalk-bluetooth-anchor-button&lt;/a&gt; contains the udev scripts for setting anchor watch from the Bluetooth remote camera shutter button&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/meri-imperiumi/signalk-aws-iot&quot;&gt;https://github.com/meri-imperiumi/signalk-aws-iot&lt;/a&gt; is a Signal K plugin for transmitting our boat state to Amazon Web Services&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Huge thanks to both the &lt;a href=&quot;http://signalk.org/&quot;&gt;Signal K&lt;/a&gt; and &lt;a href=&quot;https://hackerfleet.github.io/&quot;&gt;Hackerfleet&lt;/a&gt; communities and the Curiosity crew for making all this happen.&lt;/p&gt;

&lt;p&gt;Now we just wait for the curfews to lift so that we can get back to sailing!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://d2vqpl3tx84ay5.cloudfront.net/500x/curiosity-crew-badge.png&quot; alt=&quot;Curiosity Crew Badge&quot; /&gt;&lt;/p&gt;
</description>
      <pubDate>Fri, 27 Mar 2020 00:00:00 +0000</pubDate>
      <atom:link rel="payment" href="https://flattr.com/submit/auto?url=https%3A%2F%2Fbergie.iki.fi%2Fblog%2Fsignalk-boat-iot%2F&amp;user_id=bergie" type="text/html" />
      <link>https://bergie.iki.fi/blog/signalk-boat-iot/</link>
      <guid isPermaLink="true">https://bergie.iki.fi/blog/signalk-boat-iot/</guid>
      <author>henri.bergius@iki.fi (Henri Bergius)</author>
    </item>
  
    <item>
      
      <title>Building c-base @ 35C3 with Flowhub</title>
      <description>&lt;p&gt;The &lt;a href=&quot;https://events.ccc.de/congress/2018/wiki/index.php/Main_Page&quot;&gt;35th Chaos Communication Congress&lt;/a&gt; is now over, and it is time to write about how we built the software side of the &lt;a href=&quot;https://c-base.org&quot;&gt;c-base&lt;/a&gt; assembly there.&lt;/p&gt;

&lt;h2 id=&quot;c-base-at-35c3&quot;&gt;c-base at 35C3&lt;/h2&gt;

&lt;p&gt;The Chaos Communication Congress is a major fixture of the European security and free software scene, with thousands of attendees. As always, the “&lt;a href=&quot;https://wiki.hackerspaces.org/c-base&quot;&gt;mother of all hackerspaces&lt;/a&gt;” had a big presence there, with a custom booth that we spend nearly two weeks constructing.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://d2vqpl3tx84ay5.cloudfront.net/800x/c-base-assembly-35c3.JPG&quot; alt=&quot;the c-base assembly at 35C3&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This year’s theme was “Refreshing Memories”, and accordingly we brought various elements of the history of the c-base space station to the event. On hardware side we had things like a scale model the &lt;a href=&quot;https://en.wikipedia.org/wiki/Fernsehturm_Berlin&quot;&gt;c-base antenna&lt;/a&gt;, as well as vintage arcade machines and various artifacts from over the years.&lt;/p&gt;

&lt;p&gt;With software, we utilized &lt;a href=&quot;https://bergie.iki.fi/blog/flowhub-iot-workshop-c-base/&quot;&gt;the existing IoT infrastructure at c-base&lt;/a&gt; to control lights, sound, and drive videos and other information to a set of information displays. All of course powered by &lt;a href=&quot;https://flowhub.io/ide&quot;&gt;Flowhub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This was a quite full-stack development effort, involving microcontroller firmware programming, server-side NoFlo and MsgFlo development, and front-end infoscreen web design. We also did quite a bit of devopsing with Travis CI, Docker, and docker-compose.&lt;/p&gt;

&lt;h3 id=&quot;local-msgflo-setup&quot;&gt;Local MsgFlo setup&lt;/h3&gt;

&lt;p&gt;The first step in bringing c-base’s IoT setup was to prepare a “portable” version of the environment. An MQTT broker, MsgFlo, some components, and a graph with any on-premise c-base hardware or service dependencies removed. As this was for a CCC event, we decided to call it &lt;a href=&quot;https://github.com/c-base/c3-flo&quot;&gt;c3-flo&lt;/a&gt; (in comparison to the &lt;a href=&quot;https://github.com/c-base/c-flo&quot;&gt;c-flo&lt;/a&gt; that we run at c-base).&lt;/p&gt;

&lt;p&gt;We already have a quite nice setup where our various systems get built and tested on Travis, and uploaded to &lt;a href=&quot;https://hub.docker.com/u/cbase&quot;&gt;Docker Hub’s cbase namespace&lt;/a&gt;. Some repositories weren’t yet integrated, and so the first step was to Dockerize them.&lt;/p&gt;

&lt;p&gt;To make the local setup simple to manage, we decided to go with a &lt;a href=&quot;https://github.com/c-base/c3-flo/blob/master/docker-compose.yml&quot;&gt;single docker-compose environment&lt;/a&gt; that would start all systems needed. This would be easy to run on any x86 machine, and provide us with a quite comprehensive set of features from the IoT parts to NASA’s &lt;a href=&quot;https://bergie.iki.fi/blog/nasa-openmct-iot-dashboard/&quot;&gt;Open MCT dashboard&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Of course we kept adding to the system throughout 35C3, but in the end the graph looked like the following:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://d2vqpl3tx84ay5.cloudfront.net/c3-flo-35c3.JPG&quot;&gt;&lt;img src=&quot;https://d2vqpl3tx84ay5.cloudfront.net/800x/c3-flo-35c3.JPG&quot; alt=&quot;c-base at 35C3 as seen in Flowhub&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;wifi-setup&quot;&gt;WiFi setup&lt;/h3&gt;

&lt;p&gt;To make our setup more portable, we decided to bring a local instance of the “c-base botnet” WiFi used to Congress. This way all of our IoT devices could work at 35C3 with the exact same firmware and networking setup as they do at c-base.&lt;/p&gt;

&lt;p&gt;Normally Congress doesn’t recommend running your own access point. But if needed, there are guidelines available on how to do it properly if needed. As it happens, out of this year’s 558 unofficial access points, the c-base one was the &lt;a href=&quot;https://media.ccc.de/v/35c3-9576-35c3_infrastructure_review&quot;&gt;only one conforming to the guidelines&lt;/a&gt; (commentary around the 25 minute mark).&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://d2vqpl3tx84ay5.cloudfront.net/800x/c-base-35c3-wifi.JPG&quot; alt=&quot;WiFi numbers from 35C3&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;info-displays&quot;&gt;Info displays&lt;/h3&gt;

&lt;p&gt;Like any station, c-base has a &lt;a href=&quot;https://github.com/msgflo/msgflo-browser&quot;&gt;set of info screens&lt;/a&gt; showing various announcements, timelines, and statistics. These are built with Raspberry Pi 3s running Chrome in Kiosk Mode, with a single-page webapp that connects to our MsgFlo infrastructure over WebSockets with &lt;a href=&quot;https://github.com/msgflo/msgflo-browser&quot;&gt;msgflo-browser&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Each screen has a customized rotation of different pages to show, and we can send URLs to announce events like members arriving to c-base or a space launch livestream via MQTT.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://d2vqpl3tx84ay5.cloudfront.net/800x/c-base-infodisplay-35c3.JPG&quot; alt=&quot;c-base info screen showing an announcement&quot; /&gt;&lt;/p&gt;

&lt;p&gt;For 35C3 we built a new set of pages tailed for the Congress experience:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Tweaked version of the normal c-base events view showing current and upcoming talks&lt;/li&gt;
  &lt;li&gt;Video player to rotate various videos from the history of c-base&lt;/li&gt;
  &lt;li&gt;Photo slideshow with a &lt;a href=&quot;https://www.flickr.com/photos/metavolution/albums/72157631227136604/&quot;&gt;nice set of pictures&lt;/a&gt; from c-base&lt;/li&gt;
  &lt;li&gt;Countdown screen for some event (c-base crash, teardown of the assembly at the end of Congress)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;crashing-c-base&quot;&gt;Crashing c-base&lt;/h2&gt;

&lt;p&gt;Highlight of the whole assembly was a re-enactment of the &lt;a href=&quot;https://en.wikipedia.org/wiki/C-base#Mythological_self-image_of_the_c-base&quot;&gt;c-base crash&lt;/a&gt; from billions of years ago. Triggered by a dropped bottle of space soda, this was an experience incorporating video, lights, and audio that we ran several times every day of the conference.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://d2vqpl3tx84ay5.cloudfront.net/c-base-crash-35c3-small.GIF&quot; alt=&quot;Crash Alarm!&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The c-base &lt;a href=&quot;https://github.com/c-base/c3-flo/blob/master/animations/crash.yml&quot;&gt;crash animation&lt;/a&gt; was managed by a &lt;a href=&quot;https://noflojs.org&quot;&gt;NoFlo&lt;/a&gt; graph integrated to the our MsgFlo setup with the standard &lt;a href=&quot;https://github.com/noflo/noflo-runtime-msgflo&quot;&gt;noflo-runtime-msgflo&lt;/a&gt; tool. With this we could trigger the “crash” with a MQTT message (sent by a physical button), and run a timed sequence of actions on lights, a sound system, and our info screens.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://d2vqpl3tx84ay5.cloudfront.net/800x/c-base-35c3-crash-button.JPG&quot; alt=&quot;Button for triggering the crash of c-base&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;timeline-manager&quot;&gt;Timeline manager&lt;/h3&gt;

&lt;p&gt;There were some new components that we had to build for this purpose. The most important was a &lt;a href=&quot;https://github.com/noflo/noflo-tween/blob/master/components/Timeline.js&quot;&gt;Timeline component&lt;/a&gt; that was upstreamed as part of the &lt;a href=&quot;https://github.com/noflo/noflo-tween&quot;&gt;noflo-tween animation library&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://d2vqpl3tx84ay5.cloudfront.net/500x/noflo-tween-timeline.JPG&quot; alt=&quot;Timeline component from noflo-tween&quot; /&gt;&lt;/p&gt;

&lt;p&gt;With this you can define a multi-tracked timeline as JSON or YAML, with actions triggered on each track on their appropriate second. With MsgFlo this meant we could send timed commands to different devices and create a coordinated experience.&lt;/p&gt;

&lt;p&gt;For example, &lt;a href=&quot;https://github.com/c-base/c3-flo/blob/master/animations/crash.yml&quot;&gt;our animation&lt;/a&gt; started by showing a short video on all info screens. When the bottle fell in the video, we triggered the appropriate soundtrack, and switched the lights through various animation modes. After the video ended, we switched to a “countdown to crash” screen, and turned all lights to a red alert mode.&lt;/p&gt;

&lt;p&gt;After the crash happened, everything went dark for a few seconds, before the c-base assembly was returned into its normal state.&lt;/p&gt;

&lt;h3 id=&quot;controlling-mclighting&quot;&gt;Controlling McLighting&lt;/h3&gt;

&lt;p&gt;All LED strips we used at 35C3 were run using the &lt;a href=&quot;https://github.com/toblum/McLighting&quot;&gt;McLighting firmware&lt;/a&gt;. By default it allows switching between different light modes with a &lt;a href=&quot;https://github.com/toblum/McLighting/wiki/WebSocket-API&quot;&gt;simple WebSocket API&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For our requirements, we wanted the capability to send new commands to the lights with minimal latency, and to be able to restore the lights to whatever mode they had before the crash started in the end.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://d2vqpl3tx84ay5.cloudfront.net/500x/noflo-mclighting.JPG&quot; alt=&quot;noflo-mclighting in action&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The component is available in &lt;a href=&quot;https://github.com/noflo/noflo-mclighting&quot;&gt;noflo-mclighting&lt;/a&gt;. The only thing you need is running the NoFlo graph in the same network as the LED strips, and to send the WebSocket addresses of your LED strips to the component. After that you can control them with normal NoFlo packets.&lt;/p&gt;

&lt;h2 id=&quot;finally&quot;&gt;Finally&lt;/h2&gt;

&lt;p&gt;The whole setup took a couple of days to get right, especially regarding timings and tweaking the light modes. But, it was great! You can see &lt;a href=&quot;https://vimeo.com/309632677&quot;&gt;a video of it&lt;/a&gt; below:&lt;/p&gt;

&lt;iframe src=&quot;https://player.vimeo.com/video/309632677&quot; width=&quot;640&quot; height=&quot;360&quot; frameborder=&quot;0&quot; webkitallowfullscreen=&quot;&quot; mozallowfullscreen=&quot;&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;p&gt;And if you’re interested in experimenting this stuff, check out the “portable c-base IoT setup” at &lt;a href=&quot;https://github.com/c-base/c3-flo&quot;&gt;https://github.com/c-base/c3-flo&lt;/a&gt;.&lt;/p&gt;
</description>
      <pubDate>Sat, 05 Jan 2019 00:00:00 +0000</pubDate>
      <atom:link rel="payment" href="https://flattr.com/submit/auto?url=https%3A%2F%2Fbergie.iki.fi%2Fblog%2Fcbase-35c3-flowhub%2F&amp;user_id=bergie" type="text/html" />
      <link>https://bergie.iki.fi/blog/cbase-35c3-flowhub/</link>
      <guid isPermaLink="true">https://bergie.iki.fi/blog/cbase-35c3-flowhub/</guid>
      <author>henri.bergius@iki.fi (Henri Bergius)</author>
    </item>
  
    <item>
      
      <title>Managing a developer shell with Docker</title>
      <description>&lt;p&gt;When I’m not in &lt;a href=&quot;https://flowhub.io/ide/&quot;&gt;Flowhub-land&lt;/a&gt;, I’m used to developing software in a quite customized command line based development environment. Like for many, the cornerstones of this for me are &lt;a href=&quot;https://www.vim.org&quot;&gt;vim&lt;/a&gt; and &lt;a href=&quot;https://github.com/tmux/tmux/wiki&quot;&gt;tmux&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As customization increases, it becomes important to have a way to manage that and distribute it across the different computers. For years, I’ve used a &lt;a href=&quot;https://github.com/bergie/dotfiles&quot;&gt;dotfiles repository&lt;/a&gt; on GitHub together with &lt;a href=&quot;https://www.gnu.org/software/stow/&quot;&gt;GNU Stow&lt;/a&gt; for this.&lt;/p&gt;

&lt;p&gt;However, this still means I have to install all the software and tools before I can have my environment up and running.&lt;/p&gt;

&lt;h2 id=&quot;using-docker&quot;&gt;Using Docker&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://www.docker.com&quot;&gt;Docker&lt;/a&gt; is a tool for building and running software in a containerized fashion. Recently &lt;a href=&quot;https://github.com/tiagodeoliveira&quot;&gt;Tiago&lt;/a&gt; gave me the inspiration to use Docker not only for distributing production software, but also for actually running my development environment.&lt;/p&gt;

&lt;p&gt;Taking ideas from &lt;a href=&quot;https://github.com/tiagodeoliveira/docker-shell&quot;&gt;his setup&lt;/a&gt;, I built upon my existing dotfiles and built a &lt;a href=&quot;https://hub.docker.com/r/bergie/shell/&quot;&gt;reusable developer shell container&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;With this, I only need Docker installed on a machine, and then I’m two commands away from having my normal development environment:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;docker volume create workstation
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;docker run &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt; ~/Projects:/projects &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt; workstation:/root &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt; ~/.ssh:/keys &lt;span class=&quot;nt&quot;&gt;--name&lt;/span&gt; workstation &lt;span class=&quot;nt&quot;&gt;--rm&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-it&lt;/span&gt; bergie/shell
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here’s how it looks in action:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://d2vqpl3tx84ay5.cloudfront.net/800x/vim-developer-shell-docker.png&quot; alt=&quot;Working on NoFlo inside Docker shell&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Once I update my Docker setup (for example to install or upgrade some tool), I can get the latest version on a machine with:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;docker pull bergie/shell
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;At least in theory this should give me a fully identical working environment regardless of the host machine. Linux VPS, a MacBook, or a Windows machine should all be able to run this. And soon, this should also work out of the box &lt;a href=&quot;https://chromeunboxed.com/news/chromebook-containers-virtual-machine-crostini-google-io&quot;&gt;on Chromebooks&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;setting-this-up&quot;&gt;Setting this up&lt;/h2&gt;

&lt;p&gt;The basics are pretty simple. I already had a repository for my dotfiles, so I only needed to write &lt;a href=&quot;https://github.com/bergie/dotfiles/blob/master/Dockerfile&quot;&gt;a Dockerfile&lt;/a&gt; to install and set up all my software.&lt;/p&gt;

&lt;p&gt;To make things even easier, I &lt;a href=&quot;https://github.com/bergie/dotfiles/blob/master/.travis.yml&quot;&gt;configured Travis&lt;/a&gt; so that every time I push some change to the dotfiles repository, it will create and publish a new container image.&lt;/p&gt;

&lt;h2 id=&quot;further-development-ideas&quot;&gt;Further development ideas&lt;/h2&gt;

&lt;p&gt;So far this setup seems to work pretty well. However, here are some ideas for further improvements:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;ARM build&lt;/strong&gt;: Sometimes I need to work on Raspberry Pis. It might be nice to cross-compile an ARM version of the same setup&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Key management&lt;/strong&gt;: Currently I create new SSH keys for each host machine, and then upload them to the relevant places. With this setup I could use a USB stick, or maybe even a &lt;a href=&quot;https://www.yubico.com/products/yubikey-hardware/&quot;&gt;Yubikey&lt;/a&gt; to manage them&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Application authentication&lt;/strong&gt;: Since the Docker image is public, it doesn’t come with any secrets built in. This means I still need to authenticate with tools like NPM and Travis. It might be interesting to manage these together with my SSH keys&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;SSH host&lt;/strong&gt;: with some tweaking it might be possible to run the same container on cloud services. Then I’d need a way to get my SSH public keys there and start an SSH server&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you have ideas on how to best implement the above, please &lt;a href=&quot;mailto:henri.bergius@iki.fi&quot;&gt;get in touch&lt;/a&gt;.&lt;/p&gt;
</description>
      <pubDate>Thu, 19 Apr 2018 00:00:00 +0000</pubDate>
      <atom:link rel="payment" href="https://flattr.com/submit/auto?url=https%3A%2F%2Fbergie.iki.fi%2Fblog%2Fdocker-developer-shell%2F&amp;user_id=bergie" type="text/html" />
      <link>https://bergie.iki.fi/blog/docker-developer-shell/</link>
      <guid isPermaLink="true">https://bergie.iki.fi/blog/docker-developer-shell/</guid>
      <author>henri.bergius@iki.fi (Henri Bergius)</author>
    </item>
  
    <item>
      
      <title>MicroFlo and IoT: measuring air quality</title>
      <description>&lt;p&gt;Fine particulate matter is a serious issue in many cities around the world. In Europe, it is &lt;a href=&quot;https://ec.europa.eu/jrc/en/news/air-quality-atlas-europe-mapping-sources-fine-particulate-matter&quot;&gt;estimated to cause&lt;/a&gt; 400.000 premature deaths per year. European Union has published standards on the matter, and warned several countries that haven’t been able to reach the safe limits.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Germany saw the highest number of deaths attributable to all air pollution sources, at 80,767. It was followed by the United Kingdom (64,351) and France (63,798). These are also the most populated countries in Europe. (source: &lt;a href=&quot;http://www.dw.com/en/air-pollution-kills-half-a-million-people-in-europe-eu-agency-reports/a-40920041&quot;&gt;DW&lt;/a&gt;)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The associated health issues don’t come cheap: 20 billion euros per year on health costs alone.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“To reduce this figure we need member states to comply with the emissions limits which they have agreed to,” Schinas said. “If this is not the case the Commission as guardian of the (founding EU) treaty will have to take appropriate action,” he added. (source: &lt;a href=&quot;https://phys.org/news/2018-01-eu-summons-france-germany-uk.html&quot;&gt;phys.org&lt;/a&gt;)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;One part of solving this issue is better data. Government-run measurement stations are quite sparse, and — in some countries — their published results can be unreliable. To solve this, &lt;a href=&quot;https://okfn.de/en/&quot;&gt;Open Knowledge Foundation Germany&lt;/a&gt; started the &lt;a href=&quot;https://luftdaten.info/&quot;&gt;luftdaten.info&lt;/a&gt; project to crowdsource air pollution data around the world.&lt;/p&gt;

&lt;iframe src=&quot;https://player.vimeo.com/video/257288126&quot; width=&quot;640&quot; height=&quot;360&quot; frameborder=&quot;0&quot; webkitallowfullscreen=&quot;&quot; mozallowfullscreen=&quot;&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;p&gt;Last saturday we hosted a luftdaten.info workshop at &lt;a href=&quot;https://c-base.org/&quot;&gt;c-base&lt;/a&gt;, and used the opportunity to build and deploy some particulate matter sensors. While &lt;a href=&quot;https://luftdaten.info/en/construction-manual/&quot;&gt;luftdaten.info has a great build guide&lt;/a&gt; and we used their parts list, we decided to go with a &lt;a href=&quot;https://github.com/c-base/microflo-luftdaten&quot;&gt;custom firmware&lt;/a&gt; built with MicroFlo and integrated with the existing IoT network at c-base.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://d2vqpl3tx84ay5.cloudfront.net/800x/luftdaten-sensor-workshop2.jpg&quot; alt=&quot;Building an air quality sensor&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;microflo-on-esp8266&quot;&gt;MicroFlo on ESP8266&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;http://microflo.org/&quot;&gt;MicroFlo&lt;/a&gt; is a flow-based programming runtime targeting microcontrollers. Just like NoFlo graphs run inside a browser or Node.js, the MicroFlo graphs run on an Arduino or other compatible device. The result of a MicroFlo build is a firmware that can be flashed on a microcontroller, and which can be live-programmed using tools like &lt;a href=&quot;https://flowhub.io/iot/&quot;&gt;Flowhub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;ESP8266 is an Arduino-compatible microcontroller with integrated WiFi chip. This means any sensors or actuators on the device can easily connect to other systems, like we do with &lt;a href=&quot;https://github.com/c-base/c-flo/tree/master/devices&quot;&gt;lots of different sensors&lt;/a&gt; already at c-base.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://d2vqpl3tx84ay5.cloudfront.net/800x/luftdaten-sensor-esp8266.jpg&quot; alt=&quot;ESP8266 sensor in preparation&quot; /&gt;&lt;/p&gt;

&lt;p&gt;MicroFlo &lt;a href=&quot;https://github.com/microflo/microflo/blob/master/CHANGES.md#microflo-063&quot;&gt;recently added&lt;/a&gt; a feature where Wifi-enabled MicroFlo devices can automatically connect with a MQTT message queue and expose their in/outports as queues there. This makes MicroFlo on an ESP8266 a fully-qualified &lt;a href=&quot;https://msgflo.org/&quot;&gt;MsgFlo participant&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;building-the-firmware&quot;&gt;Building the firmware&lt;/h2&gt;

&lt;p&gt;We wanted to build a firmware that would periodically read both the DHT22 temperature and humidity sensor, and the SDS011 fine particulate sensor, even out the readings with a running median, and then send the values out at a specified interval. MicroFlo’s &lt;a href=&quot;https://github.com/microflo/microflo-core&quot;&gt;core library&lt;/a&gt; already provided most of the building blocks, but we had to write &lt;a href=&quot;https://github.com/c-base/microflo-luftdaten/tree/master/components&quot;&gt;custom components&lt;/a&gt; for dealing with the sensor hardware.&lt;/p&gt;

&lt;p&gt;Thankfully Arduino libraries existed for both sensors, and this was just a matter of wrapping those to the MicroFlo component interface.&lt;/p&gt;

&lt;p&gt;After the components were done, we could build the firmware &lt;a href=&quot;http://app.flowhub.io/#github/c-base/microflo-luftdaten&quot;&gt;as a Flowhub graph&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://app.flowhub.io/#github/c-base/microflo-luftdaten&quot;&gt;&lt;img src=&quot;https://d2vqpl3tx84ay5.cloudfront.net/800x/microflo-luftdaten-graph.png&quot; alt=&quot;MicroFlo luftdaten graph&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To verify the build we enabled &lt;a href=&quot;https://travis-ci.org/&quot;&gt;Travis CI&lt;/a&gt; where we build the firmware both against the MicroFlo Arduino and Linux targets. The Arduino one is there to verify that the build works with all the required libraries, and the Linux build we can use for test automation with &lt;a href=&quot;https://github.com/flowbased/fbp-spec&quot;&gt;fbp-spec&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To flash the actual devices you need the &lt;a href=&quot;https://www.arduino.cc/en/Main/Software&quot;&gt;Arduino IDE&lt;/a&gt; and Node.js. Then use MicroFlo to generate the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.ino&lt;/code&gt; file, and flash that to the device with the IDE. WiFi and MQTT settings can be tweaked in the &lt;a href=&quot;https://github.com/c-base/microflo-luftdaten/blob/master/secrets.example.h&quot;&gt;secrets.h&lt;/a&gt; and &lt;a href=&quot;https://github.com/c-base/microflo-luftdaten/blob/master/config.h&quot;&gt;config.h&lt;/a&gt; files.&lt;/p&gt;
&lt;h2 id=&quot;sensor-deployment&quot;&gt;Sensor deployment&lt;/h2&gt;

&lt;p&gt;The recommended weatherproofing solution for these sensors is quite straightforward: place the hardware in a piece of drainage pipe with the ends turned downwards.&lt;/p&gt;

&lt;p&gt;Since we had two sensors, we decided to install one in the patio, and the other in the c-base main hall:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://d2vqpl3tx84ay5.cloudfront.net/800x/luftdaten-sensor-mainhall.jpg&quot; alt=&quot;Particulate matter sensor in c-base main hall&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;working-with-the-sensor-data&quot;&gt;Working with the sensor data&lt;/h2&gt;

&lt;p&gt;Once the sensor devices had been flashed, they became available in &lt;a href=&quot;https://github.com/c-base/c-flo&quot;&gt;our MsgFlo setup&lt;/a&gt; and could be connected with other systems:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://d2vqpl3tx84ay5.cloudfront.net/800x/luftdaten-sensor-msgflo.png&quot; alt=&quot;Particulate matter sensor in c-base main hall&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In our case, we wanted to do two things with the data:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Log it in the c-base telemetry system to be &lt;a href=&quot;http://bergie.iki.fi/blog/nasa-openmct-iot-dashboard/&quot;&gt;visualized with NASA OpenMCT&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Submit the data from the outdoor sensor to the &lt;a href=&quot;https://luftdaten.info/&quot;&gt;luftdaten.info database&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first one was just a matter of adding &lt;a href=&quot;https://github.com/c-base/cbeam-telemetry-server/pull/61&quot;&gt;couple of configuration lines&lt;/a&gt; to our OpenMCT server. For the latter, I built a &lt;a href=&quot;https://github.com/c-base/c-flo/blob/master/components/SendToLuftDaten.py&quot;&gt;simple Python component&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Our sensors have been tracking for a couple of days now. The public data can be seen in &lt;a href=&quot;https://www.madavi.de/sensor/graph.php?sensor=msgflo-00000042-sds011&quot;&gt;the madavi service&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://d2vqpl3tx84ay5.cloudfront.net/800x/luftdaten-sensor-madavi.png&quot; alt=&quot;Readings from the c-base outdoor sensor&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We’ve &lt;a href=&quot;http://luftdaten.info/feinstaubsensor-bauen/#feinstaubsensor-konfiguration&quot;&gt;submitted our sensor&lt;/a&gt; for inclusion in the luftdaten.info database, and hopefully soon there will be another covered area in the &lt;a href=&quot;http://berlin.maps.luftdaten.info/#13/52.5150/13.4211&quot;&gt;Berlin air quality map&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://d2vqpl3tx84ay5.cloudfront.net/800x/luftdaten-sensor-berlin.png&quot; alt=&quot;luftdaten.info Berlin map&quot; /&gt;&lt;/p&gt;

&lt;p&gt;If you’d like to build your own air quality sensor, the &lt;a href=&quot;https://luftdaten.info/en/construction-manual/&quot;&gt;instructions on luftdaten.info&lt;/a&gt; are pretty comperehensive. Get the parts from your local electronics store or AliExpress, connect them together, flash the firmware, and be part of the public effort to track and improve air quality!&lt;/p&gt;

&lt;p&gt;Our &lt;a href=&quot;https://github.com/c-base/microflo-luftdaten&quot;&gt;MicroFlo firmware&lt;/a&gt; is a great alternative if you want to do further analysis of the data yourself, or simply want to get the data on MQTT.&lt;/p&gt;
</description>
      <pubDate>Mon, 26 Feb 2018 00:00:00 +0000</pubDate>
      <atom:link rel="payment" href="https://flattr.com/submit/auto?url=https%3A%2F%2Fbergie.iki.fi%2Fblog%2Fmicroflo-particulate-sensors%2F&amp;user_id=bergie" type="text/html" />
      <link>https://bergie.iki.fi/blog/microflo-particulate-sensors/</link>
      <guid isPermaLink="true">https://bergie.iki.fi/blog/microflo-particulate-sensors/</guid>
      <author>henri.bergius@iki.fi (Henri Bergius)</author>
    </item>
  
    <item>
      
      <title>asComponent: turn any JavaScript function into a NoFlo component</title>
      <description>&lt;p&gt;Version 1.1 of &lt;a href=&quot;https://noflojs.org&quot;&gt;NoFlo&lt;/a&gt; shipped this week with a new convenient way to write components. With the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;noflo.asComponent&lt;/code&gt; helper you can turn any JavaScript function into a well-behaved NoFlo component with minimal boilerplate.&lt;/p&gt;

&lt;p&gt;Usage of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;noflo.asComponent&lt;/code&gt; is quite simple:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;noflo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;noflo&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;exports&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getComponent&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;noflo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;asComponent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In this case we have a function that doesn’t take arguments. We detect this, and produce a component with a single “bang” port for invoking the function:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://d2vqpl3tx84ay5.cloudfront.net/500x/ascomponent-result.png&quot; alt=&quot;Math.random as component&quot; /&gt;&lt;/p&gt;

&lt;p&gt;You can also amend the component with helpful information like a textual description and and icon:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;noflo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;noflo&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;exports&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getComponent&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;noflo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;asComponent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Generate a random number&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;icon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;https://d2vqpl3tx84ay5.cloudfront.net/500x/ascomponent-custom-icon.png&quot; alt=&quot;Math.random with custom icon&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;multiple-inputs&quot;&gt;Multiple inputs&lt;/h2&gt;

&lt;p&gt;The example above was with a function that does not take any arguments. With functions that accept arguments, each of them becomes an input port.&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;noflo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;noflo&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;findItemsWithId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;items&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;items&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;exports&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getComponent&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;noflo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;asComponent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;findItemsWithId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;https://d2vqpl3tx84ay5.cloudfront.net/500x/ascomponent-multiple-inports.png&quot; alt=&quot;asComponent and multiple inports&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The function will be called when both input ports have a packet available.&lt;/p&gt;

&lt;h2 id=&quot;output-handling&quot;&gt;Output handling&lt;/h2&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;asComponent&lt;/code&gt; helper handles three types of functions:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Regular synchronous functions: return value gets sent to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;out&lt;/code&gt;. Thrown errors get sent to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;error&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Functions returning a Promise: resolved promises get sent to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;out&lt;/code&gt;, rejected promises to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;error&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Functions taking a Node.js style asynchronous callback: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;err&lt;/code&gt; argument to callback gets sent to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;error&lt;/code&gt;, result gets sent to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;out&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With this, it is quite easy to write wrappers for asynchronous operations. For example, to call an external REST API with the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API&quot;&gt;Fetch API&lt;/a&gt;:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;noflo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;noflo&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;getFlowhubStats&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;https://api.flowhub.io/stats&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;exports&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getComponent&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;noflo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;asComponent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getFlowhubStats&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;How that you have this component, it is quick to do a graph utilizing it (&lt;a href=&quot;https://app.flowhub.io/#github/bergie/flowhubstats&quot;&gt;open in Flowhub&lt;/a&gt;):&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://app.flowhub.io/#github/bergie/flowhubstats&quot;&gt;&lt;img src=&quot;https://d2vqpl3tx84ay5.cloudfront.net/800x/ascomponent-fetch-graph.png&quot; alt=&quot;Example graph with asynchronous asComponent&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here we get the BODY element of the browser runtime. When that has been loaded, we trigger the fetch component above. If the request succeeds, we process it through a string template to write a quick report to the page. If it fails, we grab the error message and write that.&lt;/p&gt;

&lt;h2 id=&quot;making-the-components-discoverable&quot;&gt;Making the components discoverable&lt;/h2&gt;

&lt;p&gt;The default location for a NoFlo component is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;components/ComponentName.js&lt;/code&gt; inside your project folder. Add your new components to this folder, and NoFlo will be able to run them.&lt;/p&gt;

&lt;p&gt;If you’re using &lt;a href=&quot;https://flowhub.io/ide&quot;&gt;Flowhub&lt;/a&gt;, you can also write the components in the integrated code editor, and they will be sent to the runtime.&lt;/p&gt;

&lt;p&gt;We’ve already updated the hosted NoFlo browser runtime to 1.1, so you can get started with this new component API right away.&lt;/p&gt;

&lt;h2 id=&quot;advanced-components&quot;&gt;Advanced components&lt;/h2&gt;

&lt;p&gt;In many ways, asComponent is the inverse of the &lt;a href=&quot;http://bergie.iki.fi/blog/ascallback/&quot;&gt;asCallback embedding feature&lt;/a&gt; we introduced a year ago: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;asComponent&lt;/code&gt; turns a regular JavaScript function into a NoFlo component; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;asCallback&lt;/code&gt; turns a NoFlo component (or graph) into a regular JavaScript function.&lt;/p&gt;

&lt;p&gt;If you need to work with more complex firing patterns, like combining streams or having control ports, you can of course still write regular &lt;a href=&quot;https://noflojs.org/documentation/components/#component-api&quot;&gt;Process API&lt;/a&gt; components.&lt;/p&gt;

&lt;p&gt;The regular component API is quite a bit more verbose, but at the same time gives you full access to NoFlo APIs for dealing with manually controlled preconditions, state management, and creating &lt;a href=&quot;https://noflojs.org/documentation/components/#generator-components&quot;&gt;generators&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;However, thinking about the hundreds of NoFlo components out there, most of them could be written much more simply with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;asComponent&lt;/code&gt;. This will hopefully make the process of developing NoFlo programs a lot more straightforward.&lt;/p&gt;

&lt;p&gt;Read more &lt;a href=&quot;https://noflojs.org/documentation/components/&quot;&gt;NoFlo component documentation&lt;/a&gt; and &lt;a href=&quot;https://noflojs.org/api/AsComponent/&quot;&gt;asComponent API docs&lt;/a&gt;.&lt;/p&gt;
</description>
      <pubDate>Fri, 23 Feb 2018 00:00:00 +0000</pubDate>
      <atom:link rel="payment" href="https://flattr.com/submit/auto?url=https%3A%2F%2Fbergie.iki.fi%2Fblog%2Fascomponent%2F&amp;user_id=bergie" type="text/html" />
      <link>https://bergie.iki.fi/blog/ascomponent/</link>
      <guid isPermaLink="true">https://bergie.iki.fi/blog/ascomponent/</guid>
      <author>henri.bergius@iki.fi (Henri Bergius)</author>
    </item>
  
</channel>
</rss>
