[SOLVED] Mount USB drive in Hassio to be used on the Media Folder with udev customization

Hi everyone,

I was browsing the forum to find a solution to the often asked feature of using external USB drives in Hassio for media (or even other) features.

On the forum I’ve found the following approaches:

Today I’ve found a new way that I don’t seem to see already documented on the forum to solve this issue.
The author of this solution is someone called eklex that has left this gist on Github:

The idea is very interesting and is the following:
using Linux udev subsystem, change the default rule for automount of USB drivers so that the drives will be mounted under /mnt/data/supervisor/media/ which is visible in the containers that Hassio handles.

I’ve just tried and it works perfectly.

I’ve even combined this with the original Samba Share addon, and it works just fine since that extension exposes also the media folder and my USB key is now mounted there.

To give even more credit to the author of the udev rules, he/she did a great job filtering out eventual USB keys with labeled CONFIG, to avoid messing with devices that are used only to import configuration in Hassio.
He/she does a great job at documenting the intention of the rule and the meaning of all the sections of it.

The documentation on Hassio side, on how to import udev rules is here: https://github.com/home-assistant/operating-system/blob/59b687f0dbb5c963c4a1b16bc574437a1aff99b3/Documentation/configuration.md

Just a personal reminder, since I’ve stumbled on this: you probably also need to remember to include the correct authorized_keys file with your public key!
I had ssh already enabled, but when I’ve imported the udev rules I had only those on the USB key with a CONFIG partition, and lacking to re-include an authorized_keys costed me access to ssh; it seems that the lack of the file overwrites authorized_keys remove a possible already configured file.

This approach works just fine for me, but I would expect it could even leave room for more advanced ones, that could employ a more granular logic in separating devices, subfolders and mount points.

28 Likes

This is great, exactly what I was looking for. But either I’m tired or very slow right now.

So what do I need to do with my thumb-drive (or other disk I assume) and the rules?

I don’t have a test environment running right now and I don’t feel like messing up my installation just before xmas with some real trial and error.

Is it too much to ask for a simple step by step? Doesn’t have to be detailed, but to describe the steps in a high level.

My guess would be something like this:

  1. Create at least 2 partitions on my removable drive, one CONFIG and one other with some other name.

  2. Create a folder in the config partition (/etc/udev/rules.d)

  3. Place 80-mount-usb-to-media-by-label.rules in the folder above

  4. Put drive in to the hass.io machine and execute ‘systemctl restart hassos-config’

As said, I don’t want to mess something up, so I’m asking before doing here.

Personal opinion time.
Home Assistant is not a media server, and should not attempt to become one, and I hope the devs don’t put much effort into this portion of HA.

That’s all. I’m super confused why the media browser exists in HA.

1 Like

The media browser is a good idea would be a good idea if you could link folders on another device. ie: link to media saved on a NAS. Having to save all your media on the HA server is stupid. Being able to then stream that media to other devices in your home (ie: Google Homes) would be awesome. Sure it’s currently possible to stream media from a NAS to a Google Home using other apps, but this should be part of the HA media system so it’s all in the one place and we can automate it etc.

4 Likes

hi.

It’s actually simpler than you have described (and there might be other ways but I’ve never managed to have HASSIO use the alternative method to load config, the one with the CONFIG folder).

  1. pick the USB key
    You need a USB key just for the initial configuration. Once done this is no longer required, so you could use the same medium you will use later to store your media, or even a ancient old USB key with 32MB since you need this just for a text file.

  2. prepare the USB key
    As per the documented Hassio way to pre-load config, format the USB key (I did it in ext4) and give it CONFIG as label (this is important). Then create a folder on that partition called udev and in that create a file called 80-mount-usb-to-media-by-label.rules with the content of the linked gist. You don’t have to modify it UNLESS you have an advanced setup that boots from USB. In that case you have to modify the rule (as per in line comments) to exclude that USB drive you are already using from the rule (see lines #24 and #50)
    Optionally, if you want to get ssh access to the host and manually verify that the udev rule will land in the right place, also add the authorized_keys file in the root of the USB key, containing your ssh public key, but this is not strictly required.

  3. load the config
    Plug the USB key on an already running Hassio, the in the web UI go in Supervisor -> System, and there in the box Host System, click on the kebab menu and there click on “Import from USB”. You are done, the files should have been imported and gone to the right place. If you enabled ssh you can find them copied under /etc/udev/rules.d/
    You can now unplug the USB key

  4. prepare the media
    You can now repurpose the USB key used before or just plug a new one on your device and you will have it mounted in the right place, and you should be able to see it listed under the media browser ui.
    If you want to use the original key that you have used for the config part, you have to reformat it and CHANGE ITS LABEL since the udev rule explicitly ignore to kick in for devices that are labeled as CONFIG

  5. plug in the USB device (and restart HA)
    When you plug in the drive it’s mounted correctly and if you browse in the Media Browser you will see an entry corresponding to the drive (it will show the partition label) but if you click on it you will see no content.
    To see the content it’s just a matter of restarting HA. (there might be a better way to force the re-scan but I’m not aware of it. Restarting HA just works.)

Notes:

  • I have no clue how to undo the operation. I don’t know how you can remove the udev file. I will try eventually since I don’t see risks with the operation. It might be that an empty udev folder could remove the files deployed, or in the worst-case scenario, a blank rule with the same name might possibly overwrite the deployed file.
  • My 32GB USB key formatted in ext4 works well, I can load media files. But if I try to plug a 320GB HDD, although the drive is mounted correctly in the right place (and I can also see it listed under the media browser) I cannot see any content in it. I suspect it might be related to the size of the disk, but I still need to think about it. This was a HA issue. The drive is mounted correctly in the right place, but I think that HA performs some checks at HA start-up time. It’s just a matter of restarting HA and it will display correctly the content of the drive.

Let me know if you decide to do this, I’d be curious to get confirmation that this works correctly and that the steps are clear enough.

12 Likes

I’d like not to hijack this thread that was focused on a specific to load local storage BUT it might be that the eklex udev approach could be used as a multi-purpose hack to force HASSIO to run persistent commands at our will.
We could for example do this:

  • upon the unplug of a USB key with the label MOUNT_REMOTE mount whatever remote folder you want under /mnt/data/supervisor/media/ (as long as the underlying system has support fo that filesystem)

Hoping to see other people hack around starting from similar ideas.

Hi Paoloantinoti
Thanks! I have like zero experience and trying to mount 1 TB, so I took your advice and trying to use a I gb USB drive. I did formatted with FAT32 I don’t have ext4 option available though have ext/FAT I think. Anyways, So I labeled it CONFIG, added a folder udev and added a txt file with suggested name added code lines 37, 39, 41, 43 and 44, and removed the “.txt” so that it ends with “.rules”. Inserted to USB 3.0 port on pie4 and then on chrome browser that runs on a separate window computer on local HA IP>Supervisor>systems> upload from USB.
but I didn’t see any folders created either in UI media folder nor on file explorer where we see folders like addons, config, share, media etc.
Would you mind directing if I missed any steps or totally of the base.
Thank you in advance

Hi there.

I’m not sure what you mean with the reference to lines 37, 39, 41 and 43-44.

You were supposed to copy-paste the whole file, most likely without modifying it unless you knew you had to.
Those lines are just references listed there that have been used by the author to debug the creation of the rule. You don’t need to use any of them (maybe with the exception of the last 2 to simulate the events and verify your rule behaves correctly, but a real physical test is probably simple enough in this case so there is no strict need for those commands).

Your steps seem correct according to what you describe.
The best way to verify you have done it properly would be to enable root ssh on port 22222 and verify that upon theimport operation the rule is copied over under /etc/udev/rules.d/

But just to be sure, since you haven’t mentioned it:
after the import operation is completed, you are supposed to remove your drive labelled CONFIG (is no longer needed) and plug in your real drive with the media content on it.
If you performed the steps correctly it will be mounted under /media.
What you will see at this point is that if you go under the Media Browser tab, and you will click “Local Media” you will see an entry with the name of the label of the portion of your media drive. If you will click there it will appear empty, but at that point is enough to restart your HA instance and when the process will be back you will be able to see the data in it.

Screenshot from 2020-12-31 11-20-33

I’d suggest you to retry and also perform a second verification just to avoid any issue with Linu, fat32 and partition sizes:

after you are done with the 1GB drive, remove it, reformat it (giving it a label different than CONFIG) put a picture or an mp3 on it and try to perform your test with this drive.

2 Likes

Can i use the same method if i want to mount an internal drive?

Yes, udev can be used to modify most of Linux interaction with hardware devices.
In this case, specifically, you will end up modifying lines 50 and 53.

[Solved]

Thank you @ Paoloantinori!
Any body trying, please use @paoloantinori’s directs mentioned above and *.rules has to copy all content #

udev rule

… all they way to

Exit

LABEL=“abort_rule”
Thank you!

Happy New Year everyone!
Thanks @paoloantinori for advice earlier
I got to bit of issue here I could see the drive in my media folder but having issue with Motion eye. Within my hard drive, I created a sub-folder which is not detected by Motioneye. When I gave path of main drive folder, it detected as I could see Disk usage numbers and motion created some auto generated folders. However, when I go to drive via File explorer, it is not showing me those folder created by Motioneye.
Also I can see my streaming but no video is saved, however, if I change the path to by default custom path that /share/camera, motioneye store video files captured in share/camera folder which is on pie and thus seems everything works fine. I can also view it via file explorer. Not sure if someone else have encountered same issue or I missed something? Seems like there is disconnect between HA or Motioneye with mounted drive.
Any help would be appreciated!
Thanks

Thanks for sharing this udev rule @paoloantinori (and to eklex for creating it)!

I started having a go with Home Assistant OS on a RPi4 in December and thought it would be great to be able to plug in a USB drive and share it to other devices on my LAN as well as zone-control the heating.

This udev rule worked great after plugging in a drive and restarting each add-on which needed access to the drive (Home Assistant to show it in the Media Browser, and Samba Share to share it via Samba).

When I tried it with my NTFS-formatted backup USB drive though, I found I could read, but not write; the old NTFS kernel driver is read-only. I found that to get write access to my NTFS partition, the ntfs-3g fuse driver is needed.

Adding ntfs-3g support the slow way (build the OS yourself):

  1. git clone the https://github.com/home-assistant/operating-system repository
  2. If you want to build a particular version of the OS, use git to checkout that version
  3. Edit the buildroot-external/configs/rpi4_defconfig file (or the one appropriate for your hardware), adding the following lines at the end:
BR2_PACKAGE_NTFS_3G=y
BR2_PACKAGE_NTFS_3G_NTFSPROGS=y
  1. Follow the developer instructions to perform a build of the OS, unzip the built image (.img) file, and write it to your uSD card (or other boot device…remember all old content will be lost when you do this, so back sure you back-up everything you want to keep). Note that for me this took 16GB of disk space and many hours to build.
  2. Restore all your Home Assistant stuff back onto your fresh HassOS.

However, the udev rule will still mount the NTFS partition using the old kernel NTFS module by default. It needs a little enhancement to make it use ntfs-3g!

Here’s what I came up with:

#
# udev rule
#   Mount USB drive to the media directory using the partition name as mount point
#
# Source:
#   https://gist.github.com/eklex/c5fac345de5be9d9bc420510617c86b5
#
# Description:
#   Created for Home Assistant OS, this rule mounts any USB drives
#   into the Hassio media directory (/mnt/data/supervisor/media).
#   When a USB drive is connected to the board, the rule creates one directory
#   per partition under the media directory. The newly created partition is named
#   as the partition name. If the partition does not have a name, then the following
#   name format is used: "usb-{block-name}" where the block name is sd[a-z][0-9].
#
# Note 1:
#   The rule name is always prefixed with a number. In this case, the rule uses 80.
#   This represents the order of the rule when multiple rules exists in udev.
#   Low numbers run first, high numbers run last. However, low numbers do not have all
#   the facilities than high numbers may have.
#   For this rule to run properly, use numbers equal or greater than 80.
#
# Note 2:
#   This rule will skip mounting the 'CONFIG' USB key.
#   https://github.com/home-assistant/operating-system/blob/038f1b4bd69c952769fd020db0eae0f511570d19/Documentation/configuration.md
#
# Note 3:
#   This rule will mount the OS partitions if the OS is sorted on a USB drive (i.e. USB booting).
#   To prevent this issue from happening, update the rule to skip the booting USB drive.
#   See the CAUTION message below.
#
# Source of inspiration:
#   https://www.axllent.org/docs/auto-mounting-usb-storage/
#
# Useful links:
#   https://wiki.archlinux.org/index.php/Udev
#
# udev commands:
#   - Restart udev to reload new rules:
#       udevadm control --reload-rules
#   - List device attributes of sdb1:
#       udevadm info --attribute-walk --name=/dev/sdb1
#   - List environment variables of sdb1:
#       udevadm info /dev/sdb1
#   - Trigger add/remove event for sdb1:
#       udevadm trigger --verbose --action=add --sysname-match=sdb1
#       udevadm trigger --verbose --action=remove --sysname-match=sdb1
#


# Filter on block devices, exit otherwise
# CAUTION: Change to 'sd[b-z][0-9]' if booting from a USB drive (e.g.: sda)
KERNEL!="sd[a-z][0-9]", GOTO="abort_rule"

# Skip none USB devices (e.g.: internal SATA drive)
ENV{ID_PATH}!="*-usb-*", GOTO="abort_rule"

# Import the partition info into the environment variables
IMPORT{program}="/usr/sbin/blkid -o udev -p %N"

# Exit if partition is not a filesystem
ENV{ID_FS_USAGE}!="filesystem", GOTO="abort_rule"

# Exit if this is the 'CONFIG' USB key
ENV{ID_FS_LABEL}=="CONFIG", GOTO="abort_rule"

# Get the partition name if present, otherwise create one
ENV{ID_FS_LABEL}!="", ENV{dir_name}="%E{ID_FS_LABEL}"
ENV{ID_FS_LABEL}=="", ENV{dir_name}="usb-%k"

# Determine the mount point
ENV{mount_point}="/mnt/data/supervisor/media/%E{dir_name}"

# Special processing for adding NTFS partitions; mount with ntfs-3g (either directly supported by the OS,
# or using the executable from the /etc/modprobe.d directory if present there).
ACTION!="add", GOTO="normal_mount"
ENV{ID_FS_TYPE}!="ntfs", GOTO="normal_mount"
TEST=="/bin/ntfs-3g", ENV{fs_type_arg}="-t ntfs-3g", GOTO="normal_mount"

# No ntfs-3g in the root file-system; check if it's been dropped into /etc/modprobe.d (along with it's library hopefully!)
TEST=="/etc/modprobe.d/ntfs-3g", RUN{program}+="/usr/bin/mkdir -p %E{mount_point}", RUN{program}+="/usr/bin/systemd-run -r -E LD_LIBRARY_PATH=/etc/modprobe.d /etc/modprobe.d/ntfs-3g $devnode %E{mount_point}", GOTO="end_rule"

LABEL="normal_mount"

# Mount the device on 'add' action (a.k.a. plug the USB drive)
ACTION=="add", RUN{program}+="/usr/bin/mkdir -p %E{mount_point}", RUN{program}+="/usr/bin/systemd-mount %E{fs_type_arg} --no-block --automount=no --collect $devnode %E{mount_point}"

# Umount the device on 'remove' action (a.k.a unplug or eject the USB drive)
ACTION=="remove", ENV{dir_name}!="", RUN{program}+="/usr/bin/systemd-umount %E{mount_point}", RUN{program}+="/usr/bin/rmdir %E{mount_point}"

# Exit
LABEL="end_rule"
LABEL="abort_rule"

Now, you may notice that in the above that it first checks whether ntfs-3g is in the default location it would go when built-in as part of the OS, but then goes on to check whether it’s in the /etc/modprobe.d directory…

The idea here is that rather than everyone having to rebuild the OS themselves, we can stick with official releases and updates, and just use our CONFIG USB sticks to drop ntfs-3g and the other NTFS programs and libraries into the /etc/modprobe.d directory at the same time as adding the udev rule during an ‘Import from USB’.

As the developer documentation describes, you create a modprobe (note, no ‘.d’ on the end) directory on your CONFIG USB stick and put the files in it you want to end up in the /etc/modprobe.d directory on your HassOS host.

Here’s a zip with the udev rule and modprobe directory (ntfs-3g built for Raspberry Pi 4) ready to drop onto your CONFIG USB stick:
https://www.dropbox.com/s/aflbixda23sfned/hassos-rpi4-udev-with-ntfs-3g.zip?dl=1

Note: I have seen that people don’t recommend sharing NTFS partitions mounted using ntfs-3g via Samba as access is very slow compared with using Linux-native partitions like ext4. For me it’s been enough to perform a backup, although it may have taken over twice the time compared with my backup drive being directly plugged in my PC’s USB port.

2 Likes

SOLVED: **** Got to the problem: It is a Windows Explorer issue. I use teracopy now. Works like a charm! :slight_smile:

Great post! What I was looking for.
I’ve tried this in combination with the Samba add-on( to get access to the folder).
After having issues with NTFS, I formatted a 4TB disk as ext4 plugged it into my Pi4. It mounts correctly into the path and is visible under media folder in Hassio
I can copy files to it via Samba share (from Win10) but get BUT get a message: 'There is not enough space on media. You need an additional…

Any idea why this is happening?

I’ve attached a screenshot

1 Like

I’m not able to get this to work for some reason. I follow all the steps and once I run “Import from USB” the udev folder never gets created under /etc.
USB stick is formatted as exFAT (on Win10 PC) with CONFIG as name.

I created the file using the RAW content to make sure I did not get anything extra. The first lines are:

udev rule

and last lines are:

Exit

LABEL=“abort_rule”

Tried on all 4 of my USB ports (Rpi 4).

Any idea what could be wrong?

Thanks.

Just to confirm:

you are looking for /etc/udev on the host right, not on HA container?

I mean when you connect with ssh -p22222 ...

Thanks for your reply! I suspect you are right as when I ssh in I see the Home Assistant banner in my session window. I have HA Supervised installed on a Rpi 4. I think I’ve always just connected to the HA container. I’m going to have to figure out how to connect to the host and take a look.

More to come once I have some time to look at it.

How change media folder mount /opt/docker/hassio/media to another folder.
Thanks!

Here is what I see under Supervisor>System. Wouldn’t that be my host IP? If so, that is the one I’m ssh’ing into.

I had issues getting this to work with NTFS but ext4 worked flawlessly.
Any chance I can get this to work with a sensor to show me the disk space info?

Edit: Turns out just pointing the system monitor (https://www.home-assistant.io/integrations/systemmonitor/) to the created directoy yields the correct data already!

1 Like