Build a raspberry pi kubernetes cluster

1. Get the hardware

To build this cluster you will need the following hardware parts:

  1. 1xPoE switch (link) cost EUR 118
  2. 5x 15cm ethernet cables (link) cost EUR 2.4×5 = EUR 12
  3. 4xPoE hat for Raspberry Pi (link) cost EUR 28.99×4 = EUR 115.95
  4. 4xRaspberry pi 4 8 GB (link) cost EUR 81.66×4 = EUR 326.64
  5. 4x64GB usb 3.1 pendrives (link) cost EUR 11.63×4 = EUR 46.52
  6. spacers to stack the raspberry pis (link) cost EUR 9.99
  7. Total cost EUR 630

2. Install base infrastructure

  1. Set up the PoE Hats and stack the raspberry pis using the spacers.
  2. Install raspberry pi OS and base configuration (link)
    1. Since Raspberry pi 3B you can boot directly from USB. No more io errors from unreliable SD cards 🙂
    2. To perform a headless install create a file called ssh in /boot/ folder, this will enable ssh so you can access your pis remotely without need for a monitor (link)
    3. Install tmux and get this script (link) to simultaneously modify all 4 raspis
      1. sudo apt install tmux
      2. vi multi-ssh.sh
#!/bin/bash
ssh_list=( user1@server1 user2@server2 ... )
split_list=()
for ssh_entry in "${ssh_list[@]:1}"; do
    split_list+=( split-pane ssh "$ssh_entry" ';' )
done
tmux new-session ssh "${ssh_list[0]}" ';' \
    "${split_list[@]}" \
    select-layout tiled ';' \
    set-option -w synchronize-panes
  1. Install Docker on each raspberry pi (link)
sudo apt-get update && sudo apt-get upgrade
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
sudo usermod -aG docker pi
sudo reboot

2. Install kubeadm, kubelet and kubectl on each raspberry pi (link)

sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl
sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://packages.cloud.google.com/apt/doc/apt-key.gpg
echo "deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl

3. disable swap on each raspberry pi (link)

sudo dphys-swapfile swapoff && \
sudo dphys-swapfile uninstall && \
sudo systemctl disable dphys-swapfile

4. Add cgroup parameters to /boot/cmdline.txt on each raspberry pi (link)

sudo vi /boot/cmdline.txt
cgroup_enable=cpuset cgroup_enable=memory cgroup_memory=1

5. Configure docker to use systemd on each raspberry pi

sudo mkdir /etc/docker
cat <<EOF | sudo tee /etc/docker/daemon.json
{
  "exec-opts": ["native.cgroupdriver=systemd"],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m"
  },
  "storage-driver": "overlay2"
}
EOF
sudo systemctl enable docker
sudo systemctl daemon-reload
sudo systemctl restart docker

3. Initialize Kubernetes Control Plane on the master node

  1. Choose one raspberry pi to be your master node from which you will control the cluster. This is called the Kubernetes Control Plane. Run the below commands on the master node.
sudo kubeadm init --pod-network-cidr=10.244.0.0/16
rm -rf .kube/
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
vi $HOME/.bashrc
# Add the below line to the end of .bashrc
export KUBECONFIG=$HOME/.kube/config

2. Set up the kubernetes network (I am using flannel) on the master node.

kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
cat > /run/flannel/subnet.env
FLANNEL_NETWORK=100.96.0.0/16
FLANNEL_SUBNET=100.96.1.1/24
FLANNEL_MTU=8973
FLANNEL_IPMASQ=true

3. Get the tokens to connect the different nodes. Run this command on the master node and take note of the output.

kubeadm token create --print-join-command

4. Add the different nodes to the cluster

In each raspberry pi that you want to add as a node to the cluster run the following commands.

  1. Configure the flannel subnet file
cat > /run/flannel/subnet.env
FLANNEL_NETWORK=100.96.0.0/16
FLANNEL_SUBNET=100.96.1.1/24
FLANNEL_MTU=8973
FLANNEL_IPMASQ=true

2. Use the output you obtained previously from command “kubeadm token create –print-join-command” it will look something like this

sudo kubeadm join 192.168.1.102:6443 --token 5aotn8.ab493943zf9zf9nm \
        --discovery-token-ca-cert-hash sha256:396a8a8b28b11c8caa8474384398493482034320947090766366bff9d1516699acde

3. If all went well you should see all your nodes ready with command kubectl get nodes. You are now ready to create deployments, pods and services.

5. Destroy your kubernetes infrastructure

After you are done playing, or in case things stop working and you want to start from scratch you can use the below instructions to destroy your kubernetes infrastructure.

  1. Remove nodes by running the below in your control plane instead of raspiclustern you can use the hostnames you have set up for your machines.
kubectl drain raspicluster1 --delete-emptydir-data --force --ignore-daemonsets 
kubectl drain raspicluster2 --delete-emptydir-data --force --ignore-daemonsets 
kubectl drain raspicluster3 --delete-emptydir-data --force --ignore-daemonsets 
kubectl drain raspicluster4 --delete-emptydir-data --force --ignore-daemonsets 
kubectl delete node raspicluster1 
kubectl delete node raspicluster2 
kubectl delete node raspicluster3 
kubectl delete node raspicluster4 
kubectl get nodes

2. SSH to each machine and run the below code

sudo rm /etc/kubernetes/kubelet.conf /etc/kubernetes/pki/ca.crt /etc/kubernetes/bootstrap-kubelet.conf
sudo kubeadm reset

Artificial intelligence tweeting Bird Feeder

Create a bird watching Artificial Intelligence that runs on a raspberry and tweets short videos every time it detects a bird. You can find mine at https://twitter.com/birdfeederAI

1. Get the hardware

To build this bird watcher you will need the following hardware parts. Total cost EUR 255

  1. (optional) PoE switch (link) cost EUR 118
  2. (optional) PoE hat for Raspberry Pi (link) cost EUR 28.99
  3. Raspberry pi 4 8 GB (link) cost EUR 81.66
  4. Raspberry pi camera (link) cost EUR 33.90
  5. 64GB SD card (link) cost EUR 11.99 (update, since raspberry pi 3B you can boot from USB which is faster and fails less, so better get a 64GB usb 3.1 pendrive (link) 11.63 EUR )

2. Set up base infrastructure

  1. Install raspberry pi OS (link)
  2. Activate the camera (link)
  3. Log into the raspberry pi and create a python virtual environment with base libraries
    1. mkdir -p /home/pi/dev/birdfeederAI
    2. cd /home/pi/dev/birdfeederAI
    3. python3 -m venv ./venv
      1. This creates the python virtual environment.
    4. source ./venv/bin/activate
      1. This activates the python virtual environment. All modules installed by pip will be installed only for this virtual environment
    5. which python
      1. Now that we have created and activated our virtual environment this should return: “/home/pi/dev/birdfeederAI/venv/bin/python”
    6. which pip
      1. Now that we have created and activated our virtual environment this should return: “/home/pi/dev/birdfeederAI/venv/bin/pip”
    7. which pip3
      1. Now that we have created and activated our virtual environment this should return: “/home/pi/dev/birdfeederAI/venv/bin/pip3”
    8. pip list
      1. this will list the python modules we have installed for our virtual environment.
    9. pip install --upgrade pip
      1. This will install the latest version of pip
    10. pip install opencv-python twython
      1. install the opencv python module to process video, twython to send tweets
  4. Fix all the missing libs
    1. sudo apt install apt-file
    2. sudo apt-file update
    3. for i in find /home/pi/dev/birdfeederAI/venv/lib |grep so$|xargs ldd|grep "not found"|awk '{print $1;}'; do apt-file search $i|awk 'BEGIN{FS=":"};{print $1;}'; done|sort|uniq|xargs apt install
      1. This will list the libraries which are not installed and install them for you. If something went wrong look here (link)
  5. Download the pre-trained model MobileNet-SSD
    1. cd /home/pi/dev/birdfeederAI
    1. git clone https://github.com/chuanqi305/MobileNet-SSD.git
  6. Check that the base infrastructure is correctly installed
    1. raspistill -o mypicture.jpg
      1. this should create a picture from the camera and store it as mypicture.jpg
    2. raspivid -t 5000 -o myvideo.h264
      1. this should create a video from the camera and store it as myvideo.h264
    3. copy the below code to pycamtest.py and run it with python pycamtest.py. If everything is correctly set up you should see the output of your camera in a window.
import cv2
cv2.namedWindow("TestCV2")
vc = cv2.VideoCapture(0)
if vc.isOpened():
    rval,frame = vc.read()
else:
    rval = False
while rval:
    frame = cv2.flip(frame,-1)
    cv2.imshow("TestCV2", frame)
    rval, frame = vc.read()
    key = cv2.waitKey(20)
    if key ==27:
        break
vc.release()
cv2.destroyWindow("TestCV2")

3. Set up twitter functionality

  1. Set up a twitter account
  2. Activate a twitter developer account in https://developer.twitter.com/ and generate your API keys which you will need in the next step
  3. Obtain your API keys and copy them to /home/pi/dev/birdfeederAI/auth.py
    1. cat>/home/pi/dev/birdfeederAI/auth.py
    2. consumer_key = 'puthereyourconsumerkey'
    3. consumer_secret = 'puthereyourconsumersecret'
    4. access_token = 'puthereyouraccesstoken'
    5. access_token_secret = 'puthereyouraccesstokensecret'
    6. Ctrl-C

4. Code your birdfeeder

  1. Code your program, you can use my code to set up a headless tweeting bird detecting camera 🙂
    1. git clone https://github.com/Rogeman/birdfeederAI.git
import numpy as np
import cv2
import random
import os
import logging
from twython import Twython
from twython import TwythonError

from auth import (
        consumer_key,
        consumer_secret,
        access_token,
        access_token_secret
)
twitter = Twython(
        consumer_key,
        consumer_secret,
        access_token,
        access_token_secret
)


confidence_thr = 0.5
CLASSES = ["background", "aeroplane", "bicycle", "bird", "boat",
    "bottle", "bus", "car", "cat", "chair", "cow", "diningtable",
    "dog", "horse", "motorbike", "person", "pottedplant", "sheep",
    "sofa", "train", "tvmonitor"]
COLORS = np.random.uniform(0, 255, size=(len(CLASSES), 3))
birdfeeder_dir=os.path.dirname(os.path.abspath(__file__))
logging.basicConfig(filename=birdfeeder_dir+'/log/birdfeederAI.log', level=logging.DEBUG, format='%(asctime)s %(message)s')
mobilenet_dir=birdfeeder_dir+'/MobileNet-SSD/'
net = cv2.dnn.readNetFromCaffe(mobilenet_dir+ 'deploy.prototxt' , mobilenet_dir+ 'mobilenet_iter_73000.caffemodel')
blob=None

def applySSD(image):
    global blob
    mybird = bool(False)
    blob = cv2.dnn.blobFromImage(cv2.resize(image, (300, 300)), 0.007843, (300, 300), 127.5)

    # pass the blob through the network and obtain the detections and
    # predictions
    net.setInput(blob)
    detections = net.forward()

    # loop over the detections
    for i in np.arange(0, detections.shape[2]):
        # extract the confidence (i.e., probability) associated with the
        # prediction
        confidence = detections[0, 0, i, 2]

        if confidence > confidence_thr:
            idx = int(detections[0,0,i,1])
            if CLASSES[idx]=="bird":
                mybird=bool(True)
    return mybird

def birdRatio(videoName):
    totalBirdFrames = 1
    totalFrames = 1
    vc2 = cv2.VideoCapture(videoName)
    if vc2.isOpened():
        rval2,frame2 = vc2.read()
    else:
        rval2 = False

    while rval2:
        birdinFrame = applySSD(frame2)
        rval2, frame2 = vc2.read()
        if (birdinFrame):
            totalBirdFrames = totalBirdFrames + 1
        totalFrames = totalFrames + 1

    vc2.release()
    return totalBirdFrames/totalFrames

videoLength=8*60*60*1000
randomsec=random.randint(0,videoLength)


#vc = cv2.VideoCapture(birdfeeder_dir+"/birds_video.mp4")
# If you want to record birds using your camera comment the above line and uncomment the below line. If you want to find birds in a video uncomment the line above and comment the line below 🙂
vc = cv2.VideoCapture(0)
vc.set(cv2.CAP_PROP_POS_MSEC, randomsec)
if vc.isOpened():
    width = vc.get(cv2.CAP_PROP_FRAME_WIDTH)
    height = vc.get(cv2.CAP_PROP_FRAME_HEIGHT)
    fps = vc.get(cv2.CAP_PROP_FPS)
    fcount = vc.get(cv2.CAP_PROP_FRAME_COUNT)
else:
    logging.error('Can\'t open video')

    exit()

recording= False
framerecorded = 0
framecounter = 0
birdinFrame=False
fourcc = cv2.VideoWriter_fourcc(*'h264')
#out = cv2.VideoWriter('output.mp4',fourcc,20.0,(640,480))
out = cv2.VideoWriter(birdfeeder_dir+'/output.mp4',fourcc,fps,(int(width),int(height)))

if vc.isOpened(): # try to get the first frame
    rval, frame = vc.read()
    (h, w) = frame.shape[0] , frame.shape[1]
else:
    rval = False

logging.debug('Started main loop')
while rval:
    #You enter this loop once per frame
    rval, frame = vc.read()
    #uncomment the below line if you need to flip the camera upside down.
    frame = cv2.flip(frame,-1)
    key = cv2.waitKey(20)
    if key == 27: # exit on ESC
        break
    framecounter = framecounter + 1
    if (framecounter > 60):
    # Write frame to disk every 60 frames so we can see what the camera is seeing
        framecounter = 0
        cv2.imwrite(birdfeeder_dir+"/webserver/currentframe.jpg",frame)
    if (birdinFrame==False):
        #Check if this frame has a bird in it
        birdinFrame= applySSD(frame)
    if (birdinFrame== True and recording== False):
        #You have detected the first bird in a frame, start recording
        logging.info('Started recording video')
        recording=True
    if (recording == True):
        #write the frame to file keep track of how many frames you have saved.
        framerecorded = framerecorded + 1
        out.write(frame)
    if (framerecorded > 200):
        #after 200 frames stop recording
        logging.info('Checking recorded video')
        recording = False
        birdinFrame=False
        framerecorded = 0
        out.release()
        filename = birdfeeder_dir+"/output.mp4"
        birdsinvideo= birdRatio(filename)
        logging.debug('percentage of bird in video: '+birdsinvideo)
        if (birdsinvideo> 0.50):
            # if the recorded video has more than 50% of frames with a bird in it then tweet it
            logging.info('Tweeting bird video')
            video = open(filename,'rb')
            try:
                response = twitter.upload_video(media=video, media_type='video/mp4', media_category='tweet_video', check_progress=True)
                twitter.update_status(status='birdfeeder 0.5', media_ids=[response['media_id']])
            except TwythonError as e:
                logging.error('Twitter error:'+str(e))
            birdsinvideo=0
            video.close()
        randomsec=random.randint(0,videoLength)
        vc.set(cv2.CAP_PROP_POS_MSEC, randomsec)
        os.remove(birdfeeder_dir+'/output.mp4')
        out = cv2.VideoWriter(birdfeeder_dir+'/output.mp4',fourcc,fps,(int(width),int(height)))



vc.release()

5. Create an nginx webserver to see what the camera is seeing

  1. Install Docker
sudo apt-get update && sudo apt-get upgrade
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
sudo usermod -aG docker pi
sudo reboot
  1. Run nginx docker container serving documents from the birdfeeder webserver folder
    1. docker run -it --rm -d -p 8080:80 --name web -v /home/pi/dev/birdfeederAI/webserver/:/usr/share/nginx/html nginx
  2. Create an index.html which refreshes every 2 seconds showing currentframe.jpg
cat > /home/pi/dev/birdfeederAI/webserver/index.html
<html>
    <head>
        <title>Birdfeeder</title>
        <meta http-equiv="refresh" content="2" />
    </head>
    <body>
    <img src=./currentframe.jpg>
    </body>
</html>

Ctrl+C

You can now open a web browser to your raspberry pi’s ip address port 8080 and see what your camera is seeing

6. Add birdfeeder service to systemd

We add birdfeeder to systemd so it starts on boot.

  1. Create a bash script that runs birdfeeder in a loop. Run it with nice so it does not consume 100% of cpu (running at 100% for long makes the sd card non-responsive and the system unstable).
    1. vim /home/pi/dev/birdfeederAI/bin/birdfeeder.sh
    2. chmod +x /home/pi/dev/birdfeederAI/bin/birdfeeder.sh
#!/bin/bash
docker run -it --rm -d -p 8080:80 --name web -v /home/pi/dev/birdfeederAI/webserver/:/usr/share/nginx/html nginx
source /home/pi/dev/birdfeederAI/venv/bin/activate
while [ 1 -eq 1 ]
do
nice python /home/pi/dev/birdfeederAI/birdfeeder.py
done

  1. Create service file
    1. sudo vim /lib/systemd/system/birdfeeder.service
 [Unit]
 Description=birdfeeder service
 After=multi-user.target

 [Service]
 Type=idle
 ExecStart=/home/pi/dev/birdfeederAI/bin/birdfeeder.sh

 [Install]
 WantedBy=multi-user.target

  1. Grant pemissions, add the service and reboot system
    1. sudo chmod 644 /lib/systemd/system/birdfeeder.service
    2. sudo systemctl daemon-reload
    3. sudo systemctl enable birdfeeder.service
    4. sudo reboot

Arduino controlled robot arm

I enjoy tinkering around with robots and electronics. Bridging the invisible world of software with the real world of physical things.

I discovered I could glue a breadboard to the side of the base of this robotic arm, and that I could hold the arduino board to the base with elastic bands. and that the adafruit motor board left 5 analog pins free to use, and that I could put a switch, a potentiometer and an hbridge in the breadboard with these five free pins. And that I could substitute the broken led with a new one with my soldering iron 😀

It is now all ready and working. Every time I hold down the switch button it activates one of the five motors iteratively. With the potentiometer I can have the motor run in one direction or the other. And the LED at the hand of the robot arm shines while the button is pressed.

The only problem pending is I need to change all the worn out gears from the motors as they are eroded from previous experiments (the problem with dc motors as opposed to servo motors is that you can’t know where they are, so I overextended them eroding the gears)

Machine Learning 101

I started self-training on machine learning. I bought a copy of “Hands-On Machine Learning with Scikit-Learn, Keras & Tensorflow” and am enjoying it a lot. I have a small moleskine with which I break down the concepts one day at a time 🙂

So far I have not yet encountered any concept which is not trivial. This means I am progressing. In my experience things are either trivial or impossible. Our job is to break down impossible tasks until they become trivial 🙂

Setting up Lightning Network [3/3] – what to do with your lnd node?

Now that you have your node set up and you have established a few channels you can start routing payments. You can see my node here I have opened three channels for now, and with it I am able to route payments anywhere.

You can set up a tippin.me account to receive tips in satoshis. It creates a custodial lighning wallet where people can send you tips. You can send me some satoshis at https://tippin.me/@Rogeman (as of today 1 satoshi equals 0.00003416 Euros, so don’t be shy, if you go wild and send 1,000 satoshis it will be 3 cents of a euro 😉 )

To send a tip to tippin.me you need to use the payinvoice command, instead of the sendpayment command as you won’t have an invoice and you can send any amount you want.

lncli --lnddir /opt/lnd-data/ --no-macaroons  payinvoice --pay_req lnbc1pw8aa5app5t3zqgnsq2e80s47s33a4rqc4w3spvamwp5tch732zucgglcyefwqdph235hqurfdcs9ymm8v4kkzm3q9p6xjursd9hzumt99y582vfj8ycny2gcqzysxqyz5vqu05rc3mk3m5cteh8gsvh3pf696p4wfdeezq29kkxcdrwjmtj64njk5lj4nv4jul96jcsqvw94a57y4722lrzdygu87jfkw2leu9ceqqpqmmcgl --amt 100

On the testnet a very cool test to do is buy a Blockaccino at starbloqs, check out a video here

You can request others to send you money by sending them an invoice

lncli --lnddir /opt/lnd-data/ --no-macaroons addinvoice 100 --expiry 36000
{
        "r_hash": "f9ba7fd5b0be3d768c29aa951b4a215ea7e37133ebb41fd5a7d424e7981551de",
        "pay_req": "lnbc1u1pw8a7u6pp5lxa8l4dshc7hdrpf4223kj3pt6n7xufnaw6pl4d86sjw0xq4280qdqqcqzysxqypr9qfrglxdwv8jdc9xlsyatugwztdvsn89y4hmlm2mgds5wyl9k3c963uk66zhntp6940yxpfz5fa0au9mcg4c0sfc77eg589fmpnjhcs6gp49ghuh",
        "add_index": 1
}

Once you’ve created the invoice you can send the pay_req to the payer (in the above example lnbc1u1pw8a7u6pp5lxa8l4dshc7hdrpf4223kj3pt6n7xufnaw6pl4d86sjw0xq4280qdqqcqzysxqypr9qfrglxdwv8jdc9xlsyatugwztdvsn89y4hmlm2mgds5wyl9k3c963uk66zhntp6940yxpfz5fa0au9mcg4c0sfc77eg589fmpnjhcs6gp49ghuh)

Others can send you money with the sendpayment command by paying your invoice

lncli --lnddir /opt/lnd-data/ --no-macaroons sendpayment --pay_req=nbc1u1pw8a7u6pp5lxa8l4dshc7hdrpf4223kj3pt6n7xufnaw6pl4d86sjw0xq4280qdqqcqzysxqypr9qfrglxdwv8jdc9xlsyatugwztdvsn89y4hmlm2mgds5wyl9k3c963uk66zhntp6940yxpfz5fa0au9mcg4c0sfc77eg589fmpnjhcs6gp49ghuh

With your lightning network node you can send payments which are:

  • Borderless: The internet knows no boundaries, it has no borders, you can as seamlessly send payments within your country, your continent, your planet, or your solar system. In the future we may need to send money to mars!
  • Anonymous: Since payments are routed via a mesh of nodes which can’t see the whole end to end payment route, payments are anonymous. This is different to on-chain bitcoin payments, which are only pseudo-anonymous and can be tracked to you.
  • Instantaneous: Once you start playing with lnd you will see that it takes less than a second to route a payment. This is mindblowing if you think about it. Internet packets are being communicated throughout the planet, from one internet provider to another, from one router to another, from one lnd node to another, until they reach their destination.
  • Low cost: The nodes (yours as well) set the fees they want to charge to route payments. The route chosen is always the cheapest one so this incentivises nodes to reduce the fees. Sending payments over the lightning network costs cents of euro equivalent in satoshis.
  • World scale: Lightning is capable of millions to billions of transactions per second across the network. Visa, which is currently the benchmark can transfer less than 2,000 transactions per second.

One problem lightning network has is that you can only send or receive as much money as you have route bandwidth for, this means that if you want to be able to receive payments worth 500 Euro, you need to have channels open worth 500 Euro. This can be pretty expensive for high value payments. Due to this constraint the lightning network can work very well for low value payments, like buying a coffee, and not so well for high value payments like buying a house. In any case high value payments can be done directly using the bitcoin blockchain without using the lightning network layer and are usually not done in high volumes. (Maybe a third layer protocol could be used to spit large payments into groups of smaller ones similarly how tcp over ip is capable of splitting large packets of information into smaller ones and guarantee order and completeness, you could split a payment of 1000 satoshis into two payments of 500)

This is the future of how robots will pay each other.

Setting up lightning network [1/3] – Set up your bitcoind node

Lightning network is a Layer 2 protocol that sits on top of the bitcoin/litecoin blockchain. It enables instant, low cost, anonymous payments by routing payments through point to point channels in a similar way to what the correspondent banking system uses today to transfer fiat currency.

You can check out the map of channels of the lightning network at https://graph.lndexplorer.com/ as of today, there are 3488 nodes

In order to set up your lightning network node, first you need to set up your bitcoin node. Here you have simple instructions to set it up by compiling it from source.

First we clone the git repository for the bitcoin core node

sudo apt-get install git
mkdir $HOME/src
cd $HOME/src
git clone https://github.com/bitcoin/bitcoin.git

you will need libzmq3 in order for the lighning node to communicate with your bitcoin node, so we need to install libzmq3-dev

sudo apt install libzmq3-dev

now we configure and install the node

cd bitcoin
./autogen.sh
./configure
make
sudo make install

bitcoind is installed! 🙂 now we need to create a config file and create an rpc user and password so you can communicate with your bicoind node

./share/rpcauth/rpcauth.py roge
#This command will give you the user and password you will need to include in your bitcoin.conf
String to be appended to bitcoin.conf:
rpcauth=roge:793845a197311a324722f93e8360e166$3dfb9011930a6fcb85c99e0e1ad2e0309958b2aa863955faae831e0eeec3894f
Your password:
34ZofsEbG95rWITDv8w03crrzIYBioGAKfMqDq1yY1A=

Let’s create a directory where all bitcoin data will be stored. Be warned that this directory will hold a copy of the whole bitcoin blockchain which is as of today 243 GB.

We will copy a bitcoin.conf file to the bitcoin data folder

mkdir /opt/bitcoin-data/
cp $HOME/src/bitcoin/share/examples/bitcoin.conf /opt/bitcoin-data/

now we edit the bitcoin.conf file, the following variables are important

vi /opt/bitcoin-data/bitcoin.conf
#set testnet to 1 if you'd like to run a node for testing purposes not using real bitcoins.
testnet=1 
#set daemon=1 to launch bitcoind as a daemon running in the background
daemon=1
#set rpcauth to the rpcuser you created earlier
rpcauth=roge:793845a197311a324722f93e8360e166$3dfb9011930a6fcb85c99e0e1ad2e0309958b2aa863955faae831e0eeec3894f

We are set. Now we can start our bitcoind node with the following command. It could take one or two days to synchronise with the bitcoin blockchain.

 bitcoind --datadir=/opt/bitcoin-data/ -rpcuser=roge -rpcpassword=34ZofsEbG95rWITDv8w03crrzIYBioGAKfMqDq1yY1A=

you can monitor progress looking at debug.log

tail -333f /opt/bitcoin-data/debug.log

you can connect to your bitcoind node using bitcoin-cli which allows you to manage your node

 watch bitcoin-cli -datadir=/opt/bitcoin-data/ -rpcuser=roge -rpcpassword=34ZofsEbG95rWITDv8w03crrzIYBioGAKfMqDq1yY1A= getblockchaininfo

Now encrypt your wallet don’t forget this password. Write it down on a piece of paper and store that paper somewhere safe.

bitcoin-cli -datadir=/opt/bitcoin-data -rpcuser=roge -rpcpassword=34ZofsEbG95rWITDv8w03crrzIYBioGAKfMqDq1yY1A= -stdin encryptwallet
writehereyoursupersecretpassword
Ctrl-d

now you can get an address where to deposit bitcoin in (you can buy these bitcoins in exchange for fiat currencies such as Euros or Dollars in exchanges like kraken.com or blockchain.org) do not send real bitcoin to a testnet wallet, they will be lost. You can get free testnet bitcoins by googling testnet bitcoin faucet. Here’s one (link)

bitcoin-cli -datadir=/opt/bitcoin-data -rpcuser=roge -rpcpassword=34ZofsEbG95rWITDv8w03crrzIYBioGAKfMqDq1yY1A= getnewaddress
#This will return the new address where you can send bitcoin to
# the command will return something like 3NUvF2fvitxrU1fY43rCQivx9RtCgvXuEb

Once you have transferred bitcoins to your wallet you can see your balance

bitcoin-cli -datadir=/opt/bitcoin-data -rpcuser=roge -rpcpassword=34ZofsEbG95rWITDv8w03crrzIYBioGAKfMqDq1yY1A= getbalance
#This command will output your bitcoin balance
0.00001

In order to transfer bitcoins to another address you first need to unlock your wallet for x seconds

bitcoin-cli -datadir=/opt/bitcoin-data -rpcuser=roge -rpcpassword=34ZofsEbG95rWITDv8w03crrzIYBioGAKfMqDq1yY1A= -stdinn walletpassphrase
enteryoursupersecretpassword
enternumberofsecondsthatthewalletwillremainunlocked
Ctld-d

Now you can transfer bitcoin to another wallet

bitcoin-cli -datadir=/opt/bitcoin-data -rpcuser=roge -rpcpassword=34ZofsEbG95rWITDv8w03crrzIYBioGAKfMqDq1yY1A= sendtoaddress enterthedestinationaddress entertheamounttotransfer

You can find all the bitcoin-cli commands here: https://en.bitcoin.it/wiki/Original_Bitcoin_client/API_calls_list

Now that our bitcoin node is ready, let’s set up our lightning network node! 🙂

Playing with MongoDB

MongoDB is a nosql database. This means that you don’t use SQL to query the data, instead you use javascript and receive responses in json objects. I enrolled in course M001: Mongodb basics to get a basic understanding of how it works and it seems extremely easy.

mongodb-for-giant-ideas-bbab5c3cf8

The cool part about it being javascript based is that you can become a “full stack” web developer just by learning javascript. The front end with angular, and the backend with node.js and mongodb can be sufficient for you to build web apps. (I still shudder thinking that javascript is being used for anything, yet here we are..)

Mongodb is extremely easy to start playing with, for free you can create a database cluster in the cloud with 512MB by registering in mongodb.com and getting a Mongodb atlas.

MongoDB Compass is a graphical client with which you can connect to your database and analyse your data. It analyses the data and gives you insights on the types of data, you can also filter just by selecting with your mouse the data you want to filter on in an intuitive way.

The CLI is the best way to power-query your data. below my cheat-sheet after completing the basic training course:

MongoDB cheatsheet

  1. Show databases
    1. Shows the databases
  2. Show collections
    1. Once within a database , shows the collections
  3. Insert data
    1. db.moviesScratch.insertMany([],{“ordered”:false)
      1. With ordered:false, it does not stop when a duplicate _id key is found,
  4. Query data
    1. db.movies.find().pretty()
  5. Comparison operators
    1. Greater than
      1. db.movieDetails.find({runtime:{$gt:90}})
    2. Greater than and Less than
      1. db.movieDetails.find({runtime:{$gt:90, $lt:120}},{_id:0,title:1,runtime:1})
    3. Greater or equal, less or equal
      1. db.movieDetails.find({runtime:{$gte:90, $lte:120}},{_id:0,title:1,runtime:1})
    4. Not equals
      1. db.movieDetails.find({rated: {$ne:”UNRATED”}},{_id:0,title:1,runtime:1})
    5. In
      1. db.movieDetails.find({rated: {$in: [“G”,”PG”]}},{_id:0,title:1,runtime:1,rated:1})
  6. Filter for null or non existing fields
    1. db.movies.find({mpaaRating:{$exists:true}}).pretty()
    2. db.data.find({atmosphericPressureChange:{$exists:false}}).pretty().count()
  7. Filter fields by type (double, int, string…)
    1. db.movies.find({viewerRating:{$type:”double”}})
  8. Filter with multiple “OR”
    1. db.movieDetails.find({$or: [{“tomato.meter”:{$gt:95}},{“metacritic”:{$gt:88}}]},{_id:0,title:1,”tomato.meter”:1,”metacritic”:1})
    2. db.shipwrecks.find({$or:[{watlev:”always dry”},{depth:0}]}).count()
  9. Filter with multiple “AND” (this is only needed when we want to apply many filters on the same key
    1. db.movieDetails.find({$and: [{“metacritic”:{$ne:null}},{“metacritic”:{$exists:true}}]},{_id:0,title:1,”tomato.meter”:1,”metacritic”:1})
  10. Array field moderators
    1. Get all objects which contain elements in array
      1. db.movieDetails.find({genres:{$all: [“Comedy”,”Crime”,”Drama”]}},{_id:0, title:1, genres:1}).pretty()
    2. Get size of an array
      1. db.movieDetails.find({countries:{$size:1}}).count()
      2.  db.data.find({sections:{$size:2}}).count()
    3. Find a single object with multiple elements which match all the criteria
      1. db.movieDetails.find({boxOffice: {$elemMatch: {“country”: “Germany”, “revenue”: {$gt: 16}}}})
      2.  db.surveys.find({results:{$elemMatch:{“product”:”abc”,”score”:7}}}).count()
  11. Regular expressions
    1. db.movieDetails.find({“awards.text”: {$regex: /^Won.* /}}, {_id: 0, title: 1, “awards.text”: 1}).pretty()