Uncategorized

OpenCV on Raspberry Pi in 2024

I’m using a Raspberry Pi 3B+ and I had many errors when trying to install OpenCV. I think the general thing to follow is not to install the latest versions.

This worked for me:

  • Raspberry Pi Legacy OS (bullseye)
  • pip install opencv-python==4.6.0.66
Uncategorized

Raspberry Pi + 3.5 inch touch screen

If you purchased something like this “3.5 inch HDMI-compatible Mini Touch Screen 480×320 LCD Display +ABS Case Box for Raspberry Pi 3B+/3B/2B” and are trying to get it to work in 2024 for your Raspberry Pi, then don’t use the latest Raspberry Pi OS, use the legacy version (https://www.raspberrypi.com/software/operating-systems/#raspberry-pi-os-legacy)

Uncategorized

Nginx Proxy Manager

Installation

Explained here (link)

Errors

“the map directive is not allowed here”

The latest docker image (as of 8th Feb 2024) has an issue when adding custom locations to a proxy host. It fails validation with “the map directive is not allowed here” and stays offline. This is a bug in their code but some clever person has a solution; use their docker image “jc21/nginx-proxy-manager:github-pr-3478”.

Source: https://github.com/NginxProxyManager/nginx-proxy-manager/pull/3478

Uncategorized

Self-hosting

Forward 443 ports in openwrt:
– create traffic rule to allow 443 from wan to device
– create port forwarding to wan 443 to nginx proxy host 443

Add proxy host in nginx proxyhost to redirect traffic from app1.endratek.com to your local app 10.0.0.3:3000

Uncategorized

Laravel

Install PHP

sudo apt install php php-xml php-curl

Install Composer

Reference: https://getcomposer.org/download/

Put the following in a script and execute it:

php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php -r "if (hash_file('sha384', 'composer-setup.php') === 'e21205b207c3ff031906575712edab6f13eb0b361f2085f1f1237b7126d785e826a450292b6cfd1d64d92e6563bbde02') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
php composer-setup.php
php -r "unlink('composer-setup.php');"

Create example project

composer create-project laravel/laravel example-app

Install Packages

composer install

Run app

php artisan key:generate

php artisan serve

Other packages to install

sudo apt install php-zip

Maybe a database…?

sudo apt install php-mysql

sudo apt install mysql-server

AWS

AWS Cognito Custom Emails

If you want to customise the auto generated emails from Cognito then you need to use Lambda to send your own emails. In this example, the custom emails are stored in an S3 bucket as HTML files. The lambda function retrieves the HTML file when needed and emails it to the user.

Click the “Add Lambda trigger” button.

Click on the “Messaging” option.

Click “Create Lambda function”

Create a new blank lambda function and add this code in a new file called “s3.mjs”:

import { GetObjectCommand, S3Client } from "@aws-sdk/client-s3";

const client = new S3Client({
    region: 'ap-southeast-2'
});

export const getFile = async (bucketName, key) => {
  const command = new GetObjectCommand({
    Bucket: bucketName,
    Key: key
  });

  try {
    const response = await client.send(command);
    // The Body object also has 'transformToByteArray' and 'transformToWebStream' methods.
    const str = await response.Body.transformToString();
    return str;
  } catch (err) {
    console.error(err);
  }
};

Add this code to “index.mjs”:

import { getFile } from './s3.mjs';

const bucket = "yourbucketname";
const basePath = "yourapp";

export const handler = async (event) => {
    console.log(event);
    switch (event.triggerSource) {
        case "CustomMessage_SignUp": //Sign-up trigger whenever a new user signs him/herself up.
            return sign_up_message(event);
        case "CustomMessage_AdminCreateUser": //When the user is created with adminCreateUser() API
            return admin_create_user_message(event);
        case "CustomMessage_ResendCode": //When user requests the code again.
            return resend_code_message(event);
        case "CustomMessage_ForgotPassword": //Forgot password request initiated by user
            return forgot_password(event);
        case "CustomMessage_UpdateUserAttribute": //Whenever the user attributes are updated
            return update_user_attribute_message(event);
        case "CustomMessage_VerifyUserAttribute": //Verify mobile number/email
            return verify_user_attribute(event);
        case "CustomMessage_Authentication": //MFA authentication code.
            return authentication_message(event);
        default:
            return event;
    }
};

const sign_up_message = async(event) => {
    let email = event.request.usernameParameter;
    let code = event.request.codeParameter;
    // get HTML from S3
    var content = await getFile(bucket, basePath + "/email/VerificationCode.html");
    content = content.replace("${code}", code);
    event.response = {
        emailSubject: "YourApp - Confirm your sign up",
        emailMessage: content
    }
    return event
}

const admin_create_user_message = async(event) => {
    let email = event.request.usernameParameter;
    let code = event.request.codeParameter;
    // get HTML from S3
    var content = await getFile(bucket, basePath + "/email/VerificationCode.html");
    content = content.replace("${code}", code);
    event.response = {
        emailSubject: "YourApp - Your temporary password",
        emailMessage: content
    }
    return event
}

const resend_code_message = async(event) => {
    let email = event.request.usernameParameter;
    let code = event.request.codeParameter;
    // get HTML from S3
    var content = await getFile(bucket, basePath + "/email/VerificationCode.html");
    content = content.replace("${code}", code);
    event.response = {
        emailSubject: "YourApp - Resend code",
        emailMessage: content
    }
    return event
}

const forgot_password = async(event) => {
    let email = event.request.usernameParameter;
    let code = event.request.codeParameter;
    // get HTML from S3
    var content = await getFile(bucket, basePath + "/email/VerificationCode.html");
    content = content.replace("${code}", code);
    event.response = {
        emailSubject: "YourApp - Forgot password",
        emailMessage: content
    }
    return event
}

const update_user_attribute_message = async(event) => {
    let email = event.request.usernameParameter;
    let code = event.request.codeParameter;
    // get HTML from S3
    var content = await getFile(bucket, basePath + "/email/VerificationEmail.html");
    content = content.replace("${email}", email);
    event.response = {
        emailSubject: "YourApp - User updated",
        emailMessage: content
    }
    return event
}

const verify_user_attribute = async(event) => {
    let email = event.request.usernameParameter;
    let code = event.request.codeParameter;
    // get HTML from S3
    var content = await getFile(bucket, basePath + "/email/VerificationEmail.html");
    content = content.replace("${email}", email);
    event.response = {
        emailSubject: "YourApp - Verify user attribute",
        emailMessage: content
    }
    return event
}

const authentication_message = async(event) => {
    let email = event.request.usernameParameter;
    let code = event.request.codeParameter;
    // get HTML from S3
    var content = await getFile(bucket, basePath + "/email/VerificationCode.html");
    content = content.replace("${code}", code);
    event.response = {
        emailSubject: "YourApp - MFA Authentication",
        emailMessage: content
    }
    return event
}
Uncategorized

AR on Android using Unity on Ubuntu 22.04

Here is some guidance based on my experience:

PocketGarden app

URL: https://github.com/buck-co/PocketGarden

Install Unity (2021.3.1f1 LTS) with modules:

  • Android Build Support
  • Linux Build Support

AR Foundations app

URL https://github.com/Unity-Technologies/arfoundation-samples

Install Unity (2022.2.18f1 LTS) with modules:

  • Android Build Support
  • Linux Build Support

Accept version change when opening the project.

Tips

  1. clang not found errors: Some versions of Unity don’t include clang properly in the NDK so use your own NDK if you have to, Unity will tell you which version it needs when you try to change the path.
  2. If you get keystore format invalid errors, make the keystore from unity.
  3. If you get clang segmentation faults, try clean & build your app or restarting your PC
  4. If you get libssl version errors, do this:
    wget http://archive.ubuntu.com/ubuntu/pool/main/o/openssl/libssl1.1_1.1.0g-2ubuntu4_amd64.deb
    sudo dpkg -i libssl1.1_1.1.0g-2ubuntu4_amd64.deb
  5. .

Uncategorized

AWS Amplify + Custom domain

  1. Move your DNS records to Route 53
  2. Go to Amplify
  3. Go to the App settings
  4. Go to Domain management
  5. Click Add domain
  6. Select your domain, etc, and then you’ll have add some CNAME records to your DNS zone to prove that you own the domain.
  7. You’ll have to add a CNAME record that points your custom domain to the CloudFront distribution of the app.
  8. Back in Amplify, go to the App settings
  9. Click on Rewrites and redirects
  10. Confirm/update that your custom domain is pointing to the amplify app (when I first set it up, it was pointing to www of my custom domain, weird!)
  11. Voila!
Uncategorized

AWS Amplify Access Denied Error

This error is specific to the problem where the direct URL to the page won’t work. For example, when you go to https://master.somehexnumbers.amplifyapp.com, you click on a page (eg signin page) and the address bar reads https://master.somehexnumbers.amplifyapp.com/signin, which will work. However, if you typed in https://master.somehexnumbers.amplifyapp.com/signin, you’ll see this error.

The fix is simple:

  1. Go to Amplify
  2. Go to the App settings
  3. Go to Rewrites and redirects
  4. Click on the Edit button
  5. Click Add rule and enter this rule:

Source address:

</^[^.]+$|\\.(?!(css|gif|ico|jpg|js|png|txt|svg|woff|ttf)$)([^.]+$)/>

Target address: /index.html

Type: 200 (Rewrite)

And click the Save button

Uncategorized

Gatsby + AWS S3 for Static Site Hosting

When you want to host a Gatsby site (or any static site) on S3 here’s what you need to do.

The high-level steps are:

  1. Get it working on S3 (which will be HTTP only)
  2. Add CloudFront for HTTPS

S3 Setup

Setup:

  1. Create a bucket
  2. Name it (make sure the name matches your domain, eg http://www.blahblah.com)
  3. Enable public access
  4. Enable static website hosting
  5. Upload files

Confirm that it works by browsing to the bucket website endpoint, which is like this http://www.blahblah.com.s3-website-ap-southeast-2.amazonaws.com/

Source 1: https://docs.aws.amazon.com/AmazonS3/latest/userguide/HostingWebsiteOnS3Setup.html

Source 2: https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/getting-started-cloudfront-overview.html

CloudFront Setup

  1. Move your DNS records to Route 53
  2. Generate a certificate for your domain from AWS Certificate Manager (you’ll have add some CNAME records to your DNS zone to prove that you own the domain)
  3. Create the CloudFront distribution
  4. Add DNS records (alias type) pointing your custom domain to the CloudFront distribution

Confirm that it works by browsing to your custom domain with HTTPS.

Source 1: https://aws.amazon.com/premiumsupport/knowledge-center/cloudfront-https-requests-s3/

Source 2: https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/routing-to-cloudfront-distribution.html