Entries tagged 'cat:Projects' (Page 3)

All Those Bike Attachements

Entry created on 2022-01-16 author:steeph (374) cat:Bicycles (1) cat:Electronics (16) cat:Opinion (9) cat:Projects (41) lang:en (253) top:Projects:Ideas (8)

I think bicycle accessaries are of these things that developed over time past the point where it would have been sensible to rethink how things are done. I think it would make sense the rethink how all those bike attachments are integrated.

A bicycle without any attachments is already nice. It can be used without them and none of the things are necessary all the time. So it can make sense to have them detachable. But probably most people use their bike mainly for one thing - transportation, mountain-biking, sports - and need the same combination of attachments most times the bike is used. (Minus the lights when it's not dark.) I think it's rather peculiar that people buy, attach and use all these extras without questioning the crowded state of their bicycle frame. Let me list the things that I find useful myself.

  • Bell (*)
  • Front light (*)
  • Back light (*)
  • Phone/GPS holder
  • Phone charger
  • Action camera
  • Remote for indicators (in helmet or jacket/shirt)
  • Horn

(*): required by law when driving on the street

So, in this configuration, when you get back from riding your bike, you have to turn off the front light, turn off the back light, turn off the helmet indicator, turn off the indicator remote, check the charge of the front light, the back light, the phone charger, the GPS, the helmet, the helmet control, the horn and the action cam, detach the things that need charging, bring them in the house and plug them in for charging one after another. You may also have an electronic lock, additional front lights, a breaking light, the remote control for the breaking light and a headlamp. Half of them still have a micro USB port and none of the batteries last for dozens of rides (unless you ride mostly when it isn't dark). Sure, that comes with the benefit of having these devices, people seem to think. But they don't do all of this when they get out of their car. Because it wouldn't make sense to have a separate battery for every electronic device in a modern car. Neither does it make sense on a bike.

It would be nice to have a central battery for everything on my bike and a single on/off switch. But I don't use it enough to see me investing in building it myself. Because if I'd do it, I'd want it to be safe and secure in any weather, look good and not be too clunky or heavy. So I'd have to invest time.

SBWG 1.0.0 Delayed To Next Life

Entry created on 2021-12-28 author:steeph (374) cat:Bash (31) cat:Code (31) cat:Computer (78) cat:Linux (36) cat:Projects (41) cat:SBWG (18) cat:Scripts (28) cat:Software (53) lang:en (253) top:Projects:Code:Bash Scripts:SBWG (16)

I've decided to not publish version 1.0.0 of SBWG.

Very early on I devided against a versioning approach that allowed me to stay below version 1.0 for a very long time by only incrementing the version number by 0.0.1 for important changes but rather chose to increment the version and publish a new version whenever. I stick to this approach because it allowes me to express felt overall progress in the version number. But now that the goals that I at some point set for version 1.0.0 are nearly reached (they pretty much are), this leaves me in a spot where publishing version 1.0.0 would be the next thing to do despite the fact that it's not actually really absolutely perfect, yet. Absolute perfection isn't really my approach. It's still more like a learning project.

So to avoid having published a version that looks perfect on the label but isn't inside, I will skip this version number. Don't get me wrong. My goals are. I've tested it more than I thought I would and thought of potential problems and fixed bugs that I'd argue are not something you'd expect most shell scripters to catch. It definitely works reliably for what it is intended and at least works well for much more than I thought it would in the first few months of starting this project.

So, there is no link in this entry. No new version published today. The next version will be 1.x.x something.

Alright. Now that that's done, I can start to implement new features again next year.

backup.sh

Entry created on 2021-12-05 author:steeph (374) cat:Backups (4) cat:Bash (31) cat:Code (31) cat:Computer (78) cat:Linux (36) cat:Projects (41) cat:Scripts (28) cat:Software (53) lang:en (253) top:Projects:Code (26)
This entry is an update of the entry 'Backup Shell Script'.

I've updated/improved my backup script again.

Download


#!/bin/bash
#2021-11-03

budir="/mnt/backup"
num=8
list="/root/backup-list"
hostname=$(</etc/hostname)
srcdir="$1"
#NAME=${SRCDIR//\//--}
name="$2"

function usage () {
  echo "This script requires either one or two arguments."
  echo "Usage:"
  echo "$0 JOBLIST"
  echo "$0 SOURCE_DIRECTORY NAME"
  echo
  echo "JOBLIST File that contains one backup job per line in the format SOURCE_DIRECTORY NAME"
  echo "SOURCE_DIRECTORY Directory that should be backed up. Please, no trailing slash."
  echo "NAME A string that is used to name the backup in the destination."
  exit 1
}

function single() {
  if grep -qs "$budir " /proc/mounts
  then
    fullname="$budir/$hostname/$name"
    printf "\n"
    printf "Attempting backup of source directory '%s' to '%s'.\n" "$srcdir" "$fullname"
    printf "Number of differential backups to keep: %s\n" "$num"
    printf "Removing oldest backup... "
#    rm -rf "$fullname.$num"
    rsync --archive --delete "$budir/empty/" "$fullname.$num/"		# This is quicker than rm.
    printf "Done.\n"
    for ((i=$num; i>=2; i--)); do
      printf "Renaming '%s' to '%s' ... " "$fullname.$((i-1))" "$fullname.$i"
      mv "$fullname.$((i-1))" "$fullname.$i"
      printf "Done.\n"
    done
    printf "Duplicating last backup ('%s' to '%s')... " "$fullname.0" "$fullname.1"
    [[ -d $fullname.1 ]] && exit 1							# This directory should not exist at that point.
    cp -al "$fullname.0" "$fullname.1"
#    rsync --archive --acls --xattrs --hard-links "$fullname.0/" "$fullname.1/"
    printf "Done.\n"
    now=$(date)
    printf "\n\n\n" >> "$fullname.log"
    printf "STARTING INCREMENTAL BACKUP AT %s\n" "$now" >> "$fullname.log"
    printf "Starting new incremental backy uppy at '%s.0'..." "$fullname"
    if rsync --exclude ".cache" --archive --no-links --delete "$srcdir/" "$fullname.0/" 2>&1 | tee -a "$fullname.log"
    then
      printf " Done.\n"
      printf "Done.\n" >> "$fullname.log"
    else
      printf " Failed.\n"
      printf "Failed.\n" >> "$fullname.log"
    fi
    now=$(date)
    printf "\nIf this line is here the script finished (with or without errors) at %s\n" "$now" >> "$fullname.log"
  else
    printf "'%s' is not mounted. Aborting." "$budir"
    exit 1
  fi
}

function fromlist() {
  while read job; do
    if [ -n "$job" ]; then
      name="${job#* }"
      srcdir="${job% *}"
      single
    fi
  done < "$list"
}

mkdir "$budir/empty"									# Empty directory for a quicker method to delete a large directory.

case $# in
0)
  mount "$budir"
  printf "Reading backup jobs from list. Defaulting to %s.\n" "$list"
  fromlist
  ;;
1)
  mount "$budir"
  list="$1"
  printf "Reading backup jobs from %s." "$list"
  fromlist
  ;;
2)
  mount "$budir"
  single
  ;;
3)
#  I can't decide whether to make the third argument num or budir. I don't need it anyway.
#  num=$3
#  budir=$3
#  mount $budir
#  single
  usage
  ;;
*)
  usage
  ;;
esac

exit 0

SBWG - The Pathshortener And Other Recent Changes

Entry created on 2021-12-05 author:steeph (374) cat:Bash (31) cat:Code (31) cat:Computer (78) cat:Linux (36) cat:Projects (41) cat:SBWG (18) cat:Scripts (28) cat:Software (53) lang:en (253) top:Projects:Code:Bash Scripts:SBWG (16)

I made it my goal to harden SBWG before I start to implement new features. Before I call the next version of this project 1.0 I want to make sure that unexpected input from the command line or from source files, absurd numbers of absurdly long tags and content items, stupidly weird filenames or random binary data as tag values as well as purposfully created traps in the various places where input is processed are handled well, meaning that nothing fails unless there is no sensible way around it, and if something fails, that nothing breaks. Data should be filtered carefully, errors should be handled well and whereever possible data should be made processible if it was supplied in an unprocessible form to reduce the chances of errors. On top of that I wanted to make sure that the script did its job in a reasonable amount of time considering the circumstances. I mean, it will never be very fast. Bash is just not the right language for that. But there certainly were some repetitive tasks that could be improved. Fot the latter I created a simple caching functionality that will probably be extended in the future. I managed to reduce the (calculated/estimated) generation time of my biggest test web site from almost 300 years to a few days. Actual web sites will of course not take that long to generate, even on a slow machine. A huge web site will maybe take up to one day to generate completely, even without the new options that keep the script from re-generating existing unchanged parts of the web site. But before sombody will try to create such a big web site with SBWG I will probably have improved speed further. And even then it's a worst-case time.

As part of the aforementioned goals I have started working on last new feature before version 1.0. I call it the pathreducer. Since many of the files created by SBWG are named after the tags they represent, they can become quite long and contain almost any printible character, including multi-byte unicode characters or characters of character sets I haven't even heard of. I definitely don't want to restrict more than I already have what characters and how many of them tag values can contain. Especially filesystems used by operating systems from Microsoft are relatively restrictive in maximum allowed directory, path and filename length and allowed characters. By default the pathreducer is not used. But if enabled via command line option or in a web site's settings file, it will filter directory and filenames and shorten them to a user-defined maximum length. If the pathreducer decides to change a path elements it also adds a 6-character hash value to make shortened or otherwise reduced path elements as good as unique.

That works well for now and even can create 8.3 or 6.3 filenames for old DOS filesystems. But the result is not very nice because it isn't aware of what filesystem it is going to write a file to. To be save it removes more characters than it would have to for ext and NTFS filesystems. In the future I may extend the pathreducer to detect the filesystem at least of the root of the output directory automatically and decide how exactly path elements should be reduced according to the actual limitations of the present filesystem. Than it may even be enabled by default, even though it can increase the generation time quite a bit.

There are still some tests that I want to do and I will probably find some more things that I want to fix before version 1.0. But I see light.

USB/Serial PWM Fan Controller Using an Arduino

Entry created on 2020-11-22 (edited 2021-10-15) author:steeph (374) cat:Arduino (4) cat:Case Modding (11) cat:Code (31) cat:Computer (78) cat:DIY (17) cat:Electronics (16) cat:Fans (1) cat:Hardware (16) cat:Projects (41) cat:incomplete (21) lang:en (253) top:Projects:Arduino (4) top:Projects:Case Modding (9)

I wanted to be able to control the speed of the fans in my big NAS, Fred, individually. Even though the mainboard in use has five PWM fan connectors, the chipset can only control the speed of all fans together. There are probably good fan controllers commercially available that solve this problem better than I did. But they seemed overpriced and it seemed like a fun learning project for me.

The fan controller that I made uses an Arduino Nano clone that listens to it's serial port, waiting for a command to change the speed of a fan. When a command is recognised the continuous PWM signal for that fan is changed accordingly. It's possible to control up to six fans this way with an Arduino Nano. I'm only using three though since I only have three fan groups that need to be controlled separately.

The Arduino sketch/C code for the Arduino Nano that I used is as follows.




//fan speed sensor wire attached to digital pin 2 with a 10kohm pullup resistor
//fan PWM control wire attached directly to digital pin 9

#include <PWM.h> //include PWM library http://forum.arduino.cc/index.php?topic=117425.0

volatile int half_revolutions1; //allow half_revolutioins to be accesed in intterupt
volatile int half_revolutions2; //allow half_revolutioins to be accesed in intterupt
int rpm1; //set rpm as an integer
int rpm2; //set rpm as an integer
int pwm=255;
const byte numChars = 5;
char receivedChars[numChars];

boolean newData = false;

void setup()
{
  InitTimersSafe(); //not sure what this is for, but I think i need it for PWM control?
  bool success = SetPinFrequencySafe(9, 25000); //set frequency to 25kHz
  pwmWrite(9, 51); // 51=20% duty cycle, 255=100% duty cycle

  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  analogWrite(5, 170);
  analogWrite(6, 255);
  pinMode(2,INPUT_PULLUP); //set RPM pin to digital input
  pinMode(3,INPUT_PULLUP); //set RPM pin to digital input
  half_revolutions1 = 0;
  rpm1 = 0;
  half_revolutions2 = 0;
  rpm2 = 0;

  Serial.begin(9600);
}



void loop()
{
  sei(); //enable intterupts
  attachInterrupt(0, fan_rpm1, RISING); //record pulses as they rise
  delay(1000);
  detachInterrupt(0);
  attachInterrupt(1, fan_rpm2, RISING); //record pulses as they rise
  delay(1000);
  detachInterrupt(1);
  cli(); //disable intterupts

  rpm1 = (half_revolutions1/2)*60;

  Serial.print("1");
  Serial.println(rpm1);

  rpm2 = (half_revolutions2/2)*60;

  Serial.print("2");
  Serial.println(rpm2);

  rpm1 = 0;
  half_revolutions1 = 0;

  rpm2 = 0;
  half_revolutions2 = 0;

  pwm = 255;
  recvWithStartEndMarkers();
  processCommand();
}

void fan_rpm1()
{
  ++half_revolutions1; //increment before returning value
}


void fan_rpm2()
{
  ++half_revolutions2; //increment before returning value
}


void recvWithStartEndMarkers() {
    static boolean recvInProgress = false;
    static byte ndx = 0;
    char startMarker = 's';
    char endMarker = '\n';
    char rc;
 
    while (Serial.available() > 0 && newData == false) {
        rc = Serial.read();

        if (recvInProgress == true) {
            if (rc != endMarker) {
                receivedChars[ndx] = rc;
                ndx++;
                if (ndx >= numChars) {
                    ndx = numChars - 1;
                }
            }
            else {
                receivedChars[ndx] = '\0'; // terminate the string
                recvInProgress = false;
                ndx = 0;
                newData = true;
            }
        }

        else if (rc == startMarker) {
            recvInProgress = true;
        }
    }
}

void processCommand() {
    if (newData == true) {
        Serial.print("s");
        Serial.println(receivedChars);
        switch (receivedChars[0])
        {
            case '1':
                receivedChars[0] = '0';
                sscanf(receivedChars, "%d", &pwm);
                analogWrite(5, pwm);
                break;
            case '2':
                receivedChars[0] = '0';
                sscanf(receivedChars, "%d", &pwm);
                analogWrite(6, pwm);
                break;
            case '3':
                receivedChars[0] = '0';
                sscanf(receivedChars, "%d", &pwm);
                
                break;
//            default:
//                Serial.println("I don't know what that means.");
        }
        newData = false;
    }
}

Well, how should I put it? It works, usually.

(tbc?)

(tba:photos)

Go To Navigation Page
Show/Hide Navigation