How to include JSZip in the browser

The JSZip documentation doesn’t make it entirely clear how to include it in the browser, i.e. which <script> tag you need to use in order to load JSZip.

Here’s the appropriate <script> tag:

<script src="https://unpkg.com/[email protected]/dist/jszip.min.js" type="text/javascript"></script>

You can also use the non-minified version which does not have minified class and object names:

<script src="https://unpkg.com/[email protected]/dist/jszip.js" type="text/javascript"></script>

 

Posted by Uli Köhler in HTML, Javascript

How to read local ZIP in HTML5/Javascript using JSZip

In our previous post How to load local file in Javascript using HTML5 FileReader we showed how to read a local file using the HTML5 FileReader.

Based on this, it’s pretty easy to use JSZip to read a local ZIP file:

var reader = new FileReader();
reader.onload = function(ev) {
    JSZip.loadAsync(ev.target.result).then(function(zip) {
        // TODO Your code goes here. This is just an example.
        console.log(zip)
    }).catch(function(err) {
        console.error("Failed to open", filename, " as ZIP file:", err);
    })
};
reader.onerror = function(err) {
    console.error("Failed to read file", err);
}
reader.readAsArrayBuffer(fileInput.files[0]);

One example of what you can do using the JSZip object is to list the filenames inside the ZIP file:

var filename = fileInput.files[0].name;
var reader = new FileReader();
reader.onload = function(ev) {
    JSZip.loadAsync(ev.target.result).then(function(zip) {
        for(let [filename, file] of Object.entries(zip.files)) {
            console.log(filename);
        }
    }).catch(function(err) {
        console.error("Failed to open", filename, " as ZIP file:", err);
    })
};
reader.onerror = function(err) {
    console.error("Failed to read file", err);
}
reader.readAsArrayBuffer(fileInput.files[0]);

Full example

<html>
<body>
    <input type="file" id="myfile" onchange="onMyfileChange(this)" />

    <script src="https://unpkg.com/[email protected]/dist/jszip.js" type="text/javascript"></script>
    <script type="text/javascript">
        function onMyfileChange(fileInput) {
            if(fileInput.files[0] == undefined) {
                return ;
            }

            var filename = fileInput.files[0].name;
            // var filesize = fileInput.files[0].size;
            var reader = new FileReader();
            reader.onload = function(ev) {
                JSZip.loadAsync(ev.target.result).then(function(zip) {
                    console.log(zip)
                }).catch(function(err) {
                    console.error("Failed to open", filename, " as ZIP file");
                })
            };
            reader.onerror = function(err) {
                console.error("Failed to read file", err);
            }
            reader.readAsArrayBuffer(fileInput.files[0]);
        }
    </script>
</body>
</html>

 

Posted by Uli Köhler in HTML, Javascript

How to load local file in Javascript using HTML5 FileReader

In HTML5, you can not only upload a file to a server but also process it directly in the browser using Javascript.

This post provides minimal examples of how to use FileReader to do that.

How to read a text file

<html>
<body>
    <input type="file" id="myfile" onchange="onMyfileChange(this)" />
    <script type="text/javascript">
        function onMyfileChange(fileInput) {
            if(fileInput.files[0] == undefined) {
                return ;
            }

            // Example of what information you can read
            // var filename = fileInput.files[0].name;
            // var filesize = fileInput.files[0].size;
            var reader = new FileReader();
            reader.onload = function(ev) {
                var content = ev.target.result; // content is a string
                console.log("Successfully read file");
            };
            reader.onerror = function(err) {
                console.error("Failed to read file", err);
            }
            reader.readAsText(fileInput.files[0]);
        }
    </script>
</body>
</html>

How to read a binary file as ArrayBuffer

<html>
<body>
    <input type="file" id="myfile" onchange="onMyfileChange(this)" />
    <script type="text/javascript">
        function onMyfileChange(fileInput) {
            if(fileInput.files[0] == undefined) {
                return ;
            }

            // Example of what information you can read
            // var filename = fileInput.files[0].name;
            // var filesize = fileInput.files[0].size;
            var reader = new FileReader();
            reader.onload = function(ev) {
                var content = ev.target.result; // content is an ArrayBuffer object
                console.log("Successfully read file");
            };
            reader.onerror = function(err) {
                console.error("Failed to read file", err);
            }
            reader.readAsArrayBuffer(fileInput.files[0]);
        }
    </script>
</body>
</html>

 

Posted by Uli Köhler in HTML, Javascript

How I fixed xHCI host controller not responding, assume dead

Problem:

In Linux, my USB 3.0 hub randomly kept resetting and only recovered after a reboot: All USB devices were offline until I manually rebooted the system. This is the dmesg output:

[ 3685.684555] xhci_hcd 0000:04:00.0: Abort failed to stop command ring: -110
[ 3685.716572] xhci_hcd 0000:04:00.0: Host halt failed, -110
[ 3685.716575] xhci_hcd 0000:04:00.0: xHCI host controller not responding, assume dead
[ 3685.716620] xhci_hcd 0000:04:00.0: HC died; cleaning up
[ 3685.716653] xhci_hcd 0000:04:00.0: Timeout while waiting for setup device command
[ 3685.716820] usb 3-2: USB disconnect, device number 3
[ 3685.716942] usb 4-2: USB disconnect, device number 2
[ 3685.716944] usb 4-2.4: USB disconnect, device number 3
[ 3686.268612] usb 3-2.3: device not accepting address 29, error -22
[ 3686.268694] usb 3-2.3: USB disconnect, device number 29
[ 3686.269109] usb 3-2.4: USB disconnect, device number 4
[ 3686.269114] usb 3-2.4.1: USB disconnect, device number 5
[ 3686.345109] usb 3-2.4.2: USB disconnect, device number 9
[ 3686.573230] usb 3-2.4.3: USB disconnect, device number 7
[ 3686.701272] usb 3-2.4.4: USB disconnect, device number 8

Solution:

I discovered the solution (which basically restarts the xHCI USB device) on the ArchLinux forums:

echo -n "0000:04:00.0" > /sys/bus/pci/drivers/xhci_hcd/unbind
echo -n "0000:04:00.0" > /sys/bus/pci/drivers/xhci_hcd/bind

You need to insert your device ID which you can find in the dmesg output (0000:04:00.0 in my case) and run the code as root.

Posted by Uli Köhler in Linux

How to fix error: cannot find the python “fuse” module; please install it

Problem:

When running bup fuse, you see this error message

error: cannot find the python "fuse" module; please install it

Solution:

On Ubuntu or other debian-based systems, just install the package using apt:

sudo apt -y install python3-fuse

Otherwise, install it using pip:

sudo pip3 install fuse-python
Posted by Uli Köhler in Python

How to get or set Trinamic TMC stepper motor current in Marlin firmware

In Marlin, you can dynamically configure the stepper motor current for Trinamic stepper drivers like the TMC2208 or the TMC5160.

Changing the motor current via G-Code

The easiest option is by using G-Codes. In order to set the stepper motor current for X , Y and Z to 2 Amperes (2000 mA), use M906 like this:

M906X2000Y2000Z2000

Now save the settings to the EEPROM using

M500

You can also query the current stepper motor current using

M906
X driver current: 2000
Y driver current: 2000
Z driver current: 2000
E driver current: 800
ok

Changing the motor current in the config file

You can also set default stepper motor current values in the Marlin config files. Note that these will be overridden by any value in the EEPROM.

In Configuration_adv.h, look for

#if HAS_TRINAMIC_CONFIG

which contains axis definitions like

#if AXIS_IS_TMC(X)
  #define X_CURRENT       800        // (mA) RMS current. Multiply by 1.414 for peak current.
  #define X_CURRENT_HOME  X_CURRENT  // (mA) RMS current for sensorless homing
  #define X_MICROSTEPS     32        // 0..256
  #define X_RSENSE          0.11
  #define X_CHAIN_POS      -1        // -1..0: Not chained. 1: MCU MOSI connected. 2: Next in chain, ...
  //#define X_INTERPOLATE  true      // Enable to override 'INTERPOLATE' for the X axis
#endif

Change the value in the line

#define X_CURRENT 800 // (mA) RMS current. Multiply by 1.414 for peak current.

so, for example to set 2A (2000 mA), set it to

#define X_CURRENT 2000 // (mA) RMS current. Multiply by 1.414 for peak current.

 

Posted by Uli Köhler in 3D printing

PySerial minimal request-reply example

This example sends the M119 (print endstop status) command to an attached 3D printer and prints the response in a loop

#!/usr/bin/env python3
import serial
ser = serial.Serial("/dev/ttyACM0")

try:
    while True:
        ser.write(b"M119\n")
        response = ser.read_until(b"ok\n")
        print(response.decode("utf-8"))
finally:
    ser.close()

Example output (in a loop):

Reporting endstop status
x_max: open
y_max: TRIGGERED
z_max: TRIGGERED
ok

 

Posted by Uli Köhler in 3D printing, Embedded, Python

How to set Raspberry Pi 4 USB-C to host mode

By default, the Raspberry Pi 4 USB-C port is not set to Host mode and therefore it’s not possible.

In order to set the USB-C port to host mode, add the following line to the end of /boot/config.txt (in the [all] section):

dtoverlay=dwc2,dr_mode=host

and

reboot

 

Posted by Uli Köhler in Raspberry Pi

How to backup /etc/letsencrypt to local bup repository

The following script backups your Let’s Encrypt folder. I place the script in /etc/letsencrypt/backup.sh

#!/bin/bash
export BUP_DIR=/media/usb1/letsencrypt-myserver.bup
# Init
bup -d $BUP_DIR init

# Save LetsEncrypt directory
bup -d $BUP_DIR index . --exclude csr && bup save -9 --strip-path $(pwd) -n etc-letsencrypt .

# OPTIONAL: Add par2 information
#   This is only recommended for backup on unreliable storage or for extremely critical backups
#   If you already have bitrot protection (like BTRFS with regular scrubbing), this might be overkill.
# Uncomment this line to enable:
# bup fsck -g

# OPTIONAL: Cleanup old backups
bup -d $BUP_DIR prune-older --keep-all-for 1m --keep-dailies-for 6m --keep-monthlies-for forever -9 --unsafe

Typically, you only need to adjust the BUP directory in this line:

export BUP_DIR=/media/usb1/letsencrypt-myserver.bup

In order to automatically backup daily, you can use our script from How to create a systemd backup timer & service in 10 seconds. If you don’t want to read the post, just use this command:

wget -qO- https://techoverflow.net/scripts/create-backup-service.sh | sudo bash /dev/stdin

from the /etc/letsencrypt folder.

Posted by Uli Köhler in Linux

How to view active calls details on FreePBX

Just want to know how many active calls are going on and not interested in the details? See How to view number of active calls on FreePBX

In order to view the details of ongoing calls on FreePBX, go to Admin -> Asterisk CLI

and enter

core show channels verbose

Now click Send command on the right:

This will display, for example

Channel              Context              Extension        Prio State   Application  Data                      CallerID        Duration Accountcode PeerAccount BridgeID
PJSIP/MyTrunk-4924   from-sip-external                        1 Up      AppDial      (Outgoing Line)           015212345678    00:00:28                         4e5accae-8a9c-48bb-b
PJSIP/123-0000000e   macro-dialout-trunk  s                  27 Up      Dial         PJSIP/01521234567@MyTrunk 492468024123    00:00:28                         4e5accae-8a9c-48bb-b
2 active channels
1 active call
8 calls processed

In the example shown, a PJSIP client (phone) registered as extension 123, calls out on a PJSIP trunk line named MyTrunk-492468024123, calling the PSTN number 015212345678.

Posted by Uli Köhler in FreePBX

How to view number of active calls on FreePBX

Also want to see call details like which extension is calling which number, call duration and which trunks are being used? See How to view active calls details on FreePBX instead.

In order to view how many calls are active concurrently on FreePBX, go to Admin -> Asterisk CLI

and enter

core show calls

Now click Send command on the right:

This will display, for example

1 active call
6 calls processed

indicating that one call is currently going on.

If no calls are currently in process, it will display

0 active calls
6 calls processed

 

Posted by Uli Köhler in FreePBX

How to replace string in reverse proxy HTTP request using Lua & nginx

You can use access_by_lua_block in order to replace arbitrary strings in an nginx request. Note: This will replace in the request to the reverse proxy, not in the response from the reverse proxy. See How to replace HTTP response data in nginx using lua for a Lua-based approach on how to replace a string in the response.

access_by_lua_block {
    ngx.req.read_body()
    local body = ngx.req.get_body_data()
    if body then
        body = ngx.re.gsub(body, "string_to_replace", "string_by_which_to_replace")
    end
    ngx.req.set_body_data(body)
}

This is typically used in a location {} block so you can just replace when a specific set of URLs is accessed:

location /config {
   proxy_pass http://127.0.0.1:12345/;
    proxy_set_header X-Forwarded-For $remote_addr;

    access_by_lua_block {
       ngx.req.read_body()
       local body = ngx.req.get_body_data()
       if body then
            body = ngx.re.gsub(body, "myvar", "myothervar")
       end
       ngx.req.set_body_data(body)
    }
}

 

Posted by Uli Köhler in nginx

How to replace HTTP response data in nginx using lua

This is an example of how to use body_filter_by_lua_block to replace parts of the response by a string. Note that since it’s a Lua feature, you’ll be able to use arbitrary code when modifying the body, including network requests, parsing etc. Note: This will replace in the response send to the client, not in the request sent to the the reverse proxy. See How to replace string in reverse proxy HTTP request using Lua & nginx for a Lua-based approach on how to replace a string in the request.

header_filter_by_lua_block { ngx.header.content_length = nil }
body_filter_by_lua_block {
        local body = ngx.arg[1]
        if body then
                body = ngx.re.gsub(body, "string_to_replace", "string_by_which_to_replace")
        end
        ngx.arg[1] = body
}

This is typically used in a location {} block to only replace strings for specific sets of URLs:

location /config {
   proxy_pass http://127.0.0.1:12345/;
    proxy_set_header X-Forwarded-For $remote_addr;
    proxy_set_header Host meet.techoverflow.net;

    header_filter_by_lua_block { ngx.header.content_length = nil }
    body_filter_by_lua_block {
            local body = ngx.arg[1]
            if body then
                    body = ngx.re.gsub(body, "myvar", "myothervar")
            end
            ngx.arg[1] = body
    }
}

 

Posted by Uli Köhler in nginx

How to fix Python ModuleNotFoundError: No module named ‘usb’ / usb.util

Problem:

When running a Python script, you see an error message like

Traceback (most recent call last):
  File "./dfuse-tool.py", line 2, in <module>
    import dfuse
  File "/home/uli/dev/tools/dfuse-tool/dfuse/__init__.py", line 1, in <module>
    from dfuse.DfuDevice import DfuDevice
  File "/home/uli/dev/tools/dfuse-tool/dfuse/DfuDevice.py", line 1, in <module>
    import usb.util
ModuleNotFoundError: No module named 'usb'

Solution:

You need to install PyUSB using

sudo pip3 install pyusb
Posted by Uli Köhler in Electronics, Python

How to view endstop status on Marlin using G-Code?

On 3D printer mainboards running the Marlin firmware, you can use M119 to view the current state of the endstops. Example output:

M119
Reporting endstop status
x_max: TRIGGERED
y_max: TRIGGERED
z_min: TRIGGERED
ok

 

Posted by Uli Köhler in 3D printing, Electronics

How to print Marlin firmware version using G-Code

The Marlin 3d printer firmware allows you to print the firmware version (along with different firmware settings) using the M115 command. The M115 command takes no parameters.

Example output:

M115
FIRMWARE_NAME:Marlin bugfix-2.0.x (May 13 2021 14:16:08) SOURCE_CODE_URL:github.com/MarlinFirmware/Marlin PROTOCOL_VERSION:1.0 MACHINE_TYPE:OCTOPUS_V1_0 EXTRUDER_COUNT:4 UUID:cede2a2f-41a2-4748-9b12-c55c62f367ff
Cap:SERIAL_XON_XOFF:0
Cap:BINARY_FILE_TRANSFER:0
Cap:EEPROM:1
Cap:VOLUMETRIC:1
Cap:AUTOREPORT_TEMP:1
Cap:PROGRESS:0
Cap:PRINT_JOB:1
Cap:AUTOLEVEL:0
Cap:RUNOUT:0
Cap:Z_PROBE:0
Cap:LEVELING_DATA:0
Cap:BUILD_PERCENT:0
Cap:SOFTWARE_POWER:0
Cap:TOGGLE_LIGHTS:0
Cap:CASE_LIGHT_BRIGHTNESS:0
Cap:EMERGENCY_PARSER:1
Cap:PROMPT_SUPPORT:0
Cap:SDCARD:1
Cap:REPEAT:0
Cap:SD_WRITE:1
Cap:AUTOREPORT_SD_STATUS:0
Cap:LONG_FILENAME:1
Cap:THERMAL_PROTECTION:1
Cap:MOTION_MODES:0
Cap:ARCS:1
Cap:BABYSTEPPING:0
Cap:CHAMBER_TEMPERATURE:0
Cap:COOLER_TEMPERATURE:0
Cap:MEATPACK:0
ok

 

Posted by Uli Köhler in 3D printing, Electronics

What is the difference between BIGTREE_OCTOPUS_V1 and BIGTREE_OCTOPUS_V1_USB

When building Marlin firmware for the BigTreeTech Octopus from the official BigTreeTech GitHub repository Marlin directory, you can see two different targets in PlatformIO:

  • BIGTREE_OCTOPUS_V1
  • BIGTREE_OCTOPUS_V1_USB

It is not immediately made clear what the difference between those is, but a short description can be found in ini/stm32f4.ini:

BIGTREE_OCTOPUS_V1_USB has support for using USB flashdrives directly on the board and serial-over-USB while BIGTREE_OCTOPUS_V1 has not.

In most cases, you want to build BIGTREE_OCTOPUS_V1_USB if printing via USB (e.g. via Octoprint) because the BIGTREE_OCTOPUS_V1 configuration does not allow printing via USB.
The compiler definitions for BIGTREE_OCTOPUS_V1 in ini/stm32f4.ini are:
build_flags        = ${stm32_variant.build_flags}
                     -DSTM32F446_5VX -DUSE_USB_HS_IN_FS

whereas BIGTREE_OCTOPUS_V1_USB enabled more USB-related features:

build_flags       = ${stm_flash_drive.build_flags}
                    -DSTM32F446_5VX -DUSE_USB_HS_IN_FS
                    -DUSE_USBHOST_HS -DUSBD_IRQ_PRIO=5
                    -DUSBD_IRQ_SUBPRIO=6
                    -DUSBD_USE_CDC_MSC
Posted by Uli Köhler in 3D printing, Electronics, PlatformIO, STM32

How I fixed STM32CubeProgrammer CUBEPROGRAMMER_ERROR_NOT_SUPPORTED

I tried to flash the DFU bootloader on the BigTreeTech Octopus V1 3D printer mainboard. However, STM32CubeProgrammer v2.8.0 showed me the following error message when trying to connect:

CUBEPROGRAMMER_ERROR_NOT_SUPPORTED

I could only fix this by completely uninstalling STM32CubeProgrammer and then installing STM32CubeProgrammer v2.7.0 from the BigTreeTech Github Repo. Most likely downloading v2.7.0 from the ST homepage will also work but I didn’t verify this.

Posted by Uli Köhler in 3D printing, Electronics, STM32

How to create conan debug profile

Run this command to create a debug profile from your default profile:

cp ~/.conan/profiles/default ~/.conan/profiles/debug && sed -i -e 's/Release/Debug/g' ~/.conan/profiles/debug

Example output from conan profile show debug:

[settings]
os=Linux
os_build=Linux
arch=x86_64
arch_build=x86_64
compiler=gcc
compiler.version=9
compiler.libcxx=libstdc++
build_type=Debug
[options]
[conf]
[build_requires]
[env]

 

Posted by Uli Köhler in C/C++, Conan

How to get time since epoch in milliseconds in C++

Use this snippet using chrono:

#include <chrono>

uint64_t timeSinceEpochMilliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(
    std::chrono::system_clock::now().time_since_epoch()
).count();

 

Posted by Uli Köhler in C/C++
This website uses cookies to improve your experience. We'll assume you're ok with this, but you can opt-out if you wish. Cookie settingsACCEPTPrivacy &amp; Cookies Policy