nut icon indicating copy to clipboard operation
nut copied to clipboard

Proper solution for UPSes without unique serials

Open melyux opened this issue 3 years ago • 4 comments

I've been struggling to get NUT working with two CyberPower UPSes that have no serials. As such, the ups.conf has no way to tell them apart now that usbhid-ups ignores the port = setting. I only discovered this silent ignoring of my nice differentiated symlinks when I did a lsof and found both driver instances accessing (and failing) the same UPS.

The usual solution to USB devices that are not uniquely distinguishable is to use udev rules to distinguish them in some way using their physical ports and setting a symlink to a specific port (e.g. /dev/ups_1, /dev/ups_2, etc.), which is the solution many use to great success in other cases. However, NUT seems to almost go out of its way to prevent this since the port setting is ignored. As such, I can only connect to one UPS per machine. If I try more, the two running drivers end up trying to connect to the same UPS and nothing works.

The master branch now allows setting the device = setting, but this isn't good enough since device number changes after reboots. A good solution would be if NUT can use something that's settable by udev, like the device name or the device symlink (aka "port"), since udev has the power to distinguish devices permanently. There have been many, many people over the years who have had this problem. Is there any way out of this?

melyux avatar Jan 29 '22 19:01 melyux

I too have run head on into this wall... I am trying to monitor 2 Tripplite Smart3000RM2U UPSs, but what I have found is that the driver, tripplite_usb in my case, bails out the second instance with the message "Duplicate driver instance detected! Terminating other driver!"

If there is not already a plan to address this somehow, I would offer to step up and look into it.

ntwerdochlib avatar Apr 08 '22 22:04 ntwerdochlib

However, NUT seems to almost go out of its way to prevent this since the port setting is ignored.

NUT was written before libusb1, so there was no way to open a device in libusb0.1 by its port name.

A better solution would be for UPS vendors to provide unique serial numbers accessible over USB.

clepple avatar Aug 12 '22 11:08 clepple

Software can't help and wish for hardware to do things. Sounds like the best solution is to update to libusb1.

melyux avatar Aug 12 '22 18:08 melyux

Note that port names are not guaranteed persistent (at least not on all OSes) and can change as you reboot, plug things, etc.

The libusb1 support was added over time and merged last year, but I don't think the notion of ignoring usb drivers' port parameter went away - PRs welcome!

As a twist on the situation, consider that you bought a defective product - their protocol provides for a serial number but does not provide one uniquely per device. It is important for your use case. Do nag them, do post requests to fix the firmware!

On Fri, Aug 12, 2022, 20:54 melyux @.***> wrote:

Software can't help and wish for hardware to do things. Sounds like the best solution is to update to libusb1.

— Reply to this email directly, view it on GitHub https://github.com/networkupstools/nut/issues/1273#issuecomment-1213423060, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAMPTFA3D5FL4K3G6JIRIU3VY2MYFANCNFSM5NDHQH5Q . You are receiving this because you are subscribed to this thread.Message ID: @.***>

jimklimov avatar Aug 12 '22 19:08 jimklimov

Screenshot 2023-04-23 234831 I am experiencing this same issue setting up a 3d Printer farm where I use 1 UPS per printer.

I did some skulking around and I discovered this from lsusb -t

If support was added to nut to specify the Bus, Port, Port, Port until you get to the port the device is on, that would eliminate the need for the serial #. 2 of my cyberpower ups units are on Bus 4, Port, Port 1, Ports 3,1. which is a 4 port hub with only 2 connected and since I am not moving them around, their ports do not change. even after reboot.

skl111 avatar Apr 24 '23 03:04 skl111

I am running a local modification that addresses this issue by allowing the code to skip devices that are already detected. I am running 2 Tripplite UPSs that do not have have serial numbers available in the USB query. I would have to check to see if I pushed these changes to a branch on github

ntwerdochlib avatar Apr 24 '23 14:04 ntwerdochlib

@ntwerdochlib : Cheers, I believe similar work was done in master branch, see PR #1770

jimklimov avatar Apr 24 '23 15:04 jimklimov

@skl111 : I can't vouch for how precisely would libusb allow to specify the paths. I think it has a way to identify a "bus" and a "device" on that bus (or "port" in some documentation, with minute differences not seen in parctice on several platforms where discussion went that deep).

Either way, it does not specify a tree but two values which I believe to logically map to an USB hub (as bus) and either its physical port (should be stable) or some logical identifier it assigned to an attached device (which potentially can change due to re-plugs of stuff). Or so I thought. In the tree view above, all device numbers happen to be unique (some devices have more than one interface), but the Bus is only reported for a root hub - which has a branch of further hubs each with its port numbers starting from 1. So the bus+device ID matching as implemented in NUT now(*) should suffice.

(*) Note: there were fixes to "device" matching on the master branch this year, no official release since then yet => see #1763 and related PRs for details. On most OSes you would need a custom NUT build for now, https://github.com/networkupstools/nut/wiki/Building-NUT-for-in%E2%80%90place-upgrades-or-non%E2%80%90disruptive-tests can help with that.

jimklimov avatar Apr 24 '23 15:04 jimklimov

@jimklimov thanks for the reply, lsusb uses libusb so that pr probably is accurate. I will have to take some time to compile a build for rocky 8 and debian 9 to see how well it works until and official release.

skl111 avatar Apr 28 '23 02:04 skl111

FYI: I'll be mostly offline till mid-May. Good luck on your quest!

jimklimov avatar Apr 28 '23 18:04 jimklimov

I finally got around to getting this working on debian 11 and maybe I am missing something, but this does not solve the issue as it references the device # and if that device gets removed manually or by the device itself before nut can grab it, then that # increments and its no longer valid for the config. The device being CyberPower USB connected UPS's in particular.

CyberPower Device shows connected

/:  Bus 03.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/1p, 480M
    ID 1d6b:0002 Linux Foundation 2.0 root hub
    |__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/3p, 480M
        ID 05e3:0610 Genesys Logic, Inc. Hub
        |__ Port 1: Dev 3, If 0, Class=Hub, Driver=hub/4p, 480M
            ID 214b:7250 Huasheng Electronics
        |__ Port 2: Dev 4, If 0, Class=Hub, Driver=hub/4p, 480M
            ID 214b:7250 Huasheng Electronics
            |__ Port 1: Dev 6, If 0, Class=Human Interface Device, Driver=usbfs, 1.5M
                ID 0764:0501 Cyber Power System, Inc. CP1500 AVR UPS
            |__ Port 2: Dev 63, If 0, Class=Human Interface Device, Driver=usbhid, 1.5M
                ID 0764:0501 Cyber Power System, Inc. CP1500 AVR UPS
        |__ Port 3: Dev 5, If 0, Class=Hub, Driver=hub/4p, 480M
            ID 214b:7250 Huasheng Electronics

after the 2nd ups disconnected and reconnected.

/:  Bus 03.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/1p, 480M
    ID 1d6b:0002 Linux Foundation 2.0 root hub
    |__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/3p, 480M
        ID 05e3:0610 Genesys Logic, Inc. Hub
        |__ Port 1: Dev 3, If 0, Class=Hub, Driver=hub/4p, 480M
            ID 214b:7250 Huasheng Electronics
        |__ Port 2: Dev 4, If 0, Class=Hub, Driver=hub/4p, 480M
            ID 214b:7250 Huasheng Electronics
            |__ Port 1: Dev 6, If 0, Class=Human Interface Device, Driver=usbfs, 1.5M
                ID 0764:0501 Cyber Power System, Inc. CP1500 AVR UPS
            |__ Port 2: Dev 66, If 0, Class=Human Interface Device, Driver=usbhid, 1.5M
                ID 0764:0501 Cyber Power System, Inc. CP1500 AVR UPS
        |__ Port 3: Dev 5, If 0, Class=Hub, Driver=hub/4p, 480M
            ID 214b:7250 Huasheng Electronics

I saw this option allow_duplicates but based on the manual it looks like it will ignore all 7 regex options, and it works for 2 Cyberpower UPS'es when I have it added to the 2nd UPS and that stopped it from disconnecting like it did above before I added it. If I add another CyberPower UPS, then it could get them both mixed up?

skl111 avatar Sep 12 '23 04:09 skl111

And update to this based on testing. allow_duplicates looks like it obeys the bus & dev rule, as I had the dev's at ports 6 & 7 and then when I rebooted a few times the timing was off by enough difference that nut didn't catch them when they were at 6 & 7 and they kept disconnecting and reconnecting at higher numbers.

I updated the udev rule for that series via a post in a gentoo forum about this issue to include

RUN+="/sbin/upsdrvctl stop ; /sbin/upsdrvctl start"

so it looks like

ATTR{idVendor}=="0764", ATTR{idProduct}=="0501", MODE="664", GROUP="nut", RUN+="/sbin/upsdrvctl stop ; /sbin/upsdrvctl start"

After a few reboots so far they are staying at dev 6 & 7.

I think having nut-scanner scan the ports and when it finds CyberPower UPS's, to add the usb hub port # instead of the dev # so it starts trying to attach to the UPS on that port, would bypass the need for a udev rule change.

And of course include a warning about these finicky CyberPower UPSs'

:; lsusb -tv output
/:  Bus 03.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/1p, 480M
    ID 1d6b:0002 Linux Foundation 2.0 root hub
    |__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/3p, 480M
        ID 05e3:0610 Genesys Logic, Inc. Hub
        |__ Port 1: Dev 3, If 0, Class=Hub, Driver=hub/4p, 480M
            ID 214b:7250 Huasheng Electronics
        |__ Port 2: Dev 4, If 0, Class=Hub, Driver=hub/4p, 480M
            ID 214b:7250 Huasheng Electronics
            |__ Port 1: Dev 6, If 0, Class=Human Interface Device, Driver=usbfs, 1.5M
                ID 0764:0501 Cyber Power System, Inc. CP1500 AVR UPS
            |__ Port 2: Dev 7, If 0, Class=Human Interface Device, Driver=usbfs, 1.5M
                ID 0764:0501 Cyber Power System, Inc. CP1500 AVR UPS
        |__ Port 3: Dev 5, If 0, Class=Hub, Driver=hub/4p, 480M
            ID 214b:7250 Huasheng Electronics

UPS.conf

[Ender3Pro1UPS]
        driver = "usbhid-ups"
        port = "auto"
        desc = "Ender 3 Pro 1 UPS"
        pollonly = "enabled"
        vendorid = "0764"
        productid = "0501"
        product = "ST Series"
        vendor = "CPS"
        bus = "003"
        device = "006"
        ###NOTMATCHED-YET###bcdDevice = "0001"
        allow_duplicates

[Ender3Pro2UPS]
        driver = "usbhid-ups"
        port = "auto"
        desc = "Ender 3 Pro 2 UPS"
        vendorid = "0764"
        productid = "0501"
        product = "ST Series"
        vendor = "CPS"
        bus = "003"
        device = "07"
        ###NOTMATCHED-YET###bcdDevice = "0001"
        allow_duplicates

skl111 avatar Sep 18 '23 07:09 skl111

Hi, just recently a PR #2054 has landed to add busport settings (also to nut-scanner discoveries) - I wonder if on your system the two UPSes would show that same bus and port (as HW topology), with possibly differing logical device numbers?

jimklimov avatar Sep 18 '23 07:09 jimklimov

Hi, just recently a PR has landed to add busport settings (also to nut-scanner discoveries) - I wonder if on your system the two UPSes would show that same bus and port (as HW topology), with possibly differing logical device numbers?

Thats exactly what it does, it increments the dev numbers if it doesn't get attached to, physically the same ports.

skl111 avatar Sep 18 '23 07:09 skl111

I updated the local source and remvoed the udev rule modification as well as the device # and it looks to be working, I will monitor and update it if I do or do see any issues with it.

  • ups.conf
[Ender3Pro1UPS]
        driver = "usbhid-ups"
        port = "auto"
        desc = "Ender 3 Pro 1 UPS"
        pollonly = "enabled"
        vendorid = "0764"
        productid = "0501"
        product = "ST Series"
        vendor = "CPS"
        bus = "003"
#rem device = "006"
        busport = "001"
        ###NOTMATCHED-YET###bcdDevice = "0001"
        allow_duplicates

[Ender3Pro2UPS]
        driver = "usbhid-ups"
        port = "auto"
        desc = "Ender 3 Pro 2 UPS"
        vendorid = "0764"
        productid = "0501"
        product = "ST Series"
        vendor = "CPS"
        bus = "003"
#rem device = "007"
        busport = "002"
        ###NOTMATCHED-YET###bcdDevice = "0001"
        allow_duplicates

skl111 avatar Sep 19 '23 00:09 skl111

Ok, so just for making a note - on the hub whose topology libusb reports for us, the busport values did differ here. Thanks!

jimklimov avatar Sep 19 '23 07:09 jimklimov

Ok, so just for making a note - on the hub whose topology libusb reports for us, the busport values did differ here. Thanks!

Here is the nutscanner output and I am attaching a screenshot of the lsusb -tv output. lsusb -tv 2023-09-19 040443

Scanning USB bus.
[nutdev1]
        driver = "usbhid-ups"
        port = "auto"
        vendorid = "0764"
        productid = "0501"
        product = "ST Series"
        vendor = "CPS"
        bus = "003"
        device = "007"
        busport = "002"
        ###NOTMATCHED-YET###bcdDevice = "0001"
[nutdev2]
        driver = "usbhid-ups"
        port = "auto"
        vendorid = "0764"
        productid = "0501"
        product = "ST Series"
        vendor = "CPS"
        bus = "003"
        device = "006"
        busport = "001"
        ###NOTMATCHED-YET###bcdDevice = "0001"

skl111 avatar Sep 19 '23 08:09 skl111

@skl111 : Also, looking at your earlier comment:

I saw this option allow_duplicates but based on the manual it looks like it will ignore all 7 regex options

By code, I believe it should honour the regex options (if set), and just not abort the driver initialization if it has a hit but the discovered libusb device is busy - move on and find another hit. If documentation was not sufficiently clear about this, feel free to post a PR with a better understandable rephrasing - beauty is in the eyes of the beholder, I've re-read docs/man/nut_usb_addvars.txt and it seemed okay :)

jimklimov avatar Sep 30 '23 09:09 jimklimov