Saturday, July 25, 2026

clockwork uConsole


Did not write about this earlier. It took about 9 months (!) from order to reception for me to get a clockwork uConsole employing an RPi CM4. In fact, I already forgot that I ordered the kit.

The kit essentially builds itself. However, there is one part I need to point out, care must be taken to ensure the battery holder does make contact with the main board. Initially, I just plopped it in and apparently, no contact was made. The device worked on a power supply, but not on batteries. A day later, I redid the battery holder installation and the uConsole works on batteries ever since. I would not call this a design flaw, but inconvenient it was.

However, there is a design flaw with the WiFi antenna. The instructions tell us to glue the antenna right on the outside of the metal (!) enclosure. While my first thought was that this will never work, putting a meander type radiator directly on a shielding case, I did it nevertheless. And guess what? The antenna did not work. Having essentially zero distance from the radiator to the ground short-circuits all the centimeter waves, who would have thought?!
Many folks realized that this construction was flawed and installed some sticking out helical devices on their uConsole. Certainly this will work, but, it also will make the uConsole less slick.
Here is my solution: Put something non-conductive between the case and the meander radiator. I found some packaging foam in my garbage, which I used a snippet to create enough of a distance to the case, but still keep the design somewhat sleek.


The spacer is held in place by some electrical tape. Of course one could do better than that, e.g. by 3D-printing something. 
And voilĂ , the uConsole now connects to my 6cm (5GHz) WiFi effortlessly. Earlier, I had to essentially stand right in front of the access point.



Sunday, December 28, 2025

Revival of BASIC

BASIC, the language of my youth (quickly replaced by F0RTRAN), came back in a surprising way. 

Some months ago, a PicoCalc finally arrived at my doorstep. The kit is brilliant and so is the product.
I toyed with the Lisp interpreter as an RPN calculator... fantastic! However, most of my readers are probably not interested in either RPN (reverse Polish notation) or in Lisp (and probably not in F0RTRAN either).

So, today I want to share some views of mine using the MMBASIC, which is part of the PicoCalc package.
MMBASIC allows for classical line numbering. We all know how convenient that is. Also, the line numbering BASIC code often leads to some severe spaghetti-code.

MMBASIC however, also allows for a more modern approach w/o line numbers, but labels instead. Generally labels are great, however, one needs to be careful to avoid any keywords when choosing labels.

In a label based programming language, one obviously wants to focus on routines to avoid spaghetti code. As know from many programming languages, such (sub)routines (procedures, functions or whatever the name is) usually are coded before the main program loop. BASIC does not respect this convention, first come first served in the doctrine here. 

Here is how to overcome BASIC's ignorance.

I usually have a block of constants and variables at the beginning of my code. That's cool with BASIC too.
In my usual programming, routines come next. BASIC would usually just start executing those and spit out an error when the first "return" was encountered. Fair enough, a return without a call cannot be performed.

In order to keep the traditional order of routines and functions before the main program loop, we need to pull a trick.
Similar to what is done in C, my main program loop in BASIC (at the end of the code) will get a label main:. So, the very first command after the definition of constants and variables is goto main. Obviously, this forces the interpreter to directly execute the main-loop.

I am not sure if this is elegant, however, this is how I program in modern BASIC.



Thursday, May 1, 2025

squid

Of course, I did it... I installed the squid caching proxy server on the thing client. 
The one problem is, to configure all browsers to use the proxy...

In my setup squid does not run in CasaOS, however, it does run on the server running CasaOS, similarly to the SMB-server, offering timemachine backups.

 

CasaOS

To be honest, I have no idea to introduce that topic to anyone... Anyway, I am living under rocks, so I am late to almost everything.
After successfully rescuing my ZFS-pool with Linux-Mint, I did install CasaOS on top for good measure.
You may remember that this former FreeNAS/TrueNAS-Server was running an AMD FX-6100 "Bulldozer" CPU with 16GB of RAM. Which for the time I set the system up, was pretty steep. My ZFS-pool on this server was and still is, 4 x 1TB in a parity-RAID configuration. 
With such a server, it is pretty simple to run something like CasaOS for "things".

In my second home, I am running a DELL/Wyse 5070 Thin Client with 4GB of RAM and a 2TB USB3-HDD under Linux-Mint. In this setup, the OS (and swap) is actually run on the USB3-HDD. The main task of this contraption is to play YouTube on my TV.  
While this setup is no speed-daemon, it is pretty low power, passively cooled and all in all just doing its job.
Hint: I run zram on it, such that swap to the HDD is reduced to a minumum.

The thing running around the clock, mostly idle, maybe there is something else to do with it. By now, the HDD is shared by means of NFS and SMB. While the CPU might be mainly bored, I installed CasaOS in the Thin Client. I am sure that I am not using this hardware to its full potential. For the time being, there is Navidrome spitting out some soundfiles and AdGuard doing its task on my network. In addition to that, independently of CasaOS, this server is used by my one MacBook Air for backups.

The title of this post is Casa OS. So, here comes the main dish.
Casa OS is some sort of overlay to a decent system or server. I am using Linux-Mint on both of my setups with Casa OS as an application. If you see Casa OS as an application of your system, an application that can be used remotely, you might like what you get. However, there is not much more than that.

What my needs are concerned, I am well served with are rather heavy server and server-filesystem supporting Casa OS, I do see a benefit for my operations. In a different usecase, e.g. the one in my 2nd home, the usefullness of Casa OS can be questioned. The benefit for me is that I only need to a a single strategy in my mind, for buth my sites. 
Is that enough to recommend Casa OS? Definetly no.

Over the next few days, I will install the Squid caching proxy-server on the Thin Client, such to further improve my home network. And no, this won´t run in docker under casaOS.


Monday, April 21, 2025

freeNAS it once was

All the good old time do come to an end one time. 

I am not joking here, freeNAS using BSD (freeBSD, I think), has been a really reliable NAS for its time, in particular since it was using ZFS.

In fact, I put all my data in a freeNAS ZFS pool. It was Easy to manage and deal with, until freeNAS turned into trueNAS. 
It was not easy, as I recall, but I managed to run the proper update programs to finally end up with an operating trueNAS system, still having my data in my original ZFS pool. That was until.....

Someone decided to f#-up trueNAS by porting it from BSD to Linux. While I am generally would go along with such a move, I would like to have some safeguards for random users.
While I am not considering myself a random user, I am not far off those anyway.

The treuNAS system told me that there is a fresh upgrade I shall apply, so I did... stupid me! This bloody upgrade, f-ed up my NAS for good. I spent several night trying to rescue the system, and failed doing so.

At the end, I was giving up. I booted Linux-Mint and was glad to see all my zpool drives lined up.
After installing Linux-Mint on my (non-zfs), boot drive I was able to install zfs-tools on my server. With the help of the zfs-tools I was able to import my zpool to the present Linux installation. 

I am happy to report that all my ZFS data us save. I was even able to successfully run a SCRUB on the RAID, resulting in 0 errors. May data is hence safe.
However. All the elegant management provided to trueNAS is gone. 

Is there a conclusion we can take from my experience? I am not sure. It is a gamble to trust one of the other flavour of provider. BACKUP on your own media and format.

Maybe it is better to setup your very own NFS-server and ignore all the other solution available for convenience. 

Sunday, April 20, 2025

MacBook Air (early 2015)

Those things, now that Apple no longer provides updates to macOS for Intel Macs, are getting really inexpensive by now.

My latest purchase was an 11" MacBook Air (early 2015) with an Intel Core i5, 8GB RAM and a 128GB SSD. The thing cost me €150 and came in good condition. There is a scratch on the clam shell, nothing I do care about. 
When I ordered the device, the one thing I cared about was the 8GB of RAM. I do not actually care about the amount of storage that came with it for two reasons, both of those later in this post. The other thing some people might be bothered by is the Intel Core i5, rather than a Intel Core i7. My understanding is that the i7s used in this machine were just i5s which could run of a higher clock speed, correct me if I am wrong. And here, the i5 actually plays into my use case of the device, lower CPU clock speed means longer battery life. So, for my use case, the i5 was a good thing.

There was a lot of typing "use case" in the previous section. Here is what I intend to use the thing for: travel. Hours of battery operations with tasks such as text-processing or displaying PDF-documents. With the speed of my typing, the entire computer might just to to sleep between the hits on the keyboard. And as for reading, maybe an e-Ink display would suit me better...

Those Intel-Apples are getting pretty inexpensive by now, but by no means those are cheap computers. The build-quality is exceptional, at least in this generation; the one with the good keyboards. The screen is what it is, good enough for me though. Me needing reading glasses by now, I wonder if "Retina Displays" would make any severe difference to me.

Apple is phasing out the support for Intel Macs, hence their low prices on the 2nd-hand market. Is this a bad thing? Yes and No!
Over the last few years, I did secure a few bargain Intel Macs of my likings, knowing that Linux can be installed on those very easily. My (presently) preferred flavour is Linux-Mint Cinnamon. Very easy to install, very easy to deal with. Disclaimer: my experience with Linux dates from 1993 onwards, with SLS and Slackware. And even before that I was using 386BSD. So, my definition of easy might differ from yours.
Installing Linux-Mint Cinnamon exhibit only a single simple to overcome hurdle: the lack of a WiFi-driver. I overcame this by using a generic USB-WiFi-dongle, which got me online. Once the OS was up, I could install the required driver. Now Linux was up and running. HOWEVER, the facetime-camera did not work and I could not get it to work either. With the camera not working, the ambient light adjustment does not do anything While I could ignore the camera, the ambient light-thing was a real bummer!
So, I decided to re-install some macOS for the time being. There are some options to do that, depending on what is wanted: https://support.apple.com/guide/mac-help/reinstall-macos-mchlp1599/mac
First time I tried Option-Command-R, every fell apart... now idea why.
I then tried Options-Shift-Command-R (finger acrobatics involved!), which worked (I don't recall which OS this ended up with).
Some time later, the first option worked, resulting in macOS Monterey.
One of my initial thoughts was to run Linux and macOS parallel, which dual boot, using the macOS home directory from Linux. While dual boot worked out for me, the using of the macOS home-directory from Linux did not.
There is another idea, which would work, but for the time being does not appear practical to me: partition the SSD into 3 parts. A first for macOS (APFS), a second for Linux (ext4) and a third for home (exFAT). I am pretty sure this would work, however, 128GB are pretty tight for such games.

Now to the elephant in the room, the jumping point (German: der springende Punkt) here is the use-case again. How much storage is actually needed? See above, some LibreOffice documents here and there, some PDFs here and there... not much space needed for those. Of course it is a different story should one consider photo-shoots in RAW or even videos. But, let's be honest, who would consider a MacBook Air for video editing?
As promised, there are 2 solutions to consider:
  1. Upgrade the machine with a bigger SSD. No problem with the MB-A 2015. The back can be removed easily, just a few screws to remove and it pops right off. Apple uses a proprietary SSD socket, however, adapters (eg. from China) to regula M.2 from can be found for about €2. Not all M.2 SSDs will work, you will find information about this on the InterWeb.
  2. Just of what you have, that's what I do. In addition to the internal SSD, I am using an old WD external USB3 spinny HDD. This external HDD serves 2 distinct purposes 1) external storage (dah) and 2) time-machine backups. The setup of such a disk is explained below.
Setting up the external USB3 disk is no magic either, however, at first, this might not be as obvious as it seems to the regular consumer.
My path was the following:
  • using disk-utility to erase the NTFS partition
  • reformat as APFS
  • partition the external HDD into an APFS particion twice the size of the internal SSD
  • format the remainder of the external HDD with exFAT 
Why exFAT for the second partition, you might ask. Simply said the two partitions will serve different purposes. The APFS partition will serve Time-Machine for backups.
The exFAT partition can be used as external data storage, which can be used with non-macOS computers, thereby allowing for very easy data transfer. Think of the photos or videos I mentioned above.

In my case, we are looking at 
  • 128 GB internal SSD
  • 256 GB Time-Machine storage
  • 768 GB shared/scrap/data/video/photo/etc space
Will the external drive connected all times? Of course not. When out and about, 128GB seems more than enough. Once back at the bed, connect the drive, backups will start, move the data about. All good! To be honest, I don't think that I would need any more storage than that in a daily task situation.

Concluding: get one of this Intel MacBooks now that they are soooo cheap. Don't get any of the ones with the bad butterfly keyboards! (older is better in this respect, DO THE RESEARCH). 
Review you use-case. What to you actually need when using your ultra-portable computer.

As a final tip: When you are already in your MacBook, apply fresh thermal paste to the CPU. Do that in the manner you found thermal compound in there. Apple left out parts of exposed semiconductors for a reason.
After having applied fresh thermal paste to my MacBook Air 11" (early 2015), I have not heard of the fan since.

 

Monday, April 14, 2025

PYTHON on a Chromebook

Spoiler: Thonny works.

In my previous post, I touched the topic of running Linux and BASIC on a Chromebook. The question was, does Thonny (Python 3) run too? Yes, it does.

Installing Thonny by
sudo apt install thonny
draws in a lot of stuff and takes a while. However, in the end you will get a working Thonny with a Python3 interpreter. I have not checked out any of the advanced things, such as matplotlib or NumPy. Presently I do feel confident that those will work just fine.


BASIC on a Chromebook

This continues my series into the past of many of us. Many of us learned programming by using the BASIC language. I school, I was forced to learn PASCAL, which was not of much use, other than understanding programming principles, which I already knew from BASIC. Learning F0RTRAN was the real step into the world of computing.

Anyway, this post is about BASIC on Chromebooks. I do own several of those. Not everyone of those is able to run Linux easily (there is always a way to force the hardware, one way or the other). This post is concerned with Chromebooks which can be easily set to run Linux applications.

To set any such Chromebook to do that, access "Settings" => "About ChromeOS" => "Linux Development Environment". If your Chromebook has that, install the Linux-thing. This might take a while.

Once your Chromebook has the virtual machine with (Debian) linux on board, you might start a (Linux) terminal and install "BWBASIC" by typing
sudo apt install bwbasic
in the terminal.

For the fun of it, I did install geany the same way. Now you can run your BASIC programs on a Chromebook in style. 
I have not yet checked the use of the FreeBasic Compiler. I see no reason why this should not work.

Can I run Python/Thonny on my ChromeBook? Stay tuned!


Sunday, March 23, 2025

Raspberry Pi running BASIC

Earlier on this blog, I posted something about the BASIC language on Linux. 

It turns out that all the tools mentioned in this posting are available on Raspberry Pi computers too. In fact, BWBASIC, FreeBasic and Geany work in the exact same way.


Raspberry Pi zram swap

Raspberry Pi computers may not always have the best amount of RAM available. For small embedded applications, this is just perfect, no precious ram wasted by remaining empty.
However, depending on the application, more memory might be required. The fallback would be virtual memory. In big server installations, swap is not even a topic. However, if an SD-card is were the files live on, SWAP is somewhat out of the picture.

If CPU power is not an issue, ZRAM might be a solution of the RAM-shortage of an RPi-application. 
While my RPi500 has plenty of RAM, I installed ZRAM anyways.
This is what my present memory situation looks like:

               total        used        free      shared  buff/cache   available
Mem:         8131616      835544     6173708      103560     1315828     7296072
Swap:        4270584           0     4270584

NAME       ALGORITHM DISKSIZE DATA COMPR TOTAL STREAMS MOUNTPOINT
/dev/zram0 lzo-rle       3.9G   4K   80B   12K       4 [SWAP]

NAME       TYPE      SIZE USED PRIO
/dev/zram0 partition 3.9G   0B  100
/var/swap  file      200M   0B   -2

And yes, the RPi500 is equipped with 8GB of RAM and 4 CPU cores. 
Presently I would not know how to fill up all the memory available to me.

Raspberry Pi 500 USB boot

There seems very little information on the internet on the Raspberry Pi 500. I love the RPi400, so, how could I resist to purchase an RPi500? I got the whole package, including mouse, PSU and the book.

The RPi500 comes preinstalled with a micro-SD, no surprise here. I am not a big fan of running my OS on SD-cards. So, I ordered a USB3 to SATA adapter to go with the 500. Of course my intention was to use an SSD in this setup. However, I was curious if the RPi500 could handle an spiny-disk-device. And yes, it can. Here is what I did:

Boot the RPi500 with the SD-card. Use the tool "SD Card Copier" to copy the contents of a Seagate Expansion external USB3 HDD. Surprise surprise, it worked. Once the SD-card was copied to the HDD, I shut down the RPi500 and removed the SD-card. Switching back on booted right away from the hard-drive. Of course a spiny disk does not provide a very snappy experience, but it worked. The SPi500 was able to supply the spiny disk, however, the temperature of the keyboard-computer was slightly elevated; not to an alarming level, however noticeable. 

While I call the exercise a success, I went back to the original plan and replaced the HDD with a (Kingston) SSD drive. This was done by simply using the "SD Card Copier" to copy the HDD content to the SSD.
The RPi500 runs a lot cooler and snappier now, who would have though?

Contrary to the actions one had to perform with the Raspberry Pi 4 generations, not strange commands are needed to boot the RPi5 generation using USB devices.

Friday, February 28, 2025

BASIC on Linux

Who does not remember the good old times when all (home) computers came with BASIC. To recreate the good old time feeling, BASIC had to be back on my Linux systems.

I figured out a combination of bwbasic and FreeBasic

The Bywater BASIC interpreter offers an interactive environment, similar to GW-BASIC. With a tiny trick, bwbasic can be used in a batch mode directly from shell. The "trick" being using the SYSTEM or QUIT statement at the end of the code, rather than the END statement. Here is an example:

10 for i=0 to 10
20 gosub 100
30 next
40 ?
50 system
100 ? i;
110 return

Line numbers are not necessary, however, line numbers allow to edit the code in the bwbasics interactive environment.

Sometimes, one might want to compile a program. In comes the FreeBasic compiler. It is important to point out that bwbasic and FreeBasic are not 100% compatible. I order successfully compile code as displayed above, one needs to the a "-lang" option. I found "fbc -lang qb [filename]" to work fine.
Another remark, while SYSTEM and QUIT are equivalents under bwbasic, fbc does understand SYSTEM, but not QUIT.

One interesting comparison is the performance of the interpreter and the compiled code.

Interpreter:
$ time bwbasic count.bas
Bywater BASIC Interpreter/Shell, version 2.20 patch level 2
Copyright (c) 1993, Ted A. Campbell
Copyright (c) 1995-1997, Jon B. Volkoff

 0 1 2 3 4 5 6 7 8 9 10

real 0m0.007s
user 0m0.003s
sys 0m0.004s

Compiled code:
$ time ./count
 0 1 2 3 4 5 6 7 8 9 10

real 0m0.038s
user 0m0.005s
sys 0m0.007s

When using the interpreter, the first 4 lines of the output are not controllable by the user of bwbasic. However, a very simple trick with the stream editor gets rid of the problem. It does not even cost a lot of extra time. This way, the output can be piped to yet another program. Have a look:
$ time bwbasic count.bas | sed 1,4d
 0 1 2 3 4 5 6 7 8 9 10


real 0m0.013s
user 0m0.005s
sys 0m0.018s

You may have noticed, that there is an additional empty line at the of the output. This line can also be suppressed with the stream editor. For doing that, you might want to use the following:
$ bwbasic count.bas | sed '1,4d;$d'
In my view, this is the preferred way of using the basic interpreter in a script envirronment.

There is yet another program I want to push into the mix, Geany. This IDE integrates perfectly with the FreeBasic compiler. Just be sure to add the "-lang qb" to the Build Commands. Click Build -> Set Build Commands. The "Compile" Command would therefore look like this: fbc -lang qb -w all "%f"

Geany also supports "Run" Commands. Making use od the stream editor as above, the command looks like this: bwbasic "%f" | sed '1,4d;$d' Obviously, this run option won't function on interactive programs... just saying.

Finally, one can write a little script, to run basic sources from the command line. Here is an example:
#!/bin/sh
bwbasic $1 | sed '1,4d;$d'
Of course, this can also be defined as a alias or function in you shell environment... One such option could be:
$ function run () { bwbasic $1 | sed '1,4d;$d';}


Dell Wyse 5070 Linux setup

In my previous post. I discussed the use of a Dell Wyse 5060 thing client. There is a better option, which meanwhile made it into my collection, the Dell Wyse 5070. 

The version I got is equipped with a 16GB onboard eMMC device, which is big enough for a small Linux installation. My joice fell on Xubuntu Minimal. With some additional software installed, 48% of the eMMC drive are used, roughly 6.5GB.

To keep things simple, I am using an external 2TB USB3 HDD. This disk is partitioned into a Linux swap and an ext4 partition. The ext4 partition serves as home-drive.

Swapping over USB3 is certainly not ideal. However, with only 4GB RAM, swap is desireable. In order to improve on the swap situation, zram takes care of part of the virtual memory. The total virtual memory is now 4GB (HDD) + 1.8GB (zram).


Sunday, August 28, 2022

Dell Wyse 5060 Thin Client

OMG, it has been over a year since I posted last... I am so sorry! The COVID-19 situation gave me some sort of reluctance, in which I indulged, watching other folks' work. My Raspberry Pi projects were quiet too. I simply tried to focus on growing a business... Has that worked? Maybe!

Anyway, for my business, I figured that my (t)rusty old dual core Celeron NUC was not cutting it any longer. I like the NUC, but, it might do better service to me as an Owncloud server or something alike. So, in replacing my authoring workstation, I was looking for silent (!) alternatives. When I was employed, many years ago, I was given a "thin client" to connect with the company's servers. This thing was fully passively cooled and silent but butt ugly.  Not sure what brand it was, and this is not important either.

So, in recall of what the silence during my thin client usage was, I started researching on a suitable thin client for my own business. The distinction here is that there is no intention to use the thin client as intended by the manufacturer. The original plan was to replace my (t)rusty old NUC, with something more silent and more powerful.

The research of tech and availability got me to the Dell Wyse range, in particular the 5060 model. And here is why:

  • accessible BIOS (password "Fireport") with USB boot option
  • quad core AMD 64bit CPU up to 2.4 GHz
  • 2 SODIMM sockets (one populated with a 4 GB card)
  • 8 GB SATA SSD module (internal connector)
  • 4 USB2 ports
  • 2 USB3 ports
On top, there is an internal connector for a wlan card. 

Hence, this thing should be pretty decent as a Linux workplace PC. In fact, I am writing this article on this particular piece of kit.

However, there is of course no free lunch, so, there was some work to be done before arriving at this workstation.
First of all, 8 GB of storage night be enough to run Puppy Linux, or distributions alike, however, more serious work will ask for a heavier distro. I am a long time user of Linux Mint, as this is what I was intending to use on this machine. Linux Mint does not install on 8 GB storage however.
This might look like a big problem, but it isn't, promised!

First, I want to give you an overview what the thin client looks in it's original state...
DELL WYSE 5060

Now that we has established how the thin client looks with the covers removed, lets have a look at the guts.
SATA SSD module

installed SODIMM module

SODIMM module removed, showing 2nd slot below

I had a 2GB SODIMM module in my junk box, so, I dropped it in. The original 4 GB module is now in slot 0, while the spare 2 GB module is in slot 1. While this may not be a big deal, every little bit of (gratis) RAM helps.
2 SODIMM slots used

The more interesting mod is of course to purpose the the SATA slot. 8 GB might be something, but more might be something better.

It just so happened that I had a 240 GB Sandisk SATA SSD in one of my junk boxes. It previously served a Raspberry Pi 4 but was not presently in use. There are other SSDs in my junk box, however, it is important to point out that the PCB of the Sandisk SSDs are particularly small. Have a look:
SanDisk SSD plus 240 GB
Now, lets compare that to the SSD module of the Wyse 5060...
On the left: 8 GB SSD module, on the right: 240 GB SSD
It is obvious that the Sandisk PCB is a little bit larger than the one of the original 8 GB SSD, However, it is not large enough to pose a real problem.
First of all, there is a screw and a respective terminal right in the middle of the original SSD. For electrical reasons, this has to be covered (by some electrical tape).


When installing the Sandisk SSD, some additional measures are needed to prevent electrical problem. In particular the EM-shield of the of RAM section might interfere with the larger SSD pcb. In order to overcome this problem, pliers might be required to bend the EM-shield such to no longer interfere/touch the SSD pcb.
Sandisk 240 GB SSD pcb installed
I will spare you a picture how I secured the SSD with just a strip of electrical tape.

This was a weekend project, i.e. just a few hours old. Still, I think this is a very worthy project to do. Inexpensive (if you are patient enough) and pretty rewarding in the results in my view.

I am running this with Linux Mint 20.3 and I am very pleased. I wish to point out that tweaking of the CPU frequencies might improve your experience.

Sunday, April 4, 2021

Raspberry Pi 400 Document Scanning with Canon LiDE 30

My RPi400 evolves more and more into my daily driver for my office activities. Here and there I got paper documents to share, so I needed to scan those, for sending them as PDFs around the world.

Many year ago, I purchased a Canon LiDE 30 USB scanner. This scanner is powered by the USB connection only. Until today, I used this particular scanner on a powered USB hub, thinking the power draw would be to great for the RPi400.
Well, I was wrong. Today, I hooked the scanner up to one of the USB3 ports of the RPi400 directly and the scanner worked perfectly.

If you wonder, the Canon LiDE 30 is supported up to Windows Vista 32bit or Mac OS X 10.5 (Leopard) and won't work on anything more modern than that in Microsoft or Apple environments.
However, we are in good luck with linux and the "sane" environment. 
On Raspberry Pi linux systems, XSane is available. To my surprise, the RPi400 delivers sufficient current on the USB3 connectors to power my Canon LiDE 30 scanner. 


Monday, February 22, 2021

Raspberry Pi and Arduino revisted

In my earlier post, locating a valid Arduino connection, I used exception handling by catching the error message created by attempting to open a non-existing device.
Of course there is an easier way of doing this in a POSIX compliant system, by looking at the existence of the respective device files. If you are confused about the ttyUSB0 device, this is how an inexpensive Arduino clone appears in my system.

Here is my new approach, which is bit more elegant and less brutish. This approach uses the "glob" module and the "set" data-type.


import glob

def listFiles(prefix):
    _=set()
    for file in glob.glob(prefix):
        _.add(file)
    return _

def findArduino():
    ser_dev={'/dev/ttyACM0','/dev/ttyACM1','/dev/ttyUSB0'}
    dev_list=listFiles('/dev/tty*')
    for _ in ser_dev:
        if _ in dev_list:
            return _

if __name__=='__main__':
    arduino=findArduino()
    if arduino:
        print('Arduino found at',arduino)
    else:
        print('Arduino not found')


Python Script Re-Import

Here is another study, pretty useless what it does actually, however, this might come in handy for some self-modifying projects.

This script writes a script called test01.py. It then imports the test01.py module, overwrites it, including data to a list and finally re-imports the modified test01.py module. At the very end, a function of the re-imported module is called. As a bonus the test01.py module is a fully self sufficient python program itself.

The study demonstrates how a python program can not only modify data but also modify its own functionality during run-time. Having a dictionary with python instruction could be an interesting way to write self-learning scripts.


from importlib import reload
import sys

a=[]

def modify(a,i):
    a.append(i)
    return a


# create a module to import
filename='test01.py'
f=open(filename,'w')
f.write(f'b=[]\n')
f.write(f'def test01(b):\n')
f.write(f'    return b\n')
f.write(f'if __name__=="__main__":\n')
f.write(f'    test01(b)\n')
f.write(f'    print(b)\n')
f.close()

# import the module
from test01 import *

for i in range(3):

    # play with data
    a=modify(a,i)

    # write modified module
    filename='test01.py'
    f=open(filename,'w')
    f.write(f'b='+str(a)+'\n')
    f.write(f'def test01(b):\n')
    f.write(f'    b.pop(1)\n')
    f.write(f'    return b\n')
    f.write(f'if __name__=="__main__":\n')
    f.write(f'    test01(b)\n')
    f.write(f'    print(b)\n')
    f.close()

    # re-import module
    reload(sys.modules['test01'])
    from test01 import b, test01    

    # show data from module
    print(b)

print('===')
print(a)

# run function from module
print(test01(a))


Thursday, February 18, 2021

Python Moving Average

In data analysis, moving averages are often used to "smooth" noisy data. In terms of signal processing, applying a moving average is a very crude low-pass filter. In fact, a moving average filter is a special case of an FIR (finite impulse response) filter.

Here is a study I wrote in Python using numpy and matplotlib.

import numpy as np
from matplotlib import pyplot as plt

# calculate moving average and add zero-padding
# the function takes two parameter, the data array and the
# number of bins for averaging, default 5 can be overwritten
def moving_average(a, n=5):

    ret = np.cumsum(a, dtype=float)
    ret[n:] = ret[n:] - ret[:-n]
    return (np.insert((ret[n-1:]/n),0,[0]*(n-1)))

# create some sort of noisy data
data = np.arange(100)
data = np.sin(data/5)+np.cos(data/20)+np.random.randn(100)/5

data_avg = moving_average(data,7)

print(data)
print(data_avg)

plt.plot(data,'.')
plt.plot(data_avg,'.')
plt.show()


Tuesday, February 16, 2021

Python Circular Buffer

Just to continue the series about watching me learning Python, here is one that might be useful for any  application that samples data in real time into a circular buffer, aka ring buffer. This examples runs two threads, one thread is "reading" (creating) data and depositing this data into the ring buffer, while the other thread reads a certain amount of said data independently.
Obviously, the ring buffer is in shared memory (global) and accessible by both threads.
Of course, putting random numbers into a buffer in a particular frequency and reading said buffer out with a different frequency is not solving any real problems, however, this is supposed to demonstrate how two threads could be used for sampling and analyzing data.

from time import sleep
from threading import Thread
import random

def read_val(var):
    length=len(var)
    global pos
    while True:
        for i in range(length):
            var[i]=random.random()
            pos=i
            print("generated ",i, var[i])
            sleep(0.5)

def pick_val(var):
    length=len(var)
    while True:
        sleep(0.1)
        print("most recent ",pos,var[pos])
        for i in range(length):
            lpos=(pos+i)%length
            print("=> ",i,var[i],lpos,var[lpos])

# initialize memory
data = []
for i in range(5):
    data.append(0)

t1 = Thread(target=read_val, args=(data,))
t2 = Thread(target=pick_val, args=(data,))

t1.start()
t2.start()

Saturday, February 13, 2021

Raspberry Pi with Arduino

Over the last few months I was developing hard- and software for a project. While I won't disclose any details of the project here, I think it would be fun for the readers to see me learning Raspberry Pi, Arduino and Python.
And yes, the previous Raspberry Pi blog posts were all somewhat triggered by the project mentioned above. In fact, the main idea of the project was not only using Raspberry Pi hardware for the project itself, bu also as main hardware for the company running said project, including all staff. (I am diverting...)

On particular problem with Arduino boards hooked up to Raspberry Pi boards is that the device might change from /dev/ttyACM0 to /dev/ttyACM1 from one use to the other. When using cheap clones, the device might be /dev/ttyUSB0.
So, in a project using Arduino (clone) boards with a Raspberry Pi board, one needs to test which device is in use.

Here comes the learn Python with me. This might not be the most elegant way to do this, however, here is a solution that works for me:

def initialize():
    global SERIAL_PORT
    global ser
    # find a valid serial port
    try:
        TSER='/dev/ttyACM0'
        print('trying '+TSER)
        tser = serial.Serial(
            port=TSER,
            baudrate = 115200,
            parity=serial.PARITY_NONE,
            stopbits=serial.STOPBITS_ONE,
            bytesize=serial.EIGHTBITS,
            timeout=1
        )
        print(TSER + ' found')
        SERIAL_PORT=TSER
        tser.close()
    except serial.serialutil.SerialException:
        try:
            TSER='/dev/ttyACM1'
            print('trying '+TSER)
            tser = serial.Serial(
                port=TSER,
                baudrate = 115200,
                parity=serial.PARITY_NONE,
                stopbits=serial.STOPBITS_ONE,
                bytesize=serial.EIGHTBITS,
                timeout=1
            )
            print(TSER+' found')
            SERIAL_PORT=TSER
            tser.close()
        except:
            print('no Arduino found, using clone')
            SERIAL_PORT='/dev/ttyUSB0'
            
    finally:
        print('using '+SERIAL_PORT)

    ser = serial.Serial(
        port=SERIAL_PORT,
        baudrate = 115200,
        parity=serial.PARITY_NONE,
        stopbits=serial.STOPBITS_ONE,
        bytesize=serial.EIGHTBITS,
        timeout=1
    )