Dedunu

  • Technology
  • Travel
  • GL.iNet Opal Travel Router

    I wrote about getting Surfshark. But I hate installing VPN applications on my iPhone and iPad. I bought a GL.iNet Opal (GL-SFT1200) router. It can work as a router. It can work like a Wi-Fi repeater or extender and make a hotspot from tethering too. It is suitable for travel and powered by a USB-C port.

    It is very easy to set up and replaced my old Wi-Fi access point so that I don’t have to connect from all the devices. I connected my internet connection via Ethernet. I downloaded WireGuard configuration files from Surfshark. You can compress a bunch of configuration files and import them at once. I enabled DNS over TLS for advanced security.

    It can use multiple internet connections and do load balancing. I would love to try that with another router. Ethernet is fast; however, VPN with WireGuard is slower. It could be better, but you cannot ask for more for 35 EUR.

  • Is a VPN Worth It?

    I never really liked the idea of using a VPN for the longest time because I wasn’t convinced they did much, and honestly, I got by just fine without one. At first, I didn’t even bother paying for any VPN services. But then I gave Proton VPN a shot, and it totally changed my mind about online privacy and security. After that, I was curious to see what else was out there, so I checked out Surfshark. Their basic package caught my eye—it’s super affordable at just 43 USD for 27 months, which felt like a pretty sweet deal to me!

    Do I even need a VPN?

    Using a VPN just slows me down, you know? Honestly, there are a bunch of reasons to ditch it. The speed is such a buzzkill, captchas drive me nuts, and my online payments might get shot down because I’m browsing from a different spot. Plus, some sites just outright block VPN IPs without a second thought.

    Let’s look on the bright side! I can check out stuff that I normally can’t access, which is pretty sweet. Some free shows are just a click away. Plus, I can snag online subscriptions wherever they’re the cheapest. A lot of those services hit European customers with extra fees, but I’ve figured out how to switch countries and grab the service from cheaper spots. It kinda makes the VPN subscription worth it!

  • Exploring WordPress.com: An Exciting Return

    I used WordPress a long time ago to host my blog. I used WordPress.com for a while. After a while, I decided to move away and switched to a few blogging platforms such as Blogger and Jekyll on GitHub Pages and Netlify too.

    I got WordPress.com free hosting for two years, and I decided to move my website here. It is clear that WordPress.com has come a long way. All the tools and features that it offers are amazing. I moved a lot of blog posts easily. I would write a series of blog posts about how to work with WordPress.com soon.

    I moved to a new domain from dedunu.info to dedu.nu as well. I am very excited about that too. I have been eyeing the dedu.nu domain for a while.

    I think I miss writing. I am planning to write more posts, both technical and business-related. I am excited.

  • Latest Insights on Colombo Stock Exchange Investments

    I enjoy keeping up with the latest news and trends regarding the Colombo Stock Exchange. I am eager to share this information with anyone interested.

    Stay informed and enjoy!

    Almas Equities Research – https://whatsapp.com/channel/0029Va9G19YL2ATreIUWuB0t

    Asha Securities – https://whatsapp.com/channel/0029VaaULWzEFeXlQoNfu53w

    Ambeon Research – https://whatsapp.com/channel/0029VaJD2hx4o7qK1V34OM1T

    Bartleet Stock (BRS) – https://whatsapp.com/channel/0029VaGggAdLI8YOorwNDM0U

    Capital TRUST Securities – https://whatsapp.com/channel/0029VaSF2aBHwXb3OnppE841

    First Capital Invest – https://whatsapp.com/channel/0029VaQdq7o3GJOsKQFz6G2v

    First Capital Trading Insights – https://whatsapp.com/channel/0029VaLNule1XquaQ34cYr2U

    John Keells Stock Brokers – https://whatsapp.com/channel/0029VaLB8MUHVvTk898ykk3h

    LOLC Securities – https://chat.whatsapp.com/HxmDltlRXcOK9jaNb34682

    Softlogic Stockbrokers – https://whatsapp.com/channel/0029VaA2D5qBFLgMWh0mux1v

  • Migrating SQLite to PostgreSQL with Grafana

    To migrate your SQLite database to PostgreSQL, you can use pgloader. Follow these steps to complete the migration:

    • First, acquire the Grafana PostgreSQL schema from a test environment. The schema for Grafana version 12.0.1 is available at the following link: Grafana PostgreSQL Schema.
    • Save the schema as grafana.sql.
    • Use the psql command to restore the schema into your PostgreSQL database:
    psql -h localhost -p 5432 -U postgres -d grafana -f grafana.s
    
    • Install pgloader using Homebrew:
    brew install pgloader
    
    
    • Create a file named grafana.load with the following content to define the migration process:
    load database
    from '/Users/john/path/to/grafana-sqlite.db'
    into postgresql:///grafana:password@localhost:5432/grafana
    
    with data only, reset sequences
    set work_mem to '16MB', maintenance_work_mem to '512 MB';
    
    
    • Execute the migration using pgloader:
    pgloader grafana.load
    
    
    • Update your Grafana configuration to point to the new PostgreSQL database:
    GRAFANA_DATABASE_HOST=localhost
    GRAFANA_DATABASE_PORT=5432
    GRAFANA_DATABASE_USER=grafana
    GRAFANA_DATABASE_PASSWORD=password
    GRAFANA_DATABASE_NAME=grafana
    
    
    • Finally, restart the Grafana server to apply the changes:
    sudo systemctl restart grafana-server
    
    

    By following these steps, you will successfully migrate your Grafana SQLite database to PostgreSQL.

    Note: LLMs were harmed in the making of this document.

  • Building a WiFi Clock with Raspberry Pi Pico W

    You will need these three items.

    • Raspberry Pi Pico W with soldered headers – https://www.raspberrypi.com/products/raspberry-pi-pico-2/
    • Grove Shield for Pi Pico – https://www.seeedstudio.com/Grove-Shield-for-Pi-Pico-v1-0-p-4846.html
    • Grove – OLED Display 0.66” (SSD1306) – https://www.seeedstudio.com/Grove-OLED-Display-0-66-SSD1306-v1-0-p-5096.html

    Total cost should be around 15 USD. I attached the OLED display to I2C.

    Close-up of a Grove OLED display showing the time '09:52', with a connected multi-colored wire on a wooden surface.

    The code is trying to connect to Wifi and set time from time.google.com. The contrast was set to 0 to make it easier to read. You may want to adjust that. I am drawing digits manually to see them clearly. If you have a different display that will make it easier too.

    import network
    import ntptime
    import time
    
    from machine import Pin, I2C
    from ssd1306 import SSD1306_I2C
    
    SSID = "<SSID>"
    PASSWORD = "<WIFI PASSWORD>"
    
    led = machine.Pin("LED", machine.Pin.OUT)
    wlan = network.WLAN(network.STA_IF)
    
    i2c = I2C(1, scl=Pin(7), sda=Pin(6), freq=200000)
    oled = SSD1306_I2C(64, 48, i2c)
    
    def show_text(message):
        oled.fill(0)
        x = 0
        y = 0
        for char in message:
            oled.text(char, x, y)
            x = x + 8
            if x > 64:
                y = y + 8
                x = 0
        oled.show()
    
    def connect_internet():
        led.on()
        wlan.active(True)
        wlan.connect(SSID, PASSWORD)
        
        # Wait for connection to establish
        max_wait = 10
        while max_wait > 0:
            if wlan.status() < 0 or wlan.status() >= 3:
                    break
            max_wait -= 1
            
            print('waiting for connection...')
            show_text('waiting' + str(max_wait))
            time.sleep(1)
        
        # Manage connection errors
        if wlan.status() != 3:
            show_text('failed')
            print('Network Connection has failed')
        else:
            show_text('connected')
            print('connected')
            status = wlan.ifconfig()
            print( 'ip = ' + status[0] )
            led.off()
    
    def print_time(display, number, position):
        start_x = position * 16
        
        if number == 0:
            display.fill_rect(start_x + 12,  2,  4, 46, 1)
            display.fill_rect(start_x +  2,  2,  4, 46, 1)
            display.fill_rect(start_x +  2,  2, 14,  4, 1) 
            display.fill_rect(start_x +  2, 44, 14, 14, 1) 
            
        if number == 1:
            display.fill_rect(start_x + 12,  2,  4, 46, 1)
        
        if number == 2:
            display.fill_rect(start_x +  2,  2, 14,  4, 1) 
            display.fill_rect(start_x + 12,  2,  4, 22, 1) 
            display.fill_rect(start_x +  2, 24, 14,  4, 1) 
            display.fill_rect(start_x +  2, 24,  4, 22, 1) 
            display.fill_rect(start_x +  2, 44, 14, 14, 1)
            
        if number == 3:
            display.fill_rect(start_x + 12,  2,  4, 46, 1) 
            display.fill_rect(start_x +  2,  2, 14,  4, 1) 
            display.fill_rect(start_x +  2, 24, 14,  4, 1) 
            display.fill_rect(start_x +  2, 44, 14, 14, 1)
            
        if number == 4:
            display.fill_rect(start_x + 12,  2,  4, 46, 1)
            display.fill_rect(start_x +  2, 24, 14,  4, 1) 
            display.fill_rect(start_x +  2,  2,  4, 24, 1)
            
        if number == 5:
            display.fill_rect(start_x +  2,  2, 14,  4, 1)
            display.fill_rect(start_x +  2,  2,  4, 24, 1)
            display.fill_rect(start_x +  2, 24, 14,  4, 1)
            display.fill_rect(start_x + 12, 24,  4, 24, 1)
            display.fill_rect(start_x +  2, 44, 14, 14, 1)
            
        if number == 6:
            display.fill_rect(start_x +  2,  2, 14,  4, 1)
            display.fill_rect(start_x +  2,  2,  4, 24, 1)
            display.fill_rect(start_x +  2, 24, 14,  4, 1)
            display.fill_rect(start_x + 12, 24,  4, 24, 1)
            display.fill_rect(start_x +  2, 44, 14, 14, 1)
            display.fill_rect(start_x +  2, 24,  4, 22, 1)
            
        if number == 7:
            display.fill_rect(start_x +  2,  2, 14,  4, 1)
            display.fill_rect(start_x + 12,  2,  4, 46, 1)
            
        if number == 8:
            display.fill_rect(start_x + 12,  2,  4, 46, 1)
            display.fill_rect(start_x +  2,  2,  4, 46, 1)
            display.fill_rect(start_x +  2,  2, 14,  4, 1) 
            display.fill_rect(start_x +  2, 24, 14,  4, 1) 
            display.fill_rect(start_x +  2, 44, 14, 14, 1)
            
        if number == 9:
            display.fill_rect(start_x + 12,  2,  4, 46, 1)
            display.fill_rect(start_x +  2,  2, 14,  4, 1) 
            display.fill_rect(start_x +  2, 24, 14,  4, 1)
            display.fill_rect(start_x +  2,  2,  4, 24, 1)
    
    oled.contrast(255)
    oled.fill(0)
    print_time(oled, 9, 0)
    print_time(oled, 6, 1)
    print_time(oled, 9, 2)
    print_time(oled, 6, 3)
    oled.show()
    
    connect_internet()
    ntptime.host = "time.google.com"
    ntptime.settime()
       
    while True:
        now_time = time.localtime(time.time()+7200)
        position = 0
        
        oled.fill(0)
        oled.contrast(0)
        hour = now_time[3]
        
        if hour > 12:
            hour = hour - 12
            
        if len(str(hour)) < 2:
            print_time(oled, 0, position)
            position = 1
        for character in str(hour):
            print_time(oled, int(character), position)
            position = position + 1
            
        if len(str(now_time[4])) < 2:
            print_time(oled, 0, position)
            position = position + 1
            
        for character in str(now_time[4]):
            print_time(oled, int(character), position)
            position = position + 1
            
        oled.show()
        time.sleep(30)
    
    

    The clock in action:

    Close-up of a Grove OLED display showing the time '0952', with wires connected, placed on a wooden surface.
  • Sandisk Clip Jam MP3 Player for Audiobooks

    I love listening to audiobooks. I do it during the commute and travel. I was using the iPhone Books app initially. But I cannot afford to drain my iPhone battery during trips. It is a bit tricky to add books to Apple Books. I didn’t enjoy the process. I always need my MacBook to load them. The app doesn’t support Linux.

    I was looking for an MP3 player. I found a couple of devices. It came down to the Sony NWE394 and the SanDisk Clip Jam 8GB. I found a cheaper Sony NWE394. I purchased it. Even though the listing said it would be new, it wasn’t. I returned it immediately.

    I ordered a SanDisk Clip Jam. I purchased the 8GB version. The package included a basic earphone. It is not super high quality, but for audiobooks, it will do. I used Apple earphones instead.

    These are my findings:

    • The battery is excellent. I listen to audiobooks for 4-5 hours (even longer without charging again).
    • It turns off automatically. I love this feature.
    • MP3 format works very well! Dah!
    • M4B format is not supported.
    • The Clip Jam creates a “.POS” file to track the progress. It allows you to resume from the last checkpoint. This feature is ideal for audiobooks.
    • The order of files is a bit tricky. I use “A, B, C” prefixes to keep files in order.
    • The documentation says something about the playlist. I didn’t try it myself. I will update the post if it works.
    • I didn’t use Audible Audiobooks. But the product description says it is supported.
    • The Clip Jam works with Linux very well.

  • Poetry fails with an SSH error

    One of my collegues has an issue with poetry. Error message is mentioned below.

    ssh: Could not resolve hostname https: Name or service not known

    We found out that .gitconfig has an empty http.proxy section.

    [user]
    	name = John Doe
    	email = John.Doe@example.com
    [http]
    	proxy = 

    We removed last two lines. It worked!

  • Switched to Arch Linux

    Screenshot of an Arch Linux desktop environment featuring a file manager and terminal window, with a background of a mountainous landscape.

    I have had enough with Ubuntu. I have been using Ubuntu since 2008. It was great. It was easy to install. It had everything I wanted out of the box.

    But recently, I have been annoyed with multiple things. First one is snap package manager. It is irritating to use. Firefox is an snap on Ubuntu. It has some font issues. Firefox is too slow to use.

    Ubuntu installation is around 6 GB right now. It has grown so much. I remember it used to fit into a CD. I was having a lot of hardware issues with non-LTS versions. (Laptop lid related stuff mainly)

    Last but not least, Ubuntu is pushing Ubuntu Pro on desktop customers. Canonical is holding back security packages until users make an Ubuntu account. It is free up to 5 PCs per account. I don’t want that.

    I tried to switch to Debian. I bought a cheap refurbished mini-PC. It came with a Wifi USB Stick. Debian didn’t like it that much.

    I decided to give Arch Linux a try. The install was quick. It didn’t download a lot of packages. It came with a minimal GNOME. I didn’t like the Console app that much. I got used to it slowly. But it is suprisingly fast. GUI is very responsive. The mini-PC I bought has a 4th generation i5 processor with 8GB.

    Arch Linux is easy to customize. Most of my favorite CLI tools aren’t installed. But it was available via pacman. I didn’t like pacman that much. It keeps a lot of packages in cache, even after they are installed. But you have the option to clean it.

    Firefox is no longer a snap. It is very fast. I like using Firefox again. Since Arch has a rolling release, I don’t have to reinstall/upgrade the system a lot. I use Vagrant/Docker and VirtualBox for my testing. I am trying to keep my system clean and usable for a long time.

    I installed an icon pack and a cursor to make it eye candy. I upgraded the RAM to 16GB to several VMs on this PC. I wish I switched to Arch Linux long time ago. Honestly, it is not that complicated to install and configure. I had very little to configure.

    PS: BTW I use Arch

  • Terraform: AWS Backup Policies

    This is an example how to enforce AWS backup with Organizational Backup Policies. Users on sub-accounts cannot edit these rules. You can ensure that these policies are not changed anywhere else other than the organizational policy section. You have to create these on the root account.

    provider.tf

    provider "aws" {
      region  = "us-east-1"
    }
    

    backend.tf

    terraform {
      required_version = ">= 1.6.1"
      required_providers {
        aws = {
          source  = "hashicorp/aws"
          version = "~> 5.0"
        }
      }
    }
    

    organizational_policy.tf

    resource "aws_organizations_policy" "plan_1_policy" {
      name = "dedunu-info-backup-plan-1-policy"
      type = "BACKUP_POLICY"
    
      content = jsonencode(local.plan1)
    }
    
    resource "aws_organizations_policy_attachment" "plan_1_policy_attachment" {
      policy_id = aws_organizations_policy.plan_1_policy.id
      target_id = "&lt;account-id>"
    }
    
    locals {
      plan1 = {
        "plans" : {
          "dedunu-info-backup-plan-1" : {
            "regions" : {
              "@@assign" : [
                "us-east-1",
                "us-east-2"
              ]
            },
            "rules" : {
              "dedunu-info-backup-plan-1-rule" : {
                "schedule_expression" : { "@@assign" : "cron(0 5 ? * * *)" },
                "target_backup_vault_name" : { "@@assign" : "aws-backup-vault" },
                "start_backup_window_minutes" : { "@@assign" : "60" },
                "complete_backup_window_minutes" : { "@@assign" : "180" },
                "enable_continuous_backup" : { "@@assign" : "false" },
                "lifecycle" : {
                  "delete_after_days" : { "@@assign" : "14" }
                },
                "recovery_point_tags" : {
                  "Owner" : {
                    "tag_key" : { "@@assign" : "cost-center" },
                    "tag_value" : { "@@assign" : "longterm-backup" }
                  }
                },
              }
            },
            "selections" : {
              "tags" : {
                "dedunu-info-backup-plan-1-selection" : {
                  "iam_role_arn" : { "@@assign" : "arn:aws:iam::$account:role/service-role/AWSBackupDefaultServiceRole" },
                  "tag_key" : { "@@assign" : "backup" },
                  "tag_value" : { "@@assign" : ["dedunu-backup-daily-plan-1"] }
                }
              }
            }
          }
          }
      }
    }
    

←Previous Page
1 2 3 4 … 17
Next Page→
 

Loading Comments...