Posts

All Posts

  • Zero Export Pv System

    Introduction

    A zero export PV system is a solar photovoltaic (PV) system designed to ensure that any electricity generated by the solar panels is consumed on-site and not fed back into the utility grid. Essentially, it prevents the export of excess solar energy to the grid.

    • On-site Consumption: The primary goal is to maximize the use of solar energy for the homeowner’s or building’s own electricity needs.
    • No Export to the Grid: Zero export systems are engineered to avoid sending any surplus solar power into the public power grid.
    • Grid Stability and Regulations: This approach is often implemented when local grid operators restrict or prohibit the export of solar energy due to concerns about grid stability or to comply with specific regulations.
    • Dynamic Power Regulation: Zero export systems dynamically adjust the solar inverter’s power output to match the building’s electricity consumption in real-time, ensuring no excess power is generated.
    • Alternatives to Export: Instead of exporting excess energy, zero export systems may utilize battery storage to store the surplus for later use, or simply reduce solar production to match on-site consumption.

    My PV System

    I started with a 600 Watt Microinverter and two 380 Watt Solarpananels, I then built a receiver with a ESP32 microcontroller and a 2.4Ghz transceiver to receive status information from the microinverter which sends out serial data over 2.4Ghz when triggered. more info here

    • CopyQ on CapsLock

      Remapping CapsLock to run Kmonad Script

      Let’s say we want to deactivate the physical CapsLock Button, causing it to no longer send the keycode 66. In Gnome we can do that using the Gnome Tweak Tool for example. Because I want to toggle my Clipboard Manager Window by hitting the CapsLock Button to open up CopyQ I was looking for a solution I could use with Wayland. Thankfully I found Kmonad After some fiddeling around I managed to understand how to set it up, you can do a lot more compared to my simple task of binding a shell script to a Button on my Keyboard. So here are my config files:

      • Terraform

        Tutorial - hcloud-terraform - source

        How-to: Install Fedora CoreOS at Hetzner Cloud - source

        Oh My ZSH encourages users (in the final section of .zshrc file) to put personal configurations like alias and themes into the directory set as the $ZSH_CUSTOM.

        I think it is a good idea to keep all your configurations in this directory, including your path customization. That way you can easily include it to your backups, and restore when necessary.

        • Hyprland

          Pypr - monitors

          # pyprland.toml - draft
          [pyprland]
          plugins = ["expose","monitors"]
          
          [monitors]
          [monitors.placement]
          "Dell Inc. DELL P2719H BDFS123".leftOf = "Dell Inc. DELL U2720Q 5TCZZ13"
          "LG Electronics LG TV 0x01010101".rightOf = ["Dell Inc. DELL P2719H BDFS123",
          "Dell Inc. DELL U2720Q 5TCZZ13"]

          Waybar - config.jsonc

          [{
          	"layer": "top",
          	"position": "top",
          	"output": ["DP-3"],
            "width": 1080,
          	"include": [
          		"~/.config/waybar/default-modules.jsonc",
          	],
            "modules-left": [
              "hyprland/workspaces"
            ],
            "modules-center": [
                  "hyprland/window"
            ],
          	"modules-right": [
          		"clock"
          	]
          },
          {
          	"layer": "top",
          	"position": "top",
          	"output": ["DP-5"],
            "width": 2560,
          	"include": [
          		"~/.config/waybar/default-modules.jsonc",
          	],
            "modules-left": [
              "hyprland/workspaces"
            ],
            "modules-center": [
                  "hyprland/window"
              ],
          	"modules-right": [
              "custom/weather",
              "cpu",
              "memory",
              "network",
              "temperature",
              "pulseaudio",
              "idle_inhibitor",
              "tray",
              "clock",
              "custom/wlogout"
          	],
            "network": {
                  // "interface": "wlp2*", // (Optional) To force the use of this interface
                  "format-wifi": "{essid} ({signalStrength}%) ",
                  "format-ethernet": "{ipaddr}/{cidr} ",
                  "tooltip-format": "{ifname} via {gwaddr} ",
                  "format-linked": "{ifname} (No IP) ",
                  "format-disconnected": "Disconnected ⚠",
                  "format-alt": "{ifname}: {ipaddr}/{cidr}"
            },
            "cpu": {
              "format": " {usage: >3}%",
              "on-click": "alacritty -t waybar_btop -e btop"
            },
            "memory": {
                  "format": "{}% "
            },
            "temperature": {
                  // "thermal-zone": 2,
                  "hwmon-path": ["/sys/class/hwmon/hwmon2/temp1_input"],
                  "critical-threshold": 80,
                  "format-critical": "{temperatureC}°C {icon}",
                  "format": "{temperatureC}°C {icon}",
                  "format-icons": ["", "", ""]
            },
            "pulseaudio": {
                  // "scroll-step": 1, // %, can be a float
                  "format": "{volume}% {icon} {format_source}",
                  "format-bluetooth": "{volume}% {icon} {format_source}",
                  "format-bluetooth-muted": " {icon} {format_source}",
                  "format-muted": " {format_source}",
                  "format-source": "{volume}% ",
                  "format-source-muted": "",
                  "format-icons": {
                      "headphone": "",
                      "hands-free": "",
                      "headset": "",
                      "phone": "",
                      "portable": "",
                      "car": "",
                      "default": ["", "", ""]
                  },
                  "on-click": "pavucontrol"
              },
              "idle_inhibitor": {
                  "format": "{icon}",
                  "format-icons": {
                      "activated": "",
                      "deactivated": ""
                  }
              },
              "tray": {
                  // "icon-size": 21,
                  "spacing": 10
              },
              "custom/weather": {
              "exec": ".config/waybar/scripts/weather.sh City+Country",
              "return-type": "json",
              "format": "{}",
              "tooltip": true,
              "interval": 3600
            },
            "custom/wlogout": {
              "format": "",
              "interval": "once",
              "on-click": "wlogout -c 5 -r 5 -p layer-shell",
            }
          
          },
          ]

          Wayabar - default-modules

          {  // ROMAN Numerals style
            "hyprland/workspaces#roman": {
                "active-only":false,
                "all-outputs": true,
                "format": "{icon}",
                "show-special": false,
                "on-click": "activate",
                "on-scroll-up": "hyprctl dispatch workspace e+1",
                "on-scroll-down": "hyprctl dispatch workspace e-1",
                "persistent-workspaces":{
                    "1": [],
                    "2": [],
                    "3": [],
                    "4": [],
                    "5": [],
                },
                "format-icons": {
                  "1": "I",
                  "2": "II",
                  "3": "III",
                  "4": "IV",
                  "5": "V",
                  "6": "VI",
                  "7": "VII",
                  "8": "VIII",
                  "9": "IX",
                  "10": "X",
                  
                },
            }
          }

          • SQL

            Basics

            Fundamental Syntax

            • SELECT
            • FROM
            • WHERE
            • GROUP BY
            • HAVING
            • ORDER BY
            • LIMIT

            Types of Joins - PostgreSQL-Docs

            • INNER JOIN
            • LEFT JOIN
            • RIGHT JOIN
            • FULL OUTER JOIN

            Joins of all types can be chained together or nested: either or both of T1 and T2 may be joined tables. Parentheses may be used around JOIN clauses to control the join order. In the absence of parentheses, JOIN clauses nest left-to-right.

            To put this together, assume we have tables t1

            • Kubernetes

              Index

            • CI/CD

              CI/CD

              Definition

              source
              In software engineering, CI/CD or CICD is the combined practices of continuous integration (CI) and continuous delivery (CD) or, less often, continuous deployment. They are sometimes referred to collectively as continuous development or continuous software development.

              • Pipelines

                What is a CI/CD pipeline? - source

                A CI/CD pipeline automates your software delivery process. The pipeline builds code, runs tests (CI), and safely deploys a new version of the application (CD).

                Automated pipelines remove manual errors, provide standardized feedback loops to developers, and enable fast product iterations.

                Hugo CI/CD Pipeline - source

                image: registry.gitlab.com/pages/hugo/hugo_extended:latest
                
                variables:
                  HUGO_ENV: production
                  THEME_URL: "github.com/alex-shpak/hugo-book"
                
                default:
                  before_script:
                    - apk add --no-cache go curl bash nodejs
                    - hugo mod get -u $THEME_URL
                
                pages:
                  script:
                  - hugo
                  artifacts:
                    paths:
                    - public
                  rules:
                  - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

                Python Poetry CI/CD Pipeline

                # This file is a template, and might need editing before it works on your project.
                # To contribute improvements to CI/CD templates, please follow the Development guide at:
                # https://docs.gitlab.com/ee/development/cicd/templates.html
                # This specific template is located at:
                # https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Python.gitlab-ci.yml
                
                # Official language image. Look for the different tagged releases at:
                # https://hub.docker.com/r/library/python/tags/
                image: python:latest
                
                # Change pip's cache directory to be inside the project directory since we can
                # only cache local items.
                variables:
                  PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip"
                
                stages:
                  - test
                  - lint
                  - types
                  - deploy
                
                # https://pip.pypa.io/en/stable/topics/caching/
                cache:
                  paths:
                    - .cache/pip
                
                before_script:
                  - python --version ; pip --version  # For debugging
                  - pip install poetry
                  - poetry install
                  - source `poetry env info --path`/bin/activate
                
                
                Unit Tests:
                  stage: test
                  script:
                    - echo "This is the test stage."
                    - cd tests
                    - poetry --version
                    
                Python Code Lint:
                  stage: lint
                  script:
                    - echo "let's do some linting."
                    - black .
                
                Static Type check:
                  stage: types
                  script:
                    - echo "let's do some type checking."
                    - mypy .
                
                Deploy:
                  stage: deploy
                  script:
                    - echo "let's deploy some code."

                GitLab CI Pipeline - source

                # Work in Progress Pipeline for GitLab CI
                
                default:
                  image: python:3.9 
                
                before_script:
                  - pip install poetry
                  - poetry install
                  - source `poetry env info --path`/bin/activate 
                
                stages:
                  - test
                  - build 
                
                testing:
                  stage: test
                  script:
                    - echo "This is the test stage"
                    - cd tests
                    - python3 -m unittest -v
                    - pytest --junitxml=report.xml
                  artifacts:
                    when: always
                    reports:
                      junit: /builds/USERNAME/python-devop/tests/report.xml
                
                building:
                  stage: build
                  needs: [testing]
                  script:
                    - echo "This is the build stage"
                    - poetry config repositories.gitlab https://gitlab.example.de/path/to/packages/pypi
                    - echo "Repository gitlab configured ..."
                    - poetry build
                    - echo "Build done ..."
                    - poetry publish --repository gitlab -u YOURUSERNAME -p YOURTOKEN
                    - echo "Publishing done!"

                Advanced Pipeline Examples

            • E Commerce

              E-Commerce Knowledgebase

              • GA4 Big Query

                Google Analytics 4

                Introduction to Google Analytics 4

                source: https://develop… Google Analytics 4 is an analytics service that lets you to measure traffic and engagement across your websites and apps. This documentation provides implementation instructions and reference materials geared towards a developer audience.

                Add the GA4 configuration tag to your website

                Prerequisites

                Default conversion value options

                source: https://support.goo…

              • Performance

                Business Performance Measures

                source: https://www.skillmaker.edu.au/business-…

                Business performance measures are a set of quantifiable metrics taken from various sources that together with an appropriate analytical process, allows the management of a business to track and assess the current status of a specific business, project or process. Business performance measures may be compared with pre-set goals and objectives or form part of a balanced scorecard that assesses financial or non-financial performance in the four primary areas of financial, learning/growth, internal processes and the customer. Business performance measures may also be known as organizational performance, results or key success indicators and are closely related to an organisation’s key performance indicators (KPI).

            • Cloud

              Hyperscaler Demos

            • Grafana

              Grafana is a multi-platform open source analytics and interactive visualization web application. It provides charts, graphs, and alerts for the web when connected to supported data sources.

              Prerequisites

              • hetzner - vServer - CPX21
                • 3 VCPU
                • 4 GB RAM
                • 80 GB DISK LOKAL
              • OS - Fedora 39
              • packages
                • zsh
                • oh-my-zsh
                • sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
                • tmux
                • neovim - LazyVim
                • fail2ban
                • sendmail
                • ufw
                • nginx
                • letsencrypt - steps to do
                • certbot, python3-certbot-nginx
                • postgres-server
                • grafana

              Configuration

              Screenshots

              Screenshot Screenshot

              • USB-Flashdrive-Notes

                1. Wipe Master Boot Record

                • Talking about MBR-style partitions…

                    dd if=/dev/zero of=/dev/[disk device] bs=1 count=64 seek=446 conv=notrunc
                • Explanation:

                    dd
                • This standard command copies bytes from a source and writes them to a destination.
                  It’s the simplest flexible tool for this job.

                    if=/dev/zero
                • Here, we specify that we’re reading from /dev/zero, which is a special device which emits NUL bytes–zeros.

                    of=/dev/[disk device]
                • Here, we specify which device we’re writing to.

                  • Homeasisstant

                    Homeasisstant

                    • Wifi Mqtt Gateway

                      Developing a Wifi-Mqtt-Gateway

                      What does it do?

                      The gateway receives serial data from micro-inverters over 2.4ghz, generates a message that is published via Wifi to the mosquitto mqtt broker. In Node-Red we subscribe to the topic power/inverter and receive the message generated and sent by the mqtt broker.

                      Code sample.

                      The following tutorials can be a source for information.

                      #include <WiFi.h>
                      #include <PubSubClient.h>
                      
                      // Replace the next variables with your SSID/Password combination
                      const char* ssid = "XXXXXXXX";
                      const char* password = "XXXXXXXX";
                      
                      
                      // Add your MQTT Broker IP address, example:
                      //const char* mqtt_server = "192.168.1.144";
                      const char* mqtt_server = "192.168.178.138";
                      const char* mqtt_username = "XXXXXXX";
                      const char* mqtt_password = "XXXXXXX";
                      
                      
                      WiFiClient espClient;
                      PubSubClient client(espClient);
                      long lastMsg = 0;
                      char msg[50];
                      int value = 0;
                      
                      // LED Pin
                      const int ledPin = 4;
                      
                      void setup() {
                        Serial.begin(115200);  
                        setup_wifi();
                        client.setServer(mqtt_server, 1883);
                      
                        pinMode(ledPin, OUTPUT);
                      }
                      
                      void setup_wifi() {
                        delay(10);
                        // We start by connecting to a WiFi network
                        Serial.println();
                        Serial.print("Connecting to ");
                        Serial.println(ssid);
                      
                        WiFi.begin(ssid, password);
                      
                        while (WiFi.status() != WL_CONNECTED) {
                          delay(500);
                          Serial.print(".");
                        }
                      
                        Serial.println("");
                        Serial.println("WiFi connected");
                        Serial.println("IP address: ");
                        Serial.println(WiFi.localIP());
                      }
                      
                      
                      
                      void reconnect() {
                        // Loop until we're reconnected
                        while (!client.connected()) {
                          Serial.print("Attempting MQTT connection...");
                          // Attempt to connect
                          if (client.connect("ESP8266Client",mqtt_username,mqtt_password)) {
                            Serial.println("connected");
                            // Subscribe
                            client.subscribe("esp32/output");
                          } else {
                            Serial.print("failed, rc=");
                            Serial.print(client.state());
                            Serial.println(" try again in 5 seconds");
                            // Wait 5 seconds before retrying
                            delay(5000);
                          }
                        }
                      }
                      void loop() {
                        if (!client.connected()) {
                          reconnect();
                        }
                        client.loop();
                      
                        long now = millis();
                        if (now - lastMsg > 5000) {
                          lastMsg = now;
                          const char* testString = "Hello MQTT";
                          
                          Serial.println(testString);
                          client.publish("power/test", testString);
                        }
                      }

                    • Generic X86 64

                      Install Home Assistant Operating System

                      How to install Home Assistant on Generic x86-64 Hardware

                      Let’s follow this tutorial

                      What do we need?

                      In my case a used HP t630 Thin-Client. ebay-listing ebay-listing

                  • Micro Inverter

                    What it does.

                    The setup consits of 2 300 Watt solarpanels and a sg600md micro-inverter that can be be plugged directly into a wall socket. The micro-inverter transmits it’s serial console data over 2.4ghz and thanks to the NETSGPClient the output can be received by a lc12s module connected to an ESP32. From there an MQTT client sends the received data to mosquitto over wifi and depending on the topic the MQTT message will be processed by Node-Red. The next step is saving the power statistics in the mqtt message to a database for visual representation in grafana.

                    • Hugo Setup

                      Hugo Gitlab Hetzner Setup

                      How to set up the Hugo static site generator using gitlab pages and a hetzner subdomain.

                      Prerequisites

                      See gohugo.io for details.

                      • Install Git
                      • Install Hugo (extended edition, v0.112.0 or later)

                      Getting some context before starting

                      A helpfull video by Luke Smith, together with his github repo about Hugo helps understand the structure of hugo a little quicker.

                      Setting up a git repository and pushing it to gitlab

                      Following the manual on gohugo.io we create our repository like this.